Вы находитесь на странице: 1из 92

Open∇FOAM

The open source CFD toolbox

Foundation Training

OpenCFD Ltd

Notes to workshop

1
2

Copyright and Disclaimer


Copyright © 2008-2019 OpenCFD Ltd.
All rights reserved. Any unauthorised reproduction of any form will constitute an infringement of the copyright.

OpenCFD Ltd. makes no warranty, express or implied, to the accuracy or completeness of the information in
this guide and therefore the information in this guide should not be relied upon. OpenCFD Ltd. disclaims
liability for any loss, howsoever caused, arising directly or indirectly from reliance on the information in this
guide.

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


CONTENTS 3

Contents
0.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
0.2 Example: backward-facing step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
0.3 Review of the backward-facing step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

1 Mesh processing 19
1.1 Basic meshing: clipped cavity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.2 OpenFOAM meshes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.3 Mesh conversion: elbow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

2 More case setup/running 32


2.1 Transient solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.2 More involved BCs: T-Junction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3 Turbulence and transport modelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.4 Post-processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.5 Multiphase flow: dam break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.6 Running in parallel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3 Extending basic functionality 48

4 Programming background 51
4.1 C++ overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.2 Code compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.3 Utility walk through . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5 Solver development 61
5.1 Modifying a solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.2 Dictionary I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.3 Fields and field algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
5.4 Implementing equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
5.5 PISO, SIMPLE, PIMPLE algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
5.6 Modifying a solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

A Appendix - Post-processing 75

B Appendix -Mapping one case to another 76


B.1 Appendix -Mesh manipulation: T-Junction with fan . . . . . . . . . . . . . . . . . . . . . . . . 78

C Appendix - Finite volume discretisation 82

D Appendix - Dynamic code in OpenFOAM 85

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


4 CONTENTS

What is OpenFOAM?

• Free, open source software, licensed under the GNU General Public Licence
• Produced by OpenCFD Ltd
• Released every 6 month by OpenCFD Ltd.
• Distributed as source code; pre-compiled in Docker container for Linux, MS Windows and Mac OS (see
www.openfoam.com)
• For computational fluid dynamics (CFD) (and other continuum mechanics)
• For real, 3-dimensional problems in science/engineering
• Designed as a programmable toolbox: “Matlab for CFD”
• Top level code represents the equations being solved, e.g.
∂ρU
+ ∇ • ρUU − ∇ • ρR = −∇p
∂t
1 solve
2 (
3 fvm::ddt(rho, U)
4 + fvm::div(phi, U)
5 + turbulence->divDevRhoReff(U)
6 ==
7 - fvc::grad(p)
8 );

Primary objectives for OpenFOAM

• Professional modern CFD tool bringing high fidelity solutions


• Free, open source software, licensed under the GNU General Public Licence
• Produced by OpenCFD Ltd
• For computational fluid dynamics (CFD) (and other continuum mechanics)
• Robust applications and Quality Assurance across sectors
– Transportation: Automotive, Aerospace, Marine, Rail
– Chemical
– Power
– Building and Environmental
– BioMedical
– ...

Capabilities

• OpenFOAM modelling capabilities reflex the modularity of the whole system


• OpenFOAM is developed in a transparent way to allow collaboration and implementation of new models
and capabilities
• Number of solver applications correspond to the combinations of transport equations solved; Since the
code is based on segregated pressure based solution of Navier–Stokes equations various physics demand
different treatment of pressure equation terms and other arrangements we have number of top–level
applications
• Turbulence modelling, heat transfer treatment, radiation, dynamic mesh capabilities are developed in
such an abstract layer, they are hot pluggable to many suitable applications
• Integral part of OpenFOAM is a cloud of pre and post processing capabilities including a mesh generators
for structured and unstructured meshes

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


CONTENTS 5

A toolbox, not a black box

Applications applications dir.

utilities solvers
e.g. blockMesh e.g. simpleFoam

post-processing modelling
e.g. sampling, ... e.g. turbulence, thermo, ...

pre-processing numerical meth.


e.g. meshing, ... e.g. FV, Lagrangian, ODE, ...

libOpenFOAM.so
Libraries src dir.

• OpenFOAM consists of (100+) libraries (modules) of functionality . . .


• used to create (250+) applications:

solvers (solver applications) simulate problems in CFD and other engineering mechanics
utilities perform data manipulations, visualisation, mesh processing, etc.

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


6 CONTENTS

• From version v1906 OpenFOAM offers also adjoint shape optimization

Quality assurance is done by means of consistent development process and thorough testing

• 550 unit tests (nightly)


– To ensure that the new developments do not break any other functionality
• 260 medium and validation size tests (weekly)
– Monitoring performance and resources required
∗ Results comparisons
∗ Memory usage
∗ CPU-time comparisons
• 20 Industrial tests (pre-release)
– Customer’s regression tests

OpenFOAM history

• OpenFOAM originates in 90’ on Imperial College


• Nabla Ltd. established at 2000, owning the source code

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


0.1 Overview 7

• OpenCFD Ltd. and Wikki Ltd. founded as 2004

• Code released under the GPL license

• foam extend project forked OpenFOAM at version 1.6.x

• OpenFOAM by OpenFOAM foundation forked in 2016, version 3.0

OpenFOAM releases

• OpenFOAM (Open source Field Operation And Manipulation) is free open source code released under
the GPL license

• Produced by OpenCFD

• OpenFOAM is released every 6 month (June,December)

• New developments introduced online in release notes and on free Release webinar

0.1 Overview
Plan of the course
Aim: Enable people to use OpenFOAM effectively and independently

• Will utilise the power of GNU/Linux (UNIX), using shell commands, e.g.
>> echo "Welcome to OpenFOAM"
Welcome to OpenFOAM

• Will view/edit code and case files, displayed with line numbers, e.g.
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991

• OpenFOAM version numbers are used in generic notation YYMM, where YY stands for the year and
MM for the month of the release

• Where the path is: OpenFOAM-vYYMM or user-vYYMM user should write to the command line: OpenFOAM-v1806
or user-v1806 respectively if the current version is 1806

• Everything is demonstrated with cases users can follow on their machines

• Emphasis on how to explore OpenFOAM

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


8 CONTENTS

Operation

• OpenFOAM is executed from a Linux commnad line (CMD)

• On MS Windows it could be native cmd.exe of Microsoft when using MinGW cross-compiled version

• Every application has (-help) option which shows the basic usage of the utility

• Most of the common solvers as well as decomposePar and snappyHexMesh have also -dry-run option
which invokes the setup syntax check

• Standard shell utilities and processing tools can be used on and with OpenFOAM applications

• Setup informations are provided in free-form text-files using specific keywords and C++ syntax which
will be discussed later

0.2 Example: backward-facing step


Backward-facing step (Pitz-Daily) case

Ux = 10.0
50.8 p=0

20.6 206.0 84.0

• Inlet (left) with fixed velocity Ux = 10 m/s

• Outlet (right) with fixed pressure p = 0 m2 /s2

• No-slip walls (U = 0)

• Kinematic viscosity (air) ν = µ/ρ = 1.0 × 10–5


• Turbulence model: k − ǫ;

• Steady, incompressible flow

Running the backward-facing step

• Open a terminal window by clicking the icon, left of top menu bar

• Change to the ~/OpenFOAM/ubuntu-v1906/run directory using the run alias


>> run

• Copy the pitzDaily case to the current directory


>> cp -r $FOAM_TUTORIALS/incompressible/simpleFoam/pitzDaily .

• Go into the pitzDaily case directory


>> cd pitzDaily

• Generate the pitzDaily mesh using blockMesh


>> blockMesh

• Run the pitzDaily case using simpleFoam


>> simpleFoam

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


0.2 Example: backward-facing step 9

Environment variables and aliases

• Environment variables are pre-configured pathes to important OpenFOAM directories


• Configured in the installation $WM_PROJECT_DIR/etc directory
• Begin $FOAM_... or $WM_..., list them with
>> env | grep FOAM_

• Quick changes of directory pre-defined using aliases, e.g.


alias foam='cd $WM_PROJECT_DIR'

Directory Description Env. variable Alias

/opt/OpenFOAM/OpenFOAM-v1906 Installation dir. $WM_PROJECT_DIR foam


x src Library source $FOAM_SRC src
x applications App. source $FOAM_APP app
x solvers Solver apps $FOAM_SOLVERS sol
x utilities Utility apps $FOAM_UTILITIES util
x tutorials Example cases $FOAM_TUTORIALS tut
~/OpenFOAM/ubuntu-v1906 User dir. $WM_PROJECT_USER_DIR
x run Case files $FOAM_RUN run

Post-processing a mesh

• Run paraFoam:
>> paraFoam

• Check the Mesh Parts and Volume Fields box


• Click the Apply button
• Select the Display panel
• Select representation Wireframe
• Set Color by Solid Color
• Edit Set Solid Color, e.g. black

Useful settings in paraview


In Edit -> View Settings:

• General panel:

Use Parallel Projection usual for CFD, especially 2D cases

• Lights panel:
Headlight Set to on, strength 1, white
• Annotation panel:
Orientation Axes Set to on, Interactive, Axes Label Color black

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


10 CONTENTS

In Edit -> Settings:

• Render View - General panel:

Level of Detail (LOD) controls the rendering while image is manipulated; (smaller numbers speed
things up)

• Colors panel controls global colour settings, e.g. set Background Color

Paraview toolbars
Current Time Controls
Undo/Redo Controls VCR Controls

Active Variable Controls Camera Controls


Centre Axes Controls
Common Filters

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


0.2 Example: backward-facing step 11

Pressure field plot

• Current Time Controls toolbar:

– Change time to t = 298 s and Apply button

• Active Variable Controls toolbar:

– Color by →
– Surface representation.

• Edit Coloring → Color Legend.

– Rescale to Data Range if required


– Show color legend, then edit color legend properties
– Select black Times Roman font
– Deselect Automatic Label Format and use %-#6.1f Label Format and and Range Label Format to fix
to 1 sig. fig.

• Note: Color by → attributes single value for pressure to each cell

Velocity vector plot

• Select Glyph from the Filter menu

– Open Properties panel


– Glyph → Arrow
– Scale Mode → off
– Specify Scale Factor 0.006
– Limit Max. no. of points to 2,000

• The vectors are now by default ploted using interpolated velocity data, hence the vectors initiates at the
cell vertex; To use the original data (OpenFOAM uses colocated approach to treat variables) user should
make selection of input data at the top of the Properties window in a section Active attributes

• Colour the glyphs by velocity magnitude

– Display panel → Color by U

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


12 CONTENTS

0.3 Review of the backward-facing step


pitzDaily: running the case - initialising
/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1812 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : v1812
Arch : "LSB;label=32;scalar=64"
Exec : simpleFoam
Date : Feb 27 2018
Time : 13:18:22
Host : "ed9bca5d66bb"
PID : 783
I/O : uncollated
Case : /home/ofuser/workingDir/OpenFOAM/forman-v1712/run/upgradeMaterials/pitzDaily
nProcs : 1
trapFpe: Floating point exception trapping enabled (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster (fileModificationSkew 10)
allowSystemOperations : Allowing user-supplied system call operations
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time
Create mesh for time = 0

SIMPLE: convergence criteria


field p tolerance 0.01
field U tolerance 0.001
field "(k|epsilon|omega|f|v2)" tolerance 0.001
Reading field p
Reading field U
Reading/calculating face flux field phi

• Creates mesh, reads physical properties and fields

pitzDaily: running the case - start


Time = 1
smoothSolver: Solving for Ux, Initial residual = 1, Final residual = 0.0538101, No Iterations 1
smoothSolver: Solving for Uy, Initial residual = 1, Final residual = 0.030925, No Iterations 2
GAMG: Solving for p, Initial residual = 1, Final residual = 0.068427, No Iterations 17
time step continuity errors : sum local = 1.19733, global = 0.179883, cumulative = 0.179883
smoothSolver: Solving for epsilon, Initial residual = 0.199978, Final residual = 0.0100279, No Iterations 3
bounding epsilon, min: -1.98669 max: 1080.25 average: 47.5306
smoothSolver: Solving for k, Initial residual = 1, Final residual = 0.0439206, No Iterations 3
ExecutionTime = 0.35 s ClockTime = 0 s
Time = 2
smoothSolver: Solving for Ux, Initial residual = 0.437825, Final residual = 0.030824, No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.283531, Final residual = 0.0258526, No Iterations 4
GAMG: Solving for p, Initial residual = 0.052242, Final residual = 0.00424172, No Iterations 15
time step continuity errors : sum local = 4.02676, global = 0.102655, cumulative = 0.282538
smoothSolver: Solving for epsilon, Initial residual = 0.153295, Final residual = 0.0109463, No Iterations 3
bounding epsilon, min: -40.6096 max: 23853.2 average: 84.882
smoothSolver: Solving for k, Initial residual = 0.419185, Final residual = 0.0313043, No Iterations 3
ExecutionTime = 0.4 s ClockTime = 0 s

pitzDaily: running the case - end


Time = 282
smoothSolver: Solving for Ux, Initial residual = 0.000121432, Final residual = 1.18869e-05, No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.00100076, Final residual = 6.94429e-05, No Iterations 6
GAMG: Solving for p, Initial residual = 0.000779683, Final residual = 6.73841e-05, No Iterations 5
time step continuity errors : sum local = 0.00321598, global = -0.000238078, cumulative = 1.03215
smoothSolver: Solving for epsilon, Initial residual = 0.000120088, Final residual = 6.95836e-06, No Iterations 3
smoothSolver: Solving for k, Initial residual = 0.000223194, Final residual = 1.38904e-05, No Iterations 4
ExecutionTime = 10.91 s ClockTime = 14 s
Time = 283
smoothSolver: Solving for Ux, Initial residual = 0.000117347, Final residual = 1.15458e-05, No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.000973432, Final residual = 6.69771e-05, No Iterations 6
GAMG: Solving for p, Initial residual = 0.000767448, Final residual = 6.42026e-05, No Iterations 5
time step continuity errors : sum local = 0.00306293, global = -0.000239367, cumulative = 1.03191
smoothSolver: Solving for epsilon, Initial residual = 0.000119246, Final residual = 6.82329e-06, No Iterations 3
smoothSolver: Solving for k, Initial residual = 0.000217516, Final residual = 1.35628e-05, No Iterations 4
ExecutionTime = 10.95 s ClockTime = 14 s

SIMPLE solution converged in 283 iterations


streamLine streamlines write:
seeded 10 particles
Tracks:10
Total samples:10885
Writing data to "/home/ofuser/workingDir/OpenFOAM/forman-v1712/run/upgradeMaterials/pitzDaily/postProcessing/sets/streamlines/283"
End

pitzDaily: screen output

Time = 2
smoothSolver: Solving for Ux, Initial residual = 0.449919, Final residual = 0.0314485,
No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.276409, Final residual = 0.0253638,
No Iterations 4

• smoothSolver is the chosen linear-solver for the U equation

• Linear-solver decouples vector equation for U into components Ux and Uy

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


0.3 Review of the backward-facing step 13

• Iterates until Final residual < relTol×Initial residual


• fvSolution::solvers (solvers subdictionary of system/fvSolution):
34 "(U|k|epsilon|omega|f|v2)"
35 {
36 solver smoothSolver;
37 smoother symGaussSeidel;
38 tolerance 1e-05;
39 relTol 0.1;
40 }

pitzDaily: screen output (2)

GAMG: Solving for p, Initial residual = 0.0507773, Final residual = 0.00479054,


No Iterations 16
time step continuity errors : sum local = 4.34847, global = 0.30184,
cumulative = -0.0167273

• GAMG is the chosen linear-solver for the p equation


• p equation solved 1 time because nNonOrthogonalCorrectors = 0
• Errors in mass continuity presented as:
– sum local: sum of magnitudes of continuity errors in each cell
– global: across the boundary of the domain
– cumulative: global error accumulated over time
• fvSolution::solvers
20 p
21 {
22 solver GAMG;
23 tolerance 1e-06;
24 relTol 0.1;
25 smoother GaussSeidel;
26 }

In SIMPLE algorithm, pressure equation is normally solved only once during the iteration. Non-
orthogonality is a mesh quality parameter corresponding to the angle between the surface normal and the
vector connecting neighbouring cell centres.

Residual/convergence control

• Residual (res): equation error for a variable, normalised by its magnitude


• Linear solvers (e.g. PBiCG, smoothSolver) stop iterating if
res < tolerance
||
res < relTol × initialRes
||
iter > maxIter

• Can also specify minIter


• SIMPLE algorithm has convergence control based on residuals of fields
• Solver (e.g. simpleFoam) stops when res < residualControl for all fields
43 SIMPLE
44 {
45 nNonOrthogonalCorrectors 0;
46 consistent yes; //SIMPLEC
47
48 residualControl //when to stop simulation
49 {
50 p 1e-2;
51 U 1e-3;
52 "(k|epsilon|omega|f|v2)" 1e-3;
53 }
54 }

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


14 CONTENTS

SIMPLE control

• In SIMPLE dictionary user may specify number of nNonOrthogonalCorrectors to stabilise the solution
on nonOrthogonal meshes

• Switch consistent yes can be used to switch from SIMPLE to SIMPLEC (consistent formulation) algo-
rithm which brings faster convergence. Note, SIMPLEC method does not need to under-relax pressure.
Smaller under-relaxation (0.95 - 0.7) is needed for other variables to maintain stability of solution.

• In pitzDaily case, SIMPLE algorithm reaches convergence in 867 iterations while SIMPLEC in 281
iterations.
1
SIMPLE Ux
SIMPLEC Ux
SIMPLE Uy
SIMPLEC Uy
SIMPLE p
0.1 SIMPLEC p

0.01

0.001

0.0001
0 100 200 300 400 500 600 700 800 900 1000

Case setup in OpenFOAM


simpleFoam → • Choose solver
x pitzDaily → • Copy example case for that solver
½ • Create/modify mesh
x constant
• Select models and properties
x0 → • Initialise fields & BCs for p, U, etc.
x system → • Set case controls, e.g. ∆t, schemes, tolerances

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


0.3 Review of the backward-facing step 15

pitzDaily: control parameters


<system>/controlDict:
¾ ¾
20 startFrom startTime;
21 Start time t = 0 End time t = 2000
22 startTime 0;
23
24 stopAt endTime; – Time step ∆t = 1, standard for steady-state
25 ¾
26 endTime 2000;
27 Writes out every 100 time steps
28 deltaT 1;
29
30 writeControl timeStep; – Does not rewrite over time directories
31
32 writeInterval 100; ¾
33
34 purgeWrite 0;
Writes ASCII, 6 sig. figs
35
36 writeFormat ascii;
37 – Writes uncompressed
38 writePrecision 6; ¾
39
40 writeCompression off; Time dir. naming format, 6 sig. figs
41
42 timeFormat general; – Allows modification of settings during run
43
44 timePrecision 6;
45
Parameter
46 options
runTimeModifiable true;

• Valid entries for particular keyword could be found using a false entry
• E.g., setting “stopAt xxx;” in controlDict, a solver would return:
--> FOAM FATAL IO ERROR:
xxx is not in enumeration:
4
(
endTime
writeNow
noWriteNow
nextWrite
)
file: <full path>/pitzDaily/system/controlDict.stopAt at line 24.

• Entries for stopAt are clearly listed


• User can also search for the keyword in Doxygen documentation at http://www.openfoam.com/documentation/cpp-guide

pitzDaily: setting initial/boundary conditions

• Field data are stored in time directories, e.g. 0, 0.1, 0.2, . . .


• Usually initial conditions are stored at t = 0, i.e. directory 0
• simpleFoam reads field data for pressure (p), velocity (U) and turbulence models
• Let’s look at the data files. . .

pitzDaily: pressure field


$FOAM_RUN/pitzDaily/0/p:
17 dimensions [0 2 -2 0 0 0 0];
18
19 internalField uniform 0;
20
21 boundaryField
22 {
23 inlet
24 {
25 type zeroGradient;
26 }
27
28 outlet
29 {
30 type fixedValue;
31 value uniform 0;
32 }
33
34 upperWall
35 {

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


16 CONTENTS

36 type zeroGradient;
37 }
38
39 lowerWall ... (ditto) ...
40
41 frontAndBack
42 {
43 type empty;
44 }
45 }

• Dimensions are m2 /s2 , i.e. kinematic pressure, in simpleFoam

• Internal (and boundary) fields can be:

uniform a single value


nonuniform all values in a List

• type describes the numerical boundary condition

• walls are zeroGradient

• outlet is fixedValue which requires a value; can be anything (pressure is relative), use 0 for convenience

• frontAndBack planes of a 2D case must be empty to match their base type

pitzDaily: velocity field


$FOAM_RUN/pitzDaily/0/U:
17 dimensions [0 1 -1 0 0 0 0];
18
19 internalField uniform (0 0 0);
20
21 boundaryField
22 {
23 inlet
24 {
25 type fixedValue;
26 value uniform (10 0 0);
27 }
28
29 outlet
30 {
31 type zeroGradient;
32 }
33
34 upperWall
35 {
36 type noSlip;
37 }
38
39 lowerWall ... (ditto) ...
40
41 frontAndBack
42 {
43 type empty;
44 }
45 }

• Velocity is a vector field

• No-slip walls:
– a fixedValue type
– requires a value

• uniform (10 0 0) on inlet


• uniform (0 0 0) on walls

• outlet is zeroGradient

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


0.3 Review of the backward-facing step 17

Dimensions and dimension checking

• Fields and properties have dimensions associated with them

• Powers of: mass, length (L), time (T), temperature, quantity, current, luminosity

• Specified using square bracket [...] syntax


[ 1 -1 -2 0 0 0 0 ] // [ Mass Len. Time Temp. Qnt. Cur. Lum. ]

• Velocity is L1 T−1 , i.e. [0 1 -1 0 0 0 0]

• +, −, = operators: solver stops if dimensions are not the same

• ×, / operators: dimensions are modified

• Unit system, e.g. SI, only appears in values of physical constants, e.g. R, pstd

• Physical constants hard-coded in SI but can be modified in global controlDict file in


$WM_PROJECT_DIR/etc directory:
898 DimensionedConstants
899 {
900 unitSet SI; // USCS
901 ...

• These settings can be prescribed locally in case controlDict adding DimensionedConstants or DimensionSets

• Symbolic dimensions are also specified in $WM_PROJECT_DIR/etc/controlDict that can be used in any
OpenFOAM case setup file

Boundary conditions (BCs): 1. basic

• Geometry boundary is broken into patches on which BCs are applied

• BCs are specified in field files, e.g. 0/U

• User must specify numerical BCs on fields, rather than a physical description. . .

• Rather than “inlet”, the user must specify BCs on p, U, . . .


• Some basic BCs are listed below
BC type Additional data Example
fixedValue value U = (10, 0, 0)
fixedGradient gradient ∂T /∂n = 2.5
zeroGradient — ∂p/∂n = 0

• Preprocessing utility createZeroDirectory can be used to setup BC files

• Utility reads settings from system/caseProperties file

• Boundary conditions are prescribed by category e.g. “inlet”, and set of keywords. Settings are expanded
by utility to particular variable files in zero directory

• Tutorials are in $FOAM_TUTORIALS/preProcessing/createZeroDirectory

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


18 CONTENTS

pitzDaily: physical properties

• Physical properties set in the case constant directory


>> ls -1 constant
polyMesh/
transportProperties
turbulenceProperties

• Named ...Properties: here transportProperties and turbulenceProperties

• Generally contain entries for the ...simulationType - turbulent treatment and ...Model setup to set
particular model
• turbulenceProperties:
18 simulationType RAS;
19
20 RAS
21 {
22
23 RASModel kEpsilon;
24
25 turbulence on;
26
27 printCoeffs on;
28 }

• transportProperties contains entry for kinematic viscosity nu (ν)


18 transportModel Newtonian;
19
20 nu 1e-05;

• The keyword nu requires a dimensionedScalar entry, which includes

word “nu”, used for internal naming of other fields


Dimension of the field is assumed to be in SI units m2/s

scalar a value set to 1e-05

• In compressible simulations viscosity and other physical parameters are set in different files, mainly in
constant/thermophysicalProperties

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


19

1 Mesh processing
Introduction to meshing in OpenFOAM

• blockMesh for structured meshes

• extrudeMesh for 2D or axisymmetric meshes

• moveDynamicMesh to conform organic geometry with structured mesh

• automatic meshers

– snappyHexMesh for arbitrary 3D polyhedral mesh


– (foamyHexMesh) for body fitted 3D mesh
– (foamyQuadMesh) for body fitted 2D mesh

BlockMesh snappyHexMesh (foamyHexMesh)

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


20 Mesh processing

1.1 Basic meshing: clipped cavity


Clipped cavity case
Ux = 1 m/s

60 mm

y
40 mm
x

60 mm 40 mm
• Laminar

• Lid: U = (1, 0, 0)

• No-slip walls (U = 0)

• Transient, incompressible flow

Running the clipped cavity

• Change to the ~/OpenFOAM/ubuntu-v1906/run directory


>> run

• Copy the cavityClipped case to the current directory


>> cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavityClipped .

• Go into the cavityClipped case directory


>> cd cavityClipped

• Generate the cavityClipped mesh using blockMesh


>> blockMesh

• In system/controlDict, change the startTime:


22 startTime 0;

• Run the cavityClipped case using icoFoam


>> icoFoam

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


1.1 Basic meshing: clipped cavity 21

Clipped cavity: results

• Open the case in ParaView

• Change time to t = 0.6s

• Apply Cell centers filter

• Apply Glyph filter


– Scale Mode → off
– Specify Scale Factor 0.005

• Colour the glyphs by velocity


– Display panel → Color by U

Mesh generation using blockMesh

• blockMesh is a simple mesh generator using blocks

• Allows multiple blocks and curved edges

• Configured by a blockMeshDict file in the system directory of a case


• Produces a 3D mesh of hexahedral cells

• OpenFOAM always uses 3D meshes, handling 1D, 2D and axisymmetric cases using special boundary
conditions

• There are lot of examples in the tutorials — copy something suitable for your needs and modify it

blockMeshDict configuration: vertices


5 6 7

13 14 15

1 2

2 3 4

10 11 12

y 0
x 1
0
z
8 9

• List of vertices in blockMeshDict

• All values scaled by convertToMeters

• For convenience: z-depth = 0.1×y-height

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


22 Mesh processing

17 convertToMeters 0.1;
18
19 vertices
20 (
21 (0 0 0) // Vertex 0
22 (0.6 0 0) // Vertex 1
23 (0 0.4 0) // etc ...
24 (0.6 0.4 0)
25 (1 0.4 0)
26 (0 1 0)
27 (0.6 1 0)
28 (1 1 0)
29
30 (0 0 0.1)
31 (0.6 0 0.1)
32 (0 0.4 0.1)
33 (0.6 0.4 0.1)
34 (1 0.4 0.1)
35 (0 1 0.1)
36 (0.6 1 0.1)
37 (1 1 0.1)
38 );

blockMeshDict configuration: blocks


41 blocks
42 (
43 hex (0 1 3 2 8 9 11 10) // vertex list
44 (12 8 1) // no. cells in each dir.
45 simpleGrading (1 1 1) // cell expansion ratios
46 ...
47 );

• Block description begins with hex followed by list of vertices


• Order of vertices is critical
• The 1st 4 vertices describe one plane; the 2nd 4 describe another plane
• The order defines a local coordinate system (x1 , x2 , x3 )
plane 1 plane 2 3
hex (0 1 3 2 8 9 11 10) x2 x2
x1
x1 0 1 x1
x2
x3 x3 x3
8
• The resulting (x1 , x2 , x3 ) local coordinate system must be right-handed
– looking down the Ox3 axis — with O nearest — an arc from the Ox1 axis to the Ox2 axis is in a
clockwise sense.

blockMeshDict configuration: blocks (2)

• (12 8 1) = number of cells in each direction in the block’s local coord. system
– 1 in the z-direction because the case is 2D
• The final entries specify cell grading
• Either simpleGrading or edgeGrading
– simpleGrading: requires 3 expansion ratios
– edgeGrading: requires 12 expansion ratios — see User Guide for details
• Expansion ratio = (end cell length δe ) / (start cell length δs )
• Grading is linear in between
δe
δs Expansion ratio = δe
δs

Expansion direction
• Multi-sectional grading description can be found in the Appendix

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


1.1 Basic meshing: clipped cavity 23

blockMeshDict configuration: boundary


52 boundary
53 (
54 lid
55 {
56 type wall;
57 faces
58 (
59 (5 13 14 6)
60 (6 14 15 7)
61 );
62 }
63
64 fixedWalls
65 {
66 type wall;
67 faces
68 (
69 (0 8 10 2)
70 ...
71 );
72 }
73
74 frontAndBack
75 {
76 type empty;
77 faces
78 (
79 (0 2 3 1)
80 ...
81 );
82 }
83 );

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


24 Mesh processing

• Each patch given a name, e.g. lid


• Sub-dictionary contains a type entry
• patch is the default type
• empty for 2D front and back planes
• wall for walls (generic patch with a wall label)
• faces: list of faces, each defined by 4 vertex points in order along a path around the face edges

Case file syntax: general

• Follows general principles of C++ source code


• Files have free form
– No particular meaning assigned to a column
– No need to indicate continuation across lines
• Lines have no particular meaning except to a // comment delimiter which ignores text that follows it
until the end of line
• Enclose text between /* and */ delimiters to comment over multiple lines

Case file syntax: specific

• OpenFOAM uses a flexible I/O format based on a keyword syntax


<keyword> <dataEntry1> ... <dataEntryN>; // usually 1 entry

• A data entry can be a string ("hello"), word (hello), integer (3) scalar (3.14), . . .
• . . . a dictionary: curly brackets {...}
{
... keyword entries ...
}

• . . . a list: round brackets (...)


List<Type> // optional, Type = elements of list, e.g. scalar
<n> // optional, number of entries
(
... dataEntry1 ...
);

• . . . a dimensionSet: square brackets [...]


[ 1 -1 -2 0 0 0 0 ] // [ Mass Len. Time Temp. Qnt. Cur. Lum. ]

1.2 OpenFOAM meshes


Meshes in OpenFOAM

• OpenFOAM operates in a 3 dimensional Cartesian coordinate system


• . . . 1-D, 2-D and axi-symmetry cases emulated by applying special BCs
• Arbitrary polyhedral cells in 3-D, bounded by arbitrary polygonal faces
• . . . cell: unlimited number of faces
• . . . face: unlimited number of edges

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


1.2 OpenFOAM meshes 25

• . . . internal faces intersect two cells only

• . . . boundary faces belong to one cell

• Known as polyMesh in OpenFOAM

• Arbitrary mesh interface (AMI) permits non-conforming faces between patches

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


26 Mesh processing

The polyMesh description

Sf
P

d N

• Face-based description

• Each face is assigned an owner (P) and neighbour (N) cell

• If boundary face, then no neighbour cell

constant
x polyMesh Mesh
x points List of points (vectors)
x faces List of faces, each face being a list of indices to points
x owner List of face owner-cell labels, the index = face index
x neighbour List of face neighbour-cell labels, the index = face index
x boundary List of patches, each a dictionary, declared by name

movingWall

type patch;

nFaces 20;

startFace 760;

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


1.2 OpenFOAM meshes 27

The faces list (file)


faces
face 0
face 1
...

Internal faces

Patch 0

Patch 1
Boundary faces
startFace
Patch 2
nFaces

• The list of faces is ordered in OpenFOAM

• Internal faces appear first

• Boundary faces follow, ordered in patches

• Each patch described by startFace and nFaces

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


28 Mesh processing

The boundary file

• The boundary file can be viewed and edited


• Users can modify patch names and types
• Patches can belong to a patch group
19 3
20 (
21 lid // boundary patch name
22 {
23 type wall; // patch type
24 nFaces 20; // no. faces in patch
25 startFace 632; // index of first patch
26 } // => lid patch is faces 632-651
27 fixedWalls
28 {
29 type wall;
30 nFaces 60;
31 startFace 652;
32 }
33 frontAndBack
34 {
35 type empty;
36 inGroups 1(empty); // allocates the patch to group "empty"
37 nFaces 672;
38 startFace 712;
39 }
40 )

Boundary conditions (2): constraint

• Patches are given a geometric type in mesh boundary file


• The default type is patch
• There are other special types relating to geometric constraints, see below
• All constraint patches belong to a group of the same name, e.g. empty
• BCs in field files, e.g. 0/p, must be consistent with types in the boundary file
Selection Key Description
patch generic patch
symmetry symmetry for a non-planar patch
symmetryPlane symmetry for a single planar patch
empty front and back planes of a 2D geometry
wedge wedge front and back for an axi-symmetric geometry
cyclic cyclic plane
wall wall — used for wall functions in turbulent flows

1.3 Mesh conversion: elbow


Converting meshes to OpenFOAM format

• There are several mesh conversion tools in OpenFOAM


• Where are they? How does a user find the one they want? (General questions that can apply to any
application)
1. User Guide:
http://openfoam.com/documentation/user-guide/standard-utilities.php

2. Source code: drill down source directory tree


>> ls $FOAM_UTILITIES
mesh miscellaneous parallelProcessing postProcessing preProcessing ...
>> ls $FOAM_UTILITIES/mesh
advanced conversion generation manipulation
>> ls $FOAM_UTILITIES/mesh/conversion
ansysToFoam cfx4ToFoam datToFoam fluent3DMeshToFoam fluentMeshToFoam ...

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


1.3 Mesh conversion: elbow 29

Using applications

• Once an application is located, find an example in the tutorials

• Tutorials are organised by the solver to which they relate

• By default, they work by: (1) running blockMesh; (2) running the solver

• If more complex, they are run from an Allrun script

• ⇒ Search Allrun scripts for examples of use of a utility, e.g. fluentMeshToFoam


>> find $FOAM_TUTORIALS -name Allrun
...
/opt/OpenFOAM/OpenFOAM-vYYMM/tutorials/incompressible/icoFoam/elbow/Allrun
...
>> find $FOAM_TUTORIALS -name Allrun |xargs grep -l fluentMeshToFoam
/opt/OpenFOAM/OpenFOAM-vYYMM/tutorials/incompressible/icoFoam/elbow/Allrun

The elbow case

• The elbow tutorial runs fluentMeshToFoam


• See $FOAM_TUTORIALS/incompressible/icoFoam/elbow/Allrun:
10 runApplication fluentMeshToFoam elbow.msh

• Go to the run directory, copy the elbow directory and go into it


>> run
>> cp -r $FOAM_TUTORIALS/incompressible/icoFoam/elbow .
>> cd elbow

• Type the utility name with the -help option to display usage
>> fluentMeshToFoam -help
Usage: fluentMeshToFoam [OPTIONS] <Fluent mesh file>
options:
-case <dir> specify alternate case directory, default is the cwd
-noFunctionObjects
do not execute functionObjects
-scale <factor> geometry scaling factor - default is 1
-writeSets write cell zones and patches as sets
-writeZones write cell zones as zones
-srcDoc display source code in browser
-doc display application documentation in browser
-help print the usage

Generating the elbow mesh

• Execute fluentMeshToFoam
>> fluentMeshToFoam elbow.msh

• Imported meshes can be low quality

• . . . so the mesh quality should be checked with checkMesh


>> checkMesh

• In particular, check max non-orthogonality


• . . . if > 80◦ , running difficult to achieve

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


30 Mesh processing

OpenFOAM to VTK format conversion

• ParaView post-processing can be performed using foamToVTK converter


>> foamToVTK

• Launch ParaView (type paraview), then open the file VTK/elbow_0.vtk

• Display Surface with Edges and colour by cellID

Matrix bandwidth

• cellID image shows high bandwidth

• . . . i.e. the indices of neighbouring cells are not close in value

• High bandwidth slows performance of matrix solvers

Cell renumbering

• Careful numbering of cells can reduce bandwidth in a solution matrix

• Neighbouring cells ideally have numbers close together

• Meshes in other formats may not have optimal numbering


• Run the renumberMesh utility to reduce bandwidth considerably
>> renumberMesh -overwrite
...
Mesh size: 918
Before renumbering :
band : 735
profile : 103613
Using default renumberMethod.
Selecting renumberMethod CuthillMcKee
Reading volScalarField p
Reading volVectorField U
After renumbering :
band : 29
profile : 11753
Writing mesh to "constant"

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


1.3 Mesh conversion: elbow 31

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


32 More case setup/running

2 More case setup/running


2.1 Transient solution
Transient solution
Time = 0.1
Courant Number mean: 0.0788465 max: 0.397002
smoothSolver: Solving for Ux, Initial residual = 0.417, Final residual = 1.72e-06, No Iterations 2
smoothSolver: Solving for Uy, Initial residual = 0.415, Final residual = 6.74e-06, No Iterations 2
DICPCG: Solving for p, Initial residual = 0.01795, Final residual = 4.628e-07, No Iterations 67
DICPCG: Solving for p, Initial residual = 0.5105, Final residual = 5.537e-07, No Iterations 68
DICPCG: Solving for p, Initial residual = 0.119, Final residual = 7.814e-07, No Iterations 65
time step continuity errors : sum local = 9.657e-09, global = 1.063e-10, cumulative = 2.563e-08
DICPCG: Solving for p, Initial residual = 0.1104, Final residual = 8.331e-07, No Iterations 67
DICPCG: Solving for p, Initial residual = 0.2645, Final residual = 7.867e-07, No Iterations 66
DICPCG: Solving for p, Initial residual = 0.0315, Final residual = 6.649e-07, No Iterations 64
time step continuity errors : sum local = 2.1397e-09, global = 1.024e-12, cumulative = 2.563e-08
ExecutionTime = 0.03 s ClockTime = 0 s

• icoFoam is a transient solver, i.e. solves over time steps

• Uses the PISO algorithm

• p equation solved with 2 correctors (3 times in total) and non-orthogonal correctors = 2, see fvSolution::PISO
37 PISO
38 {
39 nCorrectors 2;
40 nNonOrthogonalCorrectors 2;
41 }

Courant Number

Time = 0.1
Courant Number mean: 0.0788465 max: 0.397002

• Courant Number Co = U ∆t/∆x

• U is the flow speed in a given direction

• ∆x is the cell length in a given direction

• ∆t is the time step

• Co > 1 means the flow can pass through a cell within one time step

• Some numerical methods/algorithms stable only if Co is below a certain limit

• PISO algorithm typically limited to Co < 1

OpenFOAM workflow

• Decide on the modelling approach

• Find a solver suitable for your application

• Inspect the tutorials for a given solver

• Adopt the tutorial closer to your application

• Change the mesh, BC, initial conditions, adjust discretisation, employ the function objects of your choice

• The question is which solver is suitable for a given simulation

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.1 Transient solution 33

Selecting a solver

• Application source code is organised into sub-directories whose names represent types of flow, utility,
e.g.
>> ls $FOAM_SOLVERS
basic combustion ... heatTransfer incompressible lagrangian multiphase

• The source code for each application, e.g. icoFoam, is in its own directory
>> ls $FOAM_SOLVERS/incompressible
... icoFoam nonNewtonianIcoFoam pimpleFoam pisoFoam ... simpleFoam

• The main .C source file is named after the application, e.g. icoFoam.C
>> ls $FOAM_SOLVERS/incompressible/icoFoam
createFields.H icoFoam.C Make

• The header of the main .C file has a description of its use, e.g.
Description
Transient solver for incompressible, laminar flow of Newtonian fluids.
...

• The executable is named icoFoam


>> ls $FOAM_APPBIN
... icoFoam ...

Types of solver

• Solver names indicate what they do

• simple = SIMPLE algorithm used in steady-state solvers (can be switched to SIMPLEC)

• piso = PISO algorithm, used in transient solvers, Co < 1 limited

• pimple = PIMPLE algorithm - combination of SIMPLE and PISO, used in transient solvers, not Co
limited

• over = dynamic mesh, e.g. moving mesh, rigid body motion (6DoF) using overset (chimera) mesh

• When the velocity-pressure coupling algorithm name is not stated in the application name, it is using
PIMPLE (e.g. reactingFoam, interFoam).
Solver description can be found in Doxygen:
http://openfoam.com/documentation/cpp-guide/html/ in a solver compatibility matrix

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


34 More case setup/running

2.2 More involved BCs: T-Junction


T-Junction example
p = 10 Pa

Square duct (3D)

y
20

x
p = 10→40 Pa

200

200

Dimensions in mm

p = 0 Pa

• Turbulent, incompressible flow

• inlet (left) p ramped 10→40 Pa over 1 s


• outlet1 (top) p = 10 Pa

• outlet2 (bottom) p = 0 Pa

• No-slip walls (U = 0)

Tutorial to inspect boundary conditions in greater detail, including time varying BCs and a
turbulence setup

Running the T-Junction case

• Aim of the tutorial is to show advanced boundary conditions and fields mapping on different mesh

• TJunction is a pimpleFoam tutorial case

• Go to the run directory, copy the TJunction directory and go into it


>> run
>> cp -r $FOAM_TUTORIALS/incompressible/pimpleFoam/RAS/TJunction .
>> cd TJunction

• Generate the TJunction mesh using blockMesh


>> blockMesh

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.2 More involved BCs: T-Junction 35

Running the T-Junction case (2)

• In system/controlDict, change the endTime:


33 endTime 2;

• In system/fvSolution, change the nOuterCorrectors:


62 nOuterCorrectors 2;

• Run pimpleFoam in the background (&), redirecting output to a log file


>> pimpleFoam > log &

• View the log file in the terminal window with tail command
>> tail -f log

• Terminate with Control-C

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


36 More case setup/running

Boundary conditions (BCs): 3. derived

inlet outlet

fv
Un
Ut
zg

U: pressureInletOutletVelocity U: inletOutlet
∂Un /∂n = 0 (zg) ∂U/∂n = 0 (zg) for outflow
∂Ut /∂n = 0 (zg) for outflow U = Ub (= 0) (fv) for inflow
Ut = 0 (fv) for inflow p: fixedValue
p: totalPressure
p = p0 for outflow
p = p0 − |U|2 /2 for inflow

• totalPressure and pressureInletOutletVelocity are self-stabilising

• inletOutlet prevents problem being ill-posed in event of flow reversal

Boundary conditions (BCs): 3. derived (2)

• In fact, at the inlet, pressure is ramped from 10 → 40 Pa from t = 0 → 1

• Uses a specialisation of totalPressure, called uniformTotalPressure

• pressure can be constant or time-varying


22 inlet
23 {
24 type uniformTotalPressure;
25 p0 table // table : inline table data
26 ( // constant : constant value
27 (0 10) // tableFile : tabulated data
28 (1 40) // csvFile : CSV data
29 ); // polynomial : polynomial expression
30 // Sine : sinus function
31 // Square : square function with an offset
32 }

The general time varying BC is called uniformFixedValue; the functions introducing time variation
are defined under the class Function1; the description can be found in the online documentation
http://openfoam.com/documentation/cpp-guide/html/classFoam_1_1Function1.html

2.3 Turbulence and transport modelling


Turbulence simulation and RAS modelling

• The type of turbulence modelling is specified under simulationType in constant/turbulenceProperties


from:

laminar laminar simulation


RAS Reynolds-averaged simulation (RAS)
LES large-eddy simulation (LES)

• The RAS turbulence model is specified in a RAS sub-dictionary:

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.3 Turbulence and transport modelling 37

18 simulationType RAS;
19
20 RAS
21 {
22 RASModel kEpsilon; // Name of RAS turbulence model
23
24 turbulence on; // Turns turbulence modelling on/off
25
26 printCoeffs on; // Prints model coeffs to terminal at startup
27
28 kEpsilonCoeffs // (Optional) coefficients for selected RASModel
29 {
30 Cmu 0.09;
31 ...

Initialising turbulence fields

1. The k − ε model contains two additional fields, see 0 directory

• Turbulent kinetic energy k = U′ • U′ /2 = 1.5(|U |I)2


• Turbulent dissipation rate ε = Cµ0.75 k 1.5 /L

2. Inlet conditions can be set using derived BCs

• turbulentIntensityKineticEnergyInlet calculates k = 1.5|IU|2 , by assuming isotropic turbulence


with turbulent intensity I
• turbulentMixingLengthDissipationRateInlet calculates ε from a turbulent mixing length L

3. Initial internal values for k and ε not very important here

• Initial and boudnary conditions are usually set in accord


• Initial conditions are set as fixedValues
• BC values for k and ε are referenced as
fixedValue $internalField ;

Wall functions

• Wall functions model the effect of wall boundaries to avoid resolving turbulent boundary layers
• Wall functions are specified through BCs on turbulent viscosity νt (nut)
• nutkWallFunction is the standard wall function model
• There are other models, e.g. nutkRoughWallFunction
• epsilonWallFunction must be the corresponding BC in 0/epsilon
• kqRWallFunction must be the corresponding BC for the turbulent fields k, q and R (k in this case)

Turbulence field example (1): k


18 dimensions [ 0 2 -2 0 0 0 0 ];
19
20 internalField uniform 1;
21
22 boundaryField
23 {
24 inlet
25 {
26 type turbulentIntensityKineticEnergyInlet;
27 intensity 0.05; // 5% turbulent intensity
28 value uniform 1;
29 }
30
31 outlet1
32 {
33 type inletOutlet;
34 inletValue uniform 1;

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


38 More case setup/running

35 }
36
37 outlet2 ... (ditto) ...
38
39 defaultFaces
40 {
41 type kqRWallFunction;
42 value uniform 0;
43 }
44 }

Turbulence field example (2): nut


18 dimensions [ 0 2 -1 0 0 0 0 ];
19
20 internalField uniform 0; // Overridden by the code
21
22 boundaryField
23 {
24 inlet
25 {
26 type calculated;
27 value uniform 0;
28 }
29
30 outlet1 ... (ditto) ...
31
32 outlet2 ... (ditto) ...
33
34 defaultFaces
35 {
36 type nutkWallFunction; // The only entry of importance
37 value uniform 0;
38 }
39 }

Boundary conditions overview

• Boundary conditions are applied to the boundary patches (specified in the $FOAM_CASE/constant/polyMesh/bound
file)

• Boundary conditions are of fixed value, fixed gradient or mixed type

• Full description can be found in the online documentation:

– General description under the Boundary Conditions in the section OpenFOAM Guide
– Full list of BCs under the Boundary Conditions under the Modules in the OpenFOAM API section

• The online documentation brings up to date description of the boundary conditions and its setup

• The best is to find a Detailed description section with a verbatim copy-paste part to copy and paste to
apply the given BC

• Macro #include statements as well as variable referencing is heavily used together with the regular
expressions
#include "include/initialConditions" // content of the file is copied here
dimensions [0 1 -1 0 0 0 0];
internalField uniform $flowVelocity; // variable value from initialConditions is taken
...
"(lowerWall|upperWall).*"
{
type fixedValue;
value $internalField;
}
#include "include/frontBackUpperPatches"

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.3 Turbulence and transport modelling 39

Incompressible transport models

• Need to set ν = 1 × 10−5

• pimpleFoam uses the incompressibleTransportModels library

• Modelling specified in constant/transportProperties:


17 transportModel Newtonian;
18
19 nu 1e-05;

• User selects the transportModel, then necessary values/coeffs

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


40 More case setup/running

2.4 Post-processing
T-Junction: post-processing

• TJunction case is configured with a function object in controlDict file


• Function objects perform post-processing and run-time control during a simulation
• An extensive range of functionality, discussed in the Advanced Course

• For example, data sampling provided by the sampling library, including:


• probes: probes cell data
• sets: writes interpolated data sets along lines, curves or point clouds
• surfaces: writes surface data, e.g. isosurfaces, cutting planes, patch surfaces

T-Junction: probe data

• The probe function object writes U and p data at specified locations to probes/0
• For example, postProcessing/probes/0/p
1 # Probe 0 (1e-06 0 0.01)
2 # Probe 1 (0.21 -0.20999 0.01)
3 # Probe 2 (0.21 0.20999 0.01)
4 # Probe 3 (0.21 0 0.01)
5 # Probe 0 1 2 3
6 # Time
7 0.1 11.6382 9.53762 0.0386381 8.11444
8 0.2 12.0804 9.84855 0.0228418 9.81011
9 0.3 12.1284 10.0166 0.0206715 11.1345
10 0.4 11.6843 10.0156 0.0182874 12.8767
11 0.5 11.4135 10.0128 0.0220063 14.6487
12 0.6 11.5703 10.0121 0.0244337 16.3634
13 0.7 11.899 10.0128 0.0258589 17.9907
14 0.8 12.2565 10.0137 0.0271518 19.6124
15 0.9 12.6504 10.0144 0.0286107 21.2666
16 1 13.0484 10.0159 0.0297802 22.8825
17 ...

• Can be used to assess convergence


• Data can plotted by gnuplot
• To probe in space, post-processing utility sample can be used. See Appendix for more details
• The list of all the function objects suitable for post-processing can be found in the online documentation

Gnuplot post-processing

• Change directory to: postProcessing/probes/0


• Gnuplot is a command line driven plotting application
• Type:
>> gnuplot

• The Gnuplot CLI will start


• To plot the line with data from the first probe type:
>> plot 'p' using 1:2 with line

• To add another line with data from second probe:


>> replot 'p' using 1:3 with line

• Alternatively:

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.4 Post-processing 41

>> plot 'p' u 1:2 w l lw 2 title "p2", \


'p' u 1:3 w l lw 2 title "p2", \
'p' u 1:($4*100) w l lw 2 title "p4*100"

14
p2
p2
12 p4*100

10

0
0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6

• See http://www.gnuplot.info for more

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


42 More case setup/running

2.5 Multiphase flow: dam break


Dam break case

• Water column release

• Uses the interFoam solver

• Geometry in inches (in)

• Creates mesh with blockMesh using 5 blocks

• Simulate as laminar
atmosphere
23.00 in

leftWall rightWall

water column
23.00 in
11.50 in

2.00 in

1.00 in lowerWall
5.75 in 5.75 in

Modifying the tutorial damBreak case

• Copy the damBreak case locally, go into the directory and run blockMesh
>> run
>> cp -r $FOAM_TUTORIALS/multiphase/interFoam/laminar/damBreak/damBreak .
>> cd damBreak
>> blockMesh

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.5 Multiphase flow: dam break 43

Setting nonuniform initial field

• Volume of Fluid (VoF) method solves for fraction α of fluid phase(s)

• Nonuniform initial condition for the phase fraction of αwater (alpha)


(
1 for 100% water
αwater =
0 for 0% water (i.e. 100% air)

• setFields: initialises nonuniform fields according to setFieldsDict


18 defaultFieldValues // specify default values
19 (
20 volScalarFieldValue alpha.water 0
21 );
22
23 regions // specify regions of different values
24 (
25 boxToCell // uses same mesh set tools as cellSet
26 {
27 box (0 0 -1) (0.1461 0.292 1);
28 fieldValues
29 (
30 volScalarFieldValue alpha.water 1
31 );
32 }
33 );

Setting nonuniform initial field (2)

• The 0 contains a file alpha.water.orig

• Typical in OpenFOAM, the .orig file acts as a backup for the file used by the solver alpha.water

• When manipulating the fields in 0 directory, keep an original copy

• Run the setFields utility


>> setFields

• Now look at the 0/alpha.water file; note the boundary conditions

Transport and interface properties

• transportProperties contains a list of phases and transport property subditionaries for each phase.

• Each subdictionary includes a transportModel for the phase


– If Newtonian, kinematic viscosity specified under the keyword nu
– If another model, e.g. CrossPowerLaw, viscosity parameters are specified in a further subdictionary,
e.g. CrossPowerLawCoeffs

• The surface tension, a property of both phases, is specified by sigma

• The damBreak case uses properties of water and air

• Gravitational acceleration is specified as a uniformDimensionedField in the constant/g file

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


44 More case setup/running

Discretisation schemes

• Discretisation schemes must be set to all terms for each variable we solve differential equation for

• Settings is held in system/fvSchemes


18 ddtSchemes
19 {
20 default Euler;
21 }
22
23 gradSchemes
24 {
25 default Gauss linear;
26 }
27
28 divSchemes
29 {
30 div(rhoPhi,U) Gauss linearUpwind grad(U);
31 div(phi,alpha) Gauss vanLeer;
32 div(phirb,alpha) Gauss linear;
33 div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear;
34 }
35 ...

• Keyword default sets the scheme for all equations having this term

• When default is not specified, scheme must be specified explicitly for each variable derivation

• Keyword Gauss refers to Gauss–Green theorem for integration. Other option would be leastSquares

• The choice of discretisation scheme is always a choice between stability (upwind scheme) and precision
(linear scheme)

• Note the choice of discretisation scheme influences stability of the simulation with respect to the mesh
quality
• Documentation on schemes can be found in Doxygen at:
http://www.openfoam.com/documentation/cpp-guide/html/page-schemes.html

Most tutorials are build on orthogonal meshes allowing use of less stable but more precise discretisation
schemes. Thus user should be careful when applying the setup to a real–life meshes. Inspiration for more
robust setups can be taken from tutorials using snappyHexMesh.

Discretisation schemes for VOF

• OpenFOAM’s interface tracking solvers use OpenCFD’s multidimensional universal limiter for explicit
solution (MULES) method

– maintains boundedness of alpha. . .


– . . . independently of the underlying numerical scheme and mesh structure

• ⇒ choice of convection scheme not restricted to those that are strongly stable or bounded, e.g. upwind
differencing

• A reliable set of convection schemes is set up in system/fvSchemes


28 divSchemes
29 {
30 div(rhoPhi,U) Gauss linearUpwind grad(U);
31 div(phi,alpha) Gauss vanLeer;
32 div(phirb,alpha) Gauss linear;
33 }

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.6 Running in parallel 45

2.6 Running in parallel


Parallel running overview

• Parallel computing in OpenFOAM uses domain decomposition

• Geometry and associated fields are broken into pieces and allocated to separate processors

• decomposePar: performs domain decomposition using decomposeParDict configuration file

• Simple geometries: use hierarchical decomposition

• Complex geometries: use scotch decomposition

Domain decomposition

• Let’s run damBreak case on 4 CPUs

• Open system/decomposeParDict using gedit

• Modify the system/decomposeParDict file to a suitable number of CPUs


18 numberOfSubdomains 4; // no. of subdomains for decomposition
19
20 method hierarchical; // method of decomposition, simple geometries
21 //method scotch; // method of decomposition, complex geometries
22
23 hierarchicalCoeffs
24 {
25 n (2 2 1); // domain split into 2 in x direction
26 order xyz; // directions in which decomposition is done
27 delta 0.001; // set it to 0.001
28 }
29
30 distributed no; // is the data distributed
31 // across several disks?

• Now execute decomposePar


>> decomposePar

Try option -dry-run -verbose to see the decomposition distribution information without writing individual
domains.

Parallel running

• The case should be split into processor<n> directories, each containing its own part of the mesh and
fields
>> ls
0 constant processor0 processor1 system

• The case can be run in parallel using mpirun; the solver must be executed with the -parallel option
>> mpirun -np 4 interFoam -parallel

• Check there are 2 processes running, e.g. (kill with CTRL-C)


>> top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18767 ubuntu 25 0 184m 17m 10m R 101 1.7 0:04.28 interFoam
18768 ubuntu 25 0 184m 17m 10m R 99 1.7 0:04.25 interFoam
...

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


46 More case setup/running

Parallel running options

• Running on a cluster, a user wishes to run from machine aaa on the following machines: aaa; bbb, which
has 2 processors; and ccc

• The user should create a file, e.g. machines, containing:


1 aaa
2 bbb cpu=2
3 ccc

• The application is run with mpirun using the option:


–hostfile /path/to/machines

• For further information


>> mpirun --help

• foamJob script with -p option runs parallel cases using mpirun:

– automatically picks up no. of processors from no. of processor<n> directories


– automatically uses a file named machines if present in system directory

Post-processing and reconstruction

• reconstructPar utility: reassembles decomposed fields and mesh from processor<n> directories into
normal time directories

• Segments of domain can be post-processed individually by treating an individual processor<n> direc-


tory as a case in its own right, e.g. running
>> paraFoam -case processor1

• The decomposed case can be post-processed without reconstruction running


>> paraFoam -builtin

• . . . in Paraview in Properties window, user must select Decomposed in Case type list to see the whole
domain

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


2.6 Running in parallel 47

Results

• Field plot of phase fraction alpha.water at t = 0.25 s and at t = 0.50 s

Creating an animation

• The case can be animated in ParaView by clicking Play in the animation toolbars

• An animation can be saved by selecting File -> Save Animation

– In Paraview version 5.4 the animation can be saved directly to AVI format or . . .
– Write a set of image frames, e.g. in PNG format, damBreak*png

• The linux utilities described below are not installed on the cloud, but a typically installed on the desktop
versions of Ubuntu, Fedora or OpenSUSE

• PNG files can be converted into an animation, e.g. in MPG format with the convert utility in the
ImageMagick package
>> convert -quality 100% damBreak*png damBreak.mpg

• OR directly using mencoder


>> mencoder "mf://*.png" -mf fps=2 -o damBreak.mpg -ovc lavc -lavcopts
vcodec=mpeg4:autoaspect

• OR using OpenFOAM utility foamCreateVideo


>> foamCreateVideo -i damBreak -o video.mp4 -f 8

• The animation can be played with mplayer


>> mplayer -loop 0 damBreak.mpg

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


48 Extending basic functionality

3 Extending basic functionality


Extension with functionObjects

• Solvers typically output only basic set of volumetric fields of solved variables and information on algebraic
solvers

• All the other information can be extracted (on the fly or a posteriori) using (function objects) - func-
tionality pre-compiled in the dynamic library which is only linked to the executable at the beginning of
execution

• Easy way how to extend the functionality of OpenFOAM

• Mainly for post-processing and run control

• functionObjects specified in the case controlDict file

• Note the function objects has been considerably reworked from version OpenFOAM-v1606+

• See doxygen:
http://www.openfoam.com/documentation/cpp-guide/html/

• Post-processing functions:

– On fields – Courant number, Field average, Flux summary, pressure and others
– Forces – forces, force coefficients
– Solvers – Scalar transport

Function objects

• The function objects need to be set in controlDict

• Controls for each function object is described in Doxygen


CourantNo1
{
type CourantNo;
libs ("libfieldFunctionObjects.so");
...
}

• Function objects can be used to construct specific results

• Resulting values are recorded into a post–processing file in postProcessing direcotry

• Integral informative values can be also printed into terminal stream

• Writting of fields or other information into a file in time–directory or postProcessing directory is


controlled via options:

writeControl – timeStep, writeTime, clockTime, onEnd . . .


writeInterval ß
18 fieldMinMax
19 {
20 type fieldMinMax;
21 libs ("libfieldFunctionObjects.so");
22 log yes; // into Info stream
23 writeControl timeStep;
24 writeInterval 10;
25 mode magnitude;
26 fields ( U T k );
27 }

• Templates are located in $FOAM_ETC/caseDicts/postProcessing

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


49

Function objects

• There are several ways how to run function objects:

– During runtime by specifying the functions in the controlDict . . . see TJunction


functions
(
arbitraryName
{
type CourantNo
...
}
)

– In a post-processing stage by running the solver with option -postProcess which will run the
function objects defined in the controlDict
>> simpleFoam -postProcess

– In a post-processing stage by running solver with -postProcess -func command line option to
execute only the function object specified on the command line
pimpleFoam -postProcess -func yPlus

– By running utility postProcess with the function specification


postProcess -func CourantNo

• The function object which needs a field to be read from the particular time directory should be run with
a -fields option

• When the function requires more arguments, the following syntax is used:
postProcess -func "patchAverage(name=outlet,U)"

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


50 Extending basic functionality

Dynamic code

• C++ code used in case setup files

• Code is compiled and linked to executable at the start of utility or solver execution

• Code snippets in the case directories #codeStream, for example in controlDict:


startTime 0;
endTime 100;
..
writeInterval #codeStream
{
code
#{
scalar start = readScalar(dict["startTime"]);
scalar end = readScalar(dict["endTime"]);
label nDumps = 5;
os << ((end-start)/nDumps);
#};
};

• Simple arithmetic expressions in a single line #calc, for example:


magUinlet 1;
turbIntensity 0.1;
inletDiameter 0.1;
lengthScale #calc "0.07 * $inletDiameter"
tkeInlet #calc "1.5*sqr($magUinlet * $turbIntensity)"
omegaInlet #calc "sqrt($tkeInlet)/(pow(0.09,0.25)*$lengthScale)"

• Coded boundary conditions using codedFixedValue or codedMixed

• Coded Function object coded

• Coded source term

• To be able to code boundary condition or other Dynamic code snippet, it is necessary to understand
basic common approaches and design of the code

• For detailed description refer to the Appendix, more detailed explanation is given in the Advanced
training

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


51

4 Programming background
4.1 C++ overview
OpenFOAM Programming: language in general

• The success of any language is due to efficiency in expressing concepts

• Using verbal language, ‘velocity field’. . .

– has abstract meaning without reference to the type of the flow or specific data
– encapsulates the idea of movement with direction and magnitude
– relates to other physical properties

• In mathematical language, we represent velocity field by a single symbol ‘U’

– Symbols can express further concepts, e.g. the field of velocity magnitude by |U|

• This is emulated in OpenFOAM

– Our velocity field can be represented by U


– ‘The field of velocity magnitude’ can be mag(U)

Equation representation in OpenFOAM

• Top level code represents the equations being solved, e.g.

∂ρU
+ ∇ • ρUU + ∇ • ρR = − ∇p
| ∂t
{z } | {z } | {z } |{z}
1 2 3 4

1. Local rate of change of ρU

2. Convective rate of change of ρU

3. Viscous dissipation (laminar + turbulent)

4. Pressure gradient
1 solve
2 (
3 fvm::ddt(rho, U)
4 + fvm::div(phi, U)
5 + turbulence->divDevRhoReff(U)
6 ==
7 - fvc::grad(p)
8 );

• Uses polymorphism: objects of different classes respond differently to functions of the same name

– solve function behaves differently depending on the class (type) it operates on


– +, -, == operators have been overloaded
– divDevRhoReff function is overridden by each turbulence model, so is interpreted differently de-
pending on the model selected at runtime
– Improves code readability

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


52 Programming background

Classes and objects

• Velocity is a vector field. In object-oriented programming. . .

– there could be a vectorField class


– the velocity field U would be an instance or object of that class

• Temperature, pressure, density are scalar fields

– there could be a scalarField class


– p, T, rho would be objects of that class

• C++ provides template classes, e.g. Field<Type>

– The <Type> can be scalar, vector, tensor


– General features of the template class are passed on to any class created from it
– Reduces code duplication

Class hierarchy

Classes Functions
List<Type> size()

Field<Type> operator+(..., ...)

• C++ allows a hierarchy of classes


• Generic concepts can be defined in a base class, e.g. List<Type>
• A derived class, e.g. Field<Type> can be formed from base classes
• The derived class inherits attributes/behaviour of the base classes
• e.g. we could access the size of vectorField U with U.size()

Class files
For a class vector
• Class definition in vector.C:
– a set of instructions such as object construction, data storage and functions
• Compilation of vector.C:
– either with an application file Test-vector.C — containing the main function — into an application
executable Test-vector
– or into a shared object library OpenFOAM.so that is linked to Testvector
• Class declaration in vector.H:
– a list of defined functions etc., not the functions themselves
– every compiled (.C) file needs this list for the classes it uses
– the .H file must be included before any code using the class (including the class declaration .C code
itself)
#include "vector.H";

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


4.2 Code compilation 53

Compiling and linking

Main code vector class

Test-vector.C Header file vector.H


#include "vector.H" -I option Definition...
int main()
{
vector d(1, 2, 3);
... vector.C
return(0); #include "vector.H"
} Code...

Compiled Compiled
Test-vector Linked OpenFOAM.so
Executable -l option Library

Basic structure of C++ classes


C++ classes contain data and functions

• Private data and functions: only accessible to the class itself

– protects a class from bugs introduced by external code

• Public functions (and data) accessible from outside of the class, including

– Constructors: code to construct an object of the class


– Access functions: functions that access private data functions
– Operators: Definitions of operators, e.g. +, -, etc.

4.2 Code compilation


Compilation example: pisoFoam – optional

1. Make a local source code directory in the user’s account and go into that directory
>> mkdir -p $WM_PROJECT_USER_DIR/applications
>> cd !$

• Note: !$ or !:$ — word designator, meaning “last argument on previous line”, i.e. the directory
that has been created

2. Copy the pisoFoam source code from the installation and go into the directory
>> cp -r $FOAM_SOLVERS/incompressible/pisoFoam .
>> cd pisoFoam

3. Change $FOAM_APPBIN to $FOAM_USER_APPBIN in the Make/files file


1 pisoFoam.C
2
3 EXE = $(FOAM_USER_APPBIN)/pisoFoam

4. Compile with wmake


>> wmake

• Let’s explain how the compilation works...

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


54 Programming background

Compilation with wmake

• OpenFOAM uses its own compilation tool wmake


• . . . designed for a single package containing 100s of applications/libraries
• Application/library code requires a Make directory, containing 2 files
– files: List of compiled .C file(s) and executable name
– options: Compilation options
• wmake builds a dependency list with .dep file extension, e.g. pisoFoam.dep

– Can be used to locate included files on the system

• For a library, wmake creates an lnInclude directory with links to all source files
– A good place to search for files, e.g. $FOAM_SRC/OpenFOAM/lnInclude

wmake: the files file

• The files file contains a list of .C source files that must be compiled

– It does not need the .C files already compiled into linked libraries
– Often, the ‘list’ is just the single main .C file

• For applications, “EXE =” specifies the path/name of the compiled executable


• For libraries, “LIB =” specifies the path/name of the compiled library
• Standard release applications are stored in $FOAM_APPBIN (libraries in $FOAM_LIBBIN)
• User applications should go in $FOAM_USER_APPBIN
• $FOAM_USER_APPBIN takes precedence on the system $PATH so a user application will ‘override’ a release
application of the same name
– e.g. test for pisoFoam by typing:
>> which pisoFoam
/home/ubuntu/OpenFOAM/.../linuxGccDPOpt/bin/pisoFoam

wmake: including headers

• The compiler searches for included files in the following directories:


1. $WM_PROJECT_DIR/src/OpenFOAM/lnInclude
2. pisoFoam/lnInclude: a local lnInclude directory
3. pisoFoam: the local directory
4. platform dependent paths set in $WM_DIR/rules/$WM_ARCH, e.g.
/usr/X11/include
5. Other directories specified in the Make/options file with the -I option
• The Make/options file contains the full directory paths, e.g.
1 EXE_INC = \
2 -I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
3 -I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
4 -I$(LIB_SRC)/transportModels \
5 -I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
6 -I$(LIB_SRC)/finiteVolume/lnInclude \
7 -I$(LIB_SRC)/meshTools/lnInclude \
8 -I$(LIB_SRC)/sampling/lnInclude

• Uses a common UNIX scripting syntax of a backslash (\) to continue across lines

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


4.2 Code compilation 55

wmake: linking to libraries

• The compiler links to shared object libraries in the following directory paths:

1. $FOAM_LIBBIN
2. platform dependent paths set in $WM_DIR/rules/$WM_ARCH/ directory, e.g./usr/X11/lib
3. Other directories specified in the Make/options file with the -L option, typically
7 EXE_LIBS = -L$(FOAM_USER_LIBBIN)

• The actual library files to be linked are:

1. the libOpenFOAM.so library from the $FOAM_LIBBIN directory


2. platform dependent libraries, e.g.libm.so from /usr/X11/lib
3. other libraries specified in the Make/options file with the -l option, removing the lib prefix and .so
extension from the library file name
7 EXE_LIBS = \
8 -lturbulenceModels \
9 -lincompressibleTurbulenceModels \
10 -lincompressibleTransportModels \
11 -lfiniteVolume \
12 -lmeshTools \
13 -lfvOptions \
14 -lsampling

wmake: compiling

• To compile, change to the directory tree containing the Make folder and type
>> wmake

• Alternatively, include the application directory path as an argument, e.g.


>> wmake $FOAM_SOLVERS/incompressible/pisoFoam

wclean: cleaning up after wmake

• Sometimes after making code changes, or before packing a solver to send elsewhere, .dep files need
removing

• To clean a source directory, go to the directory and type


>> wclean

• The wrmdep script also removes .dep files recursively down a directory tree

Getting started with OpenFOAM programming

• Utilities and basic solvers provide the easiest introduction to OpenFOAM programming because

• . . . they introduce OpenFOAM classes without needing to look at class code

• . . . they illustrate C++ and OpenFOAM syntax

• . . . and they demonstrate code compilation

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


56 Programming background

4.3 Utility walk through


Utility walk through

• Let us look at a post-processing utility that creates total pressure from static p and U
• Simple utility ptot shows how the code works with fields of values and how it reads them from the files
and writes it down
• The utility is not any more part of the latest OpenFOAM, but we will walk through it as it shows
important principles
• Let’s go to the source code directory
run
cp -r /opt/OpenFOAM/extra/ptot .
cd ptot

• It contains a file called ptot.C. . .


• . . . and a Make directory
• Open the source code ptot.C with a gedit

The fvCFD.H file

• Following the comment block at the top of ptot.C:


32 #include "fvCFD.H"

• fvCFD.H is a file containing a selection of included class header files that are generally relevant to finite
volume CFD, e.g.:
– Time.H: the Time database
– fvMesh.H: the finite volume mesh class
– fvc.H, fvMatrices.H, fvm.H, etc.: finite volume equation discretisation
– argList.H: handles terminal argument list
– . . . and more
• Some of these may not be needed, but it does not matter much; if the application is CFD-related, just
include fvCFD.H
• fvCFD.H is in $FOAM_SRC/finiteVolume/lnInclude and classes compiled in the finiteVolume library
• Make/options:
1 EXE_INC = \
2 -I$(LIB_SRC)/finiteVolume/lnInclude
3
4 EXE_LIBS = \
5 -lfiniteVolume \
6 -lgenericPatchFields

Time and command line options

• The first part of the code is concerned with Time and command line options
36 int main(int argc, char *argv[])
37 {
38 timeSelector::addOptions();
39 #include "addRegionOption.H"
40
41 #include "setRootCase.H"
42 #include "createTime.H"
43
44 instantList timeDirs = timeSelector::select0(runTime, args);

• timeSelector::addOptions(): reads command line options that apply utility to data from selected
time directories only

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


4.3 Utility walk through 57

• setRootCase.H: sets the root path and case directories according to the arguments
• createTime.H: instantiate runTime of the type Time — a class that holds information relating to time
which acts as a database for the simulation
• timeSelector::select0() function returns a list of time directories to calculate ptot for

Database for OpenFOAM cases

controlDict Time runTime

fvSchemes
fvMesh mesh mesh2
fvSolution

Properties nu Fields p U Dictionaries turbulenceProperties

• OpenFOAM has a hierarchical database for case data wich is held in the memory
• Time: top-level objectRegistry; controls time and data reading/writing
– Object typically named runTime
– Reads controlDict
• fvMesh: next level of objectRegistry
– Object typically named mesh, but can be more than one
– Reads fvSchemes and fvSolution
• Fields, properties, dictionaries registered with a particular fvMesh

Creating a mesh and looping over times


46 # include "createNamedMesh.H"
47
48 forAll(timeDirs, timeI)
49 {
50 runTime.setTime(timeDirs[timeI], timeI);

• createMesh.H: instantiates mesh of type fvMesh — finite volume mesh


21 fvMesh mesh
22 (
23 IOobject
24 (
25 fvMesh::defaultRegion,
26 runTime.timeName(),
27 runTime,
28 IOobject::MUST_READ
29 )
30 );

• runTime set to particular time from the timeDirs list

Info statements

• The next line is an Info<< statement


• Info output stream is an OpenFOAM version of Pout output stream
52 Info<< "Time = " << runTime.timeName() << endl;

• Messages (terminal) written by Info messageStream, syntax:


1 Info<< "message1" << "message2" << FoamDataType << endl;

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


58 Programming background

• Useful diagnosatic tool:


– used to monitor a field, cell value, energies, etc. in a simulation
– statements can be inserted to find the line where a code ‘blows up’
• Useful post-processing tool: this will be demonstrated later

Reading and writing case data

• Most case data is read/written using the IOobject class


• An IOobject is typically constructed from
Name used for the name of the file
Instance used for the name of the directory
Object Registry that the object is registered with
Read Option controls reading from file; defaults to NO_READ
Write Option controls writing to file; defaults to NO_WRITE
• For the pressure field, the IOobject is
54 IOobject pheader
55 (
56 "p", // Name of pressure field file
57 runTime.timeName(), // Time directory it is read from
58 mesh, // The mesh object registry
59 IOobject::MUST_READ // Read p in from file
60 IOobject::NO_WRITE // Do not "automatically" write it out
61 );

• Further code creates an IOobject for U

Reading a field
72 if (pheader.headerOk() && Uheader.headerOk())
73 {
74 mesh.readUpdate();
75
76 Info<< " Reading p" << endl;
77 volScalarField p
78 (
79 pheader, // IOobject
80 mesh // fvMesh
81 );

• headerOk() function checks if p and U files exist


• mesh.readUpdate() re-reads the mesh if modified
• Constructs a volScalarField for p by reading from file, using
IOobject instructs where to read/write the file
fvMesh the mesh that relates to the field, to ensure consistency
• Further code creates a volVectorField for U

Access functions

• Objects like p contain a lot of stored data


• Data can be accessed by functions using syntax object.functionName()
• For example, for p, we could call the following
p.mesh() returns the mesh relating to the pressure field
p.name() returns the name of the pressure field
p.dimensions() returns the dimensions
p.internalField() returns the internal field (cell values) only
p.oldTime() returns the pressure field from the previous time step
p.size() returns size of the pressure field (number of cells)

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


4.3 Utility walk through 59

Finding functions that exist

• Users want to know if functions exist that do what they need

• Source code documented using Doxygen (http://www.doxygen.org)

• Can be accessed online:


http://www.openfoam.com/documentation/cpp-guide/html/

• Can be built from sources using doxygen (may require root permission; ensure OpenFOAM env variables
are set)
>> cd $WM_PROJECT_DIR/doc/Doxygen
>> doxygen

• From the top level, the Classes menu is particularly useful

• Alphabetical List and Class Members are useful sub-menus

• In Class description, List of all members is particularly useful

• Inheritance and collaboration diagrams provide description of class hierarchy

Creating a new field

83 if (p.dimensions() == dimensionSet(0, 2, -2, 0, 0))


84 {
85 volScalarField ptot
86 (
87 IOobject
88 (
89 "ptot",
90 runTime.timeName(),
91 mesh,
92 IOobject::NO_READ
93 ),
94 p + 0.5*magSqr(U)
95 );
96 ptot.write();
97 }

• Code compares dimensions of pressure to those of kinematic pressure: L2 /T2

• Code evaluates differently depending on dimensions

– for kinematic pressure, it evaluates p + |U|2 /2


– for dynamic pressure, it evaluates p + ρ|U|2 /2

• For kinematic pressure, constructs a volScalarField named ptot from an IOobject and p + 0.5*magSqr(U)

• write() function writes the ptot field to the current time dir.

Ending the utility

133 else
134 {
135 Info<< " No p or U" << endl;
136 }
137
138 Info<< endl;
139 }
140 return 0;
141 }

• Print a terminal Info message if p and U field does not exist in the current time directory

• Ends with return 0;

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


60 Programming background

Summary of key classes

• #include createTime.H: creates Time database named runTime

• #include createMesh.H: creates fvMesh named mesh

• IOobject class controls data read/write and storage on database

• volScalarField, volVectorField classes create field objects, e.g. p, U

• dimensionSet class defines dimensional units

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


61

5 Solver development
5.1 Modifying a solver
Solver source code

• Let us look at icoFoam

• Go to the equivalent solver directory


>> cd $FOAM_SOLVERS/incompressible/icoFoam
>> gedit icoFoam.C

• It contains the C++ files icoFoam.C and createFields.H

Basic classes in OpenFOAM

• There are a number of basic classes in OpenFOAM

• . . . derived from more fundamental C++ classes

• OpenFOAM’s classes have a bit more functionality, so use them

C++ class OpenFOAM class and additional features


int/long label Automatic switching
bool Switch Accepts true/false, on/off, yes/no
string word Strings with no whitespace, ‘/’, etc.
float/double scalar Depends on $WM_PRECISION_OPTION
— vector 3D vector with algebra
— tensor 3×3 tensor with algebra

• Note: C++ has a vector class, similar to an array

5.2 Dictionary I/O


The createFields.H file

• The icoFoam.C file begins with #include files discussed previously until. . .
76 # include "createFields.H"

• Creation of solver fields usually contained within a createFields.H file

• Creates an IOdictionary from an IOobject that reads in the case file constant/transportProperties:
3 IOdictionary transportProperties
4 (
5 IOobject
6 (
7 "transportProperties", // name of the file
8 runTime.constant(), // case "constant" directory
9 mesh, // mesh object registry
10 IOobject::MUST_READ_IF_MODIFIED, // read from file and update
11 // if modified
12 IOobject::NO_WRITE // do not write to file
13 )
14 );

• Creates kinematic viscosity nu of type dimensionedScalar by a lookup of keyword nu from transportProperties


15 dimensionedScalar nu
16 (
17 "nu",
18 dimViscosity,
19 transportProperties.lookup("nu")
20 );

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


62 Solver development

Dictionary lookup

• The user can therefore read in keyword entries by

1. Creating an IOdictionary
2. Looking up entries with the .lookup("keyword") function

• lookup("keyword") returns an Istream

• Most objects can be constructed from Istream, e.g.


class object(dict.lookup("keyword")); // Construct from Istream

• . . . because type of object can be established from syntax, e.g.

– string ("hello world")


– word (hello)
– Switch (on/yes/true)
– dimensionedScalar

• scalar (1) and label (1) are exceptions

• ⇒ special readLabel/readScalar functions create a scalar/label


scalar a(readScalar(dictionary.lookup("a")));
label i(readLabel (dictionary.lookup("i")));

5.3 Fields and field algebra


Field construction

• Pressure created by
21 volScalarField p
22 (
23 IOobject
24 (
25 "p",
26 runTime.timeName(),
27 mesh,
28 IOobject::MUST_READ,
29 IOobject::AUTO_WRITE // write out to file automatically
30 ),
31 mesh
32 );

• AUTO_WRITE applied to fields we write out to time directories according to controlDict settings

• All fields written out by write() function called on the database in icoFoam.C
99 runTime.write();

• 3 common ways to construct a field, with different file read/write options:

Read Write Constructor


✓ ✓/✕ volScalarField(IOobject, fvMesh)
✕ ✓ volScalarField(IOobject, volScalarField)
✕ ✕ volScalarField(volScalarField)

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


5.3 Fields and field algebra 63

More about fields

• Velocity flux instantiated as surfaceScalarField


50 #include "createPhi.H"

$FOAM_SRC/finiteVolume/lnInclude/createPhi.H:
39 surfaceScalarField phi
40 (
41 IOobject
42 (
43 "phi",
44 runTime.timeName(),
45 mesh,
46 IOobject::READ_IF_PRESENT, // Read if file exists
47 IOobject::AUTO_WRITE
48 ),
49 fvc::flux(U) // ...otherwise evaluate
50 );

• Function fvc::flux() returns following:

• linearInterpolate(U) & mesh.Sf()

– What is a volScalarField, surfaceScalarField, etc.?


– What is the “&” symbol?
– What about “mesh.Sf()”?

Meshes

Sf
P

d N

Description Symbol Function


Cell volumes V V()
Old time step cell volumes Vo VO()
Old-old time cell volumes V oo VOO()
Face area vectors Sf Sf()
Face area magnitudes |Sf | magSf()
Cell centres C C()
Face centres Cf Cf()
Face motion fluxes φ phi()

• There is a hierarchy of mesh classes including geometricMesh, polyMesh

• fvMesh: includes extra functionality for finite volume discretisation

• In particular, it stores data relating to access functions above

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


64 Solver development

Tensor fields

• Fields can be of the following <Type>

Rank Name <Type> Example nCmpts


0 Scalar scalar p 1
1 Vector vector U 3
2 Tensor (general) tensor ∇U 9
2 Symmetric tensor symmetricTensor ∇U + ∇UT 6
2 Spherical tensor sphericalTensor pI 1

• Special tensors are constructed by default, e.g. Identity tensor I:


$FOAM_SRC/OpenFOAM/lnInclude/sphericalTensor.H:
51 static const sphericalTensor I(1);

Field algebra

• Algebra can be performed on fields

Operator Ranks Expression OpenFOAM


Inner product ≥1 a•b a & b
Double inner product 2 a •• b a && b
Cross product 1 a×b a ^ b
Outer product ab† a * b
Square a2 ≡ aa sqr(a)
Magnitude squared |a|2 ≡√a R• a magSqr(a)
Magnitude |a| ≡ a R• a mag(a)
Transpose 2 aT a.T()
Trace 2 tr a = I •• a tr(a)
Symmetric 2 symm a = (a + aT )/2 symm(a)
Skew 2 skew a = (a − aT )/2 skew(a)
Deviatoric 2 dev a = a − (tr a)I/3 dev(a)
Deviatoric (II) 2 devII a = a − 2(tr a)I/3 dev2(a)
†a ⊗ b

• There are more operators, like transcendental scalar functions, sin, exp etc.

Field interpolation

• Interpolation: transforms a vol<Type>Field to a surface<Type>Field

• fvc::interpolate(Q): generic interpolation function

– scheme selected in fvSchemes case file

• linearInterpolate: hard coded linear interpolation, e.g. for Q

|nf • dfN |
Qf = wf QP + (1 − wf )QN , wf =
|nf • d|

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


5.3 Fields and field algebra 65

dfN
nf d
N

The flux phi

• Let’s return to the expression for phi

volVectorField fvMesh
z}|{ z }| {
linearInterpolate( U ) & mesh .Sf()
| {z } |{z} | {z }
surfaceVectorField •
surfaceVectorField

• Returns the surfaceScalarField phi from inner product of two surfaceVectorFields

• phi: volumetric flux through the cell faces

• OpenFOAM will not permit algebra between a vol<Type>Field and a surface<Type>Field

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


66 Solver development

5.4 Implementing equations


Back to the solver. . .

• Next. . .
92 while (runTime.loop())
93 {
94 Info<< "Time = " << runTime.timeName() << nl << endl;
95
96 # include "readPISOControls.H"
97 # include "CourantNo.H"
98
99 fvVectorMatrix UEqn
100 (
101 fvm::ddt(U)
102 + fvm::div(phi, U)
103 - fvm::laplacian(nu, U)
104 );
105
106 solve(UEqn == -fvc::grad(p));

• Important. . . creating and solving equations

• We need to understand what fvVectorMatrix, fvm::, solve, etc. mean

Discretisation

• Discretisation ≡ approximation of a continuous problem into discrete quantities

Continuous Discrete OpenFOAM class


Time Time steps (intervals) Time
Space (geometry) Mesh of cells fvMesh
Fields Cell values vol<Type>Field
Differential eqns. Algebraic eqns. fv<Type>Matrix

• fv<Type>Matrix describes an algebraic equation for a vol<Type>Field, e.g. Q, storing:

– [M ] = matrix coefficients
– B = source — also a vol<Type>Field

     
M11 M12 ... M1N Q1 B1

 M21 M22 ... M2N 


 Q2 


 B2 

 .. .. .. ..   ..  =  .. 
 . . . .   .   . 
MN 1 MN 2 ... MN N QN BN

[M ] Q = B

Terms in equations/expressions

• Equations contain derivatives such as ∇ • , ∇, ∇2 , ∇×

• OpenFOAM has functions for derivatives, e.g. div, grad, laplacian, curl

• To calculate derivatives with current values, prefix with fvc::

– e.g.fvc::grad(p) calculates the pressure gradient ∇p


– fvc:: returns a field

• To discretise a term into matrix equation you wish to solve, prefix with fvm::

– e.g. to solve ∇ • Γ∇p = 0, use fvm::laplacian(Gamma, p)


– fvm:: returns an fvMatrix

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


5.4 Implementing equations 67

Solution method and equations

• OpenFOAM uses the finite volume method for discretisation

• Co-located framework: solution fields defined at cell centres

• Segregated, decoupled: solves scalar matrix equations in an iterative sequence

• ⇒ There are only 4 terms that can form matrix coefficients, i.e. can “be” fvm::

Description Expression Function


Time derivative ∂ρQ/∂t fvm::ddt(rho, Q)
Convection ∇ • (ρUQ) fvm::div(phi, Q)
Laplacian ∇ • Γ∇Q fvm::laplacian(Gamma, Q)
Source ρQ fvm::Sp(rho, Q)

• Equivalent functions exist for ∂Q/∂t and ∇2 Q (without ρ, Γ)

• Convective derivative: fvm::div function with surfaceScalarField flux (phi) as the 1st argument

Common source terms/derivatives

• Equation (explicit) source terms can be calculated using the following functions

Description Expression Function


Divergence ∇•Q fvc::div(Q)
Gradient ∇Q fvc::grad(Q)
Curl ∇×Q fvc::curl(Q)
Source Q Q

Back to the solver. . .

• Solver implements the momentum equation


∂U
+ ∇ • (UU) − ∇ • ν∇U = −∇p
∂t

• All terms in U can be treated implicitly (fvm::)

• fvVectorMatrix created for all terms except ∇p (we will find out why later)
100 fvVectorMatrix UEqn
101 (
102 fvm::ddt(U)
103 + fvm::div(phi, U)
104 - fvm::laplacian(nu, U)
105 );

• The “right hand side” (fvc::grad(p)) introduced with the == operator

• solve function solves the fvVectorMatrix equation


109 solve(UEqn == -fvc::grad(p));

• Next. . . the PISO loop

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


68 Solver development

5.5 PISO, SIMPLE, PIMPLE algorithms


Mass conservation in incompressible flows

• Mass conservation equation


∂ρ
+ ∇ • (ρU) = 0
∂t
• Incompressible ⇒ ρ = const
∇•U = 0

• 3 components of velocity Ux , Uy , Uz ; only 1 equation


• A constraint, not a solvable equation
• Incompressible flow is often dominated by this constraint
• Q: How can we solve the system ensuring this constraint is satisfied?
• A: Use the pressure-implicit split-operator (PISO) algorithm

The “trick” in PISO

• Manipulation of [U Eqn]]
"+ ◦ ◦ #" # " #
+ ◦ ◦
◦ ◦

+
+ ◦
U = B
◦ ◦ +
"+ #" # " # " ◦ ◦
#" #
+ ◦◦
+ U = B − ◦◦ U
+ ◦ ◦
+ ◦ ◦
| {z } | {z }
A H(U)

• A and H are evaluated by functions UEqn.A() and UEqn.H()


– A contains 1 value per cell ⇒ a volScalarField
– H is calculated using latest values of U ⇒ a volVectorField
• Explicit momentum equation
∂U
+ ∇ • (UU) − ∇ • ν∇U = − ∇p
∂t
[U Eqn]] = − ∇p

AU = − ∇p + H

Equations in PISO

• From the expression for momentum


AU = H − ∇p

• . . . a momentum corrector equation can be written


H 1
U= − ∇p
A A
• Applying mass continuity (∇ • U = 0), a pressure corrector equation is derived
µ ¶
1 H
∇ • ∇p = ∇ •
A A
• A flux corrector equation can be written
·µ ¶ µ ¶ ¸
H 1
φ = S f • Uf = S f • − (∇p)f
A f A f

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


5.5 PISO, SIMPLE, PIMPLE algorithms 69
PISO algorithm
New p, U, φ
Start time step

Momentum matrix [U Eqn]]

Solve momentum [U Eqn]] = −∇p

Evaluate H(U), A
µ ¶
1 H
Pressure corrector ∇ • ∇p = ∇ •
A A

New p

Momentum corrector H 1
and flux corrector U = A − A ∇p
φ = Sf • [(H/A)f − (1/A)f (∇p)f ]
End time step

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


70 Solver development

PISO algorithm and OpenFOAM code


Start time step
100 fvVectorMatrix UEqn
101 (
102 fvm::ddt(U)
[U Eqn]] 103 + fvm::div(phi, U)
104 - fvm::laplacian(nu, U)
105 );
109 solve(UEqn == -fvc::grad(p));
[U Eqn]] = −∇p
115 volScalarField rUA = 1.0/UEqn.A();
Evaluate H(U), A 116 HbyA = rUA*UEqn.H();

µ ¶ 117 surfaceScalarField phiHbyA =


1 H 118 ... (fvc::interpolate(HbyA) & mesh.Sf())
∇ • ∇p = ∇ • 136 fvScalarMatrix pEqn
A A 137 (
138 fvm::laplacian(rUA, p) == fvc::div(phiHbyA)
139 );
New p
141 pEqn.solve(mesh.solver(p.select(
142 piso.finalInnerIter())));
H 1
U= − ∇p 151 U = HbyA - rUA*fvc::grad(p);
A A
φ = Sf • [(H/A)f − (1/A)f (∇p)f ] 145 phi = phiHbyA - pEqn.flux();
End time step

Final comments on the solver

• A flux() function returns the flux field from the matrix

• Loop over the pressure, momentum and flux correctors


113 while (piso.correct())

• Correct fluxes to conserve globally in badly-posed cases


124 adjustPhi(phiHbyA, U, p);

• Loop over the pressure to correct non-orthogonality

:tabnew >0 13 while (piso.correctNonOrthogonal())

• See $FOAM_SRC/finiteVolume/cfdTools/general/solutionControl/ solutionControl/solutionControlI.

• Set value in pRefCell to pRefValue for cases with no fixedValue p boundary


139 pEqn.setReference(pRefCell, pRefValue);

• . . . which is set to 0 or read from system/fvSolution file

SIMPLE: Semi-implicit methods pressure-linked equations

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


5.6 Modifying a solver 71

New p, U, φ
Start time step
p, U, φ
Momentum matrix [U Eqn]]
Under-relax [U Eqn]]
Solve momentum [U Eqn]] = −∇p

Evaluate H(U), A
µ ¶
1 H
Pressure corrector ∇ • ∇p = ∇ •
A A

Under-relax p

Momentum corrector H 1
and flux corrector U = A − A ∇p
φ = Sf • [(H/A)f − (1/A)f (∇p)f ]
End time step

Advantages and disadvantages of PISO and SIMPLE (SIMPLEC)

Algorithm PISO SIMPLE


Efficiency Fast: [U Eqn]] created once Slower: Under-relaxation
Stability Typically unstable for Co > 1 Stable for Co > 1
Accuracy Potential ∂/∂t error —

• Advantages/disadvantages relate to algorithm loop structure, particularly construction of the momentum


matrix [U Eqn]]
• SIMPLEC algorithm (SIMPLE corrected) has faster rate of convergence, compared to SIMPLE (The
under-relaxation factors must be adjusted).

PIMPLE algorithm

• PIMPLE algorithm combines the loop structures of PISO and SIMPLE

• Used in solvers with ∂/∂t terms in equations

• Can run transient: not Co limited, unlike PISO

• Can run pseudo-transient: big time steps to reach steady-state with minimal under-relaxation

5.6 Modifying a solver


Exercise: add an energy equation to icoFoam

• Task: to create a new icoThermalFoam solver by modifying icoFoam

• . . . by adding an energy (temperature) transport equation

∂T
+ ∇ • (UT ) − ∇ • DT ∇T = 0
∂t

• Create the icoThermalFoam source directory by copying icoFoam from $FOAM_SOLVERS


>> cd $WM_PROJECT_USER_DIR/applications
>> cp -r $FOAM_SOLVERS/incompressible/icoFoam icoThermalFoam
>> cd icoThermalFoam
>> wclean
>> mv icoFoam.C icoThermalFoam.C

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


72 Solver development

• Edit the Make/files file:


icoThermalFoam.C
EXE = $(FOAM_USER_APPBIN)/icoThermalFoam

• Compile the solver

icoThermalFoam solver: energy equation

• Where do we insert the energy equation in the solver?

• Coupling from momentum to energy equation due to convection

• No coupling from energy to momentum

• ⇒ energy equation can be added at the end of each time step, line 144
144 solve
145 (
146 fvm::ddt(T)
147 + fvm::div(phi, T)
148 - fvm::laplacian(DT, T)
149 );

icoThermalFoam solver: temperature field

• We need to add a new temperature field T

• Open the createFields.H file

• Copy the p field constructor (lines 20–33)

• Paste to line 49 and replace p by T (in 3 places)


49 Info<< "Reading field T\n" << endl;
50 volScalarField T
51 (
52 IOobject
53 (
54 "T",
55 runTime.timeName(),
56 mesh,
57 IOobject::MUST_READ,
58 IOobject::AUTO_WRITE
59 ),
60 mesh
61 );

icoThermalFoam solver: thermal diffusivity

• We need to add a new thermal diffusivity DT


• Like viscosity nu, it must be a dimensionedScalar

• In the createFields.H file, copy the nu constructor (lines 15–18)

• Paste to line 20 and replace nu by DT (in 2 places)


20 dimensionedScalar DT
21 (
22 "DT",
23 dimViscosity,
24 transportProperties.lookup("DT")
25 );
26

• Compile the new solver

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


5.6 Modifying a solver 73

icoThermalFoam: cavityClippedThermal case

• Create a cavityClippedThermal case by cloning the cavityClipped case


>> run
>> cp -r cavityClipped cavityClippedThermal
>> cd cavityClippedThermal

• Clone the 0/T file from 0/p


>> cp 0/p 0/T

• Edit 0/T to initialise with 400K on lid, 300K on other walls


17 dimensions [0 0 0 1 0 0 0]; // Dimensions of temperature
18
19 internalField uniform 300; // Initialise with uniform 300 K
20
21 boundaryField
22 {
23 lid
24 {
25 type fixedValue; // Fixed temperature
26 value uniform 400; // 400 K
27 }
28
29 fixedWalls
30 {
31 type fixedValue; // Fixed temperature
32 value uniform 300; // 300 K
33 }
34 ...

cavityClippedThermal: properties and settings

• Create thermal diffusivity DT; set to 0.1× kinematic viscosity


17 nu [ 0 2 -1 0 0 0 0 ] 0.01;
18 DT [ 0 2 -1 0 0 0 0 ] 0.001;

• Set endTime to 2 in controlDict to allow time for thermal convection


26 endTime 2;

• Add discretisation scheme for convection of T in fvSchemes


32 div(phi,T) Gauss linear; // Central-differencing on convection

• Check default settings for other terms e.g. Laplacian in fvSchemes


35 laplacianSchemes
36 {
37 default Gauss linear orthogonal;
38 ...

• Set matrix solver for T eqn to be the same as U eqn in fvSolution


28 "(U|T)" // Change U->"(U|T)" ; means "U or T"
29 {
30 solver smoothSolver;
31 ...

• Run icoThermalFoam
>> icoThermalFoam

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


74 Solver development

cavityClippedThermal: results

• In ParaView, load T field and set time to 2

• Apply a Slice filter to data oriented with Z Normal

• Apply a Contour filter to the slice, Contour by T, with 10 K spacing

Summary of further key classes

• IOdictionary class stores data file (dictionaries) on database, from which keywords can be looked up

• scalar, vector, tensor include associated algebra


see Scalar.H, TensorI.H

• GeometricField: actual class for p, U, phi, etc.

• fvMatrix class for finite volume matrix, e.g. UEqn

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


75

A Appendix - Post-processing
Sampling data along a line

• Sample utility was replaced by a function object but still for a reference we show the basic use here
• To run the following case return to the TJunction case run on the first day of the training
• The sample post-processing utility provides functionality from sampling library
• Can be used, for example, to plot graphs
• Easy to automate/configure with a sampleDict configuration file
• Examples can be found in the release
>> find $FOAM_TUTORIALS -name sampleDict

• Let’s copy one of those


>> cp $FOAM_TUTORIALS/electromagnetics/mhdFoam/hartmann/system/sampleDict system

Configuring the sample utility

• We will plot Ux along the centre of the horizontal pipe


• Change the sets entry in the sampleDict file
sets
(
pipe
{
type face; // samples at cell faces
axis x; // prints the x ordinate at each sample point
start ( 0 0 0.01 );
end ( 0.22 0 0.01 );
}
);

• Change the fields entry in the sampleDict file


fields ( U ); // sampling velocity field U

• Execute the sample utility


>> sample

• Results are written into sets directory

Quick plot using gnuplot

• Execute gnuplot and plot graph at t = 2


>> gnuplot
gnuplot> plot [0:0.22] [0:9] "postProcessing/sets/2/pipe_U.xy" with lines notitle

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


76 Appendix -Mapping one case to another

B Appendix -Mapping one case to another


Increasing mesh resolution

• One of the solution strategy user may want to apply is to initialise the case on the course grid and then
refine the grid

• The size of the volumetric fields must always correspond to the size of the mesh; The mesh refinement
must be followed by the field mapping onto a new mesh

• Following example shows how to run TJunction tutorial on a refined mesh

• Plan: to refine the T-Junction mesh and run to convergence

• Quicker to initialise using the coarse mesh solution

• Clone the TJunction case to make TJunctionFine


>> run
>> mkdir TJunctionFine
>> cp -r TJunction/system TJunctionFine
>> cp -r TJunction/constant TJunctionFine
>> cd TJunctionFine

• Refine mesh 2×2×2, overwriting existing mesh

• Could modify blockMeshDict and re-run blockMesh

• Running refineMesh utility more convenient


>> refineMesh -overwrite

Field mapping

• Fields can be mapped from one mesh to another with mapFields utility

• Mapping between conforming geometries/fields done with -consistent option

• Otherwise, mapping on patches specified in mapFieldsDict file

Source field geometry


Target field geometry
Region of no mapping

Coincident patches:
can be mapped using patchMap

Internal target patches:


can be mapped using cuttingPatches

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


77

T-Junction field mapping, set up case and run

• Map consistent fields from TJunction case at t = 2


>> mapFields ../TJunction -sourceTime 2 -consistent

• Fields are written into 0 directory

• In 0/p, uniformTotalPressure BC on inlet must be changed to uniformTotalPressure with the


constant keyword

• Alternatively the time directory 0 holding the mapped fields from old-mesh at time 2 seconds must be
renamed to time directory 2 to continue with the computation following the ramp function. Note the
time value used by solver is taken from the time directory name.

• In system/controlDict, change endTime to 0.4


26 endTime 0.4;

• Run the case using foamJob script to output to a log file


> foamJob pimpleFoam
Application : pimpleFoam
Executing: $FOAM_APPBIN/pimpleFoam > log 2>&1 &

Results from fine mesh

t=0 t = 0.4

• Load the TJunctionFine case in ParaView

• Apply a Slice filter to data

• Orientate the slice Z Normal

• Display by U (cell value - cube icon)

• Compare results at t = 0 and 0.4

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


78 Appendix -Mapping one case to another

B.1 Appendix -Mesh manipulation: T-Junction with fan


T-Junction with fan

y
∅12
x

100 4

• Tutorial TJunctionFan shows how to create a baffle on a structured grid and devide it into two parts:
– Blockage
– Internal pressure jump modelling fan in the channel
• Fan introduced in horizontal pipe at x = 100
• Fan performance specified by ∆p = p0 + a1 |U|, where p0 = 100, a1 = 0
• Go to the run directory, copy the TJunctionFan directory and go into it
>> run
>> cp -r $FOAM_TUTORIALS/incompressible/pimpleFoam/TJunctionFan .
>> cd TJunctionFan

• Generate the TJunction mesh using blockMesh


>> blockMesh

Modelling the fan and housing

wall wall
baffle
fan

cyclic cyclic

• The fan can be approximated by a cyclic (periodic) BC


• A cyclic condition forms a connection between 2 patches; here, fan inlet and outlet patches
• Pressure drop across the fan modelled using a derived fan BC
• The housing can be modelled as baffles using a wall BC

Creating baffles in a mesh

faceSet faceZone boundary


Geometry List of faces Oriented faces New patches

topoSet topoSet createBaffles

fan_half0 fan_half1

• Step 1: identify mesh faces that become baffle and fan, using topoSet

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


B.1 Appendix -Mesh manipulation: T-Junction with fan 79

• Step 2: create baffle and fan patches , using createBaffles

• topoSet allows us to create various geometry subsets, e.g.

• faceSet, cellSet, pointSet: lists of faces, cells, points

• faceZone: faceSet with orientation, i.e. which direction the faces “point”

• createBaffles creates patches from a faceZone

Creating faceZones with topoSet

• topoSet is configured by a set of actions in topoSetDict file

• Here we create faceSets, from which faceZones are created

• The fan consists of 2 patches, with the 1st facing upwind


• The faceZone for the fan requires the first set of faces to upwind

• We specify the upwind direction by defining some cells — a cellSet — upwind of the fan faces

• First the cyclic internal faces are collected into a zone and then the baffle set is created

topoSetDict file
18 actions
19 (
20 {
21 name cyclicFacesFaceSet; // faces for the fan
22 type faceSet;
23 action new;
24 source boxToFace; // specified by bounding box
25 sourceInfo
26 {
27 box (0.099 -0.006 0.004)(0.101 0.006 0.016);
28 }
29 }
30
31 {
32 name cyclicFacesSlaveCells; // defines upwind direction
33 type cellSet;
34 ...
35 }
36
37 {
38 name cyclicFaces; // faceZone to create fan patches
39 type faceZoneSet;
40 action new;
41 source setsToFaceZone; // method to turn set to zone
42 sourceInfo
43 {
44 faceSet cyclicFacesFaceSet;
45 cellSet cyclicFacesSlaveCells;
46 }
47 }
48 ...

topoSetDict file (cont.)


49 {
50 name baffleFaceSet;
51 type faceSet;
52 action new;
53 source boxToFace;
54 sourceInfo
55 {
56 box (0.099 -10 -10)(0.101 10 10);
57 }
58 }
59
60 {
61 name baffleFaceSet;
62 type faceSet;
63 action delete;
64 source boxToFace;
65 sourceInfo
66 {
67 box (0.099 -0.006 0.004)(0.101 0.006 0.016);
68 }

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


80 Appendix -Mapping one case to another

69 }
70
71 {
72 name baffleFaces;
73 type faceZoneSet;
74 action new;
75 source setToFaceZone;
76 sourceInfo
77 {
78 faceSet baffleFaceSet;
79 }
80 }
81 );

Generating the mesh with fan and baffles

• Run topoSet
>> topoSet

• topoSet collects the internal faces into sets. These sets need to be turned into internal “boundary”
conditions (baffles and cyclic) with utility createBaffles
• Utility createBaffles operates on faceZones based on the description in $FOAM_CASE/system/createBafflesDic

createBafflesDict
20 internalFacesOnly true;
21
22 baffles // Baffles to create.
23 {
24 baffleFaces
25 {
26 type faceZone;
27 zoneName baffleFaces; //previously defined zone
28
29 patchPairs
30 {
31 type wall;
32
33 patchFields
34 {
35 epsilon
36 {
37 type epsilonWallFunction;
38 value uniform 0;
39 }
40 k
41 {
42 type kqRWallFunction;
43 value uniform 0;
44 }
45 nut
46 {
47 type nutkWallFunction;
48 value uniform 0;
49 }
50 nuTilda
51 {
52 type zeroGradient;
53 }
54 p
55 {
56 type zeroGradient;
57 }
58 U
59 {
60 type fixedValue;
61 value uniform (0 0 0);
62 }
63 }
64 }
65 }

createBafflesDict cont.
76 cyclicFaces
77 {
78 //- Select faces and orientation through a searchableSurface
79 type searchableSurface;
80 surface searchablePlate;
81 origin (0.099 -0.006 0.004);
82 span (0 0.012 0.012);
83
84 patchPairs
85 {
86 type cyclic;
87
88 //- Optional override of added patchfields. If not specified
89 // any added patchfields are of type calculated.
90 patchFields
91 {
92 p
93 {
94 type fan;
95 patchType cyclic;
96 jump uniform 0;
97 value uniform 0;
98 jumpTable polynomial 1((100 0));
99 }

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


B.1 Appendix -Mesh manipulation: T-Junction with fan 81

100 }
101 }
102 }
103 }

Running the case with fan and baffles

• Run the case


>> pimpleFoam > log &

• Post-process with ParaView

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


82 Appendix - Finite volume discretisation

C Appendix - Finite volume discretisation


The finite volume method
The finite volume (FV) method is one form of equation discretisation. In general:
• Discrete quantities Qi are primarily stored at the centroids (C) of each cell i
• Terms in a PDE are discretised by integrating over the cell volume V
• Integrals over V of spatial derivatives are converted to integrals over the cell surface S using Gauss’s
Theorem
Z Z
∇ ⋆ Q dV = dS ⋆ Q (⋆ = • , ×, ⊗ )
V S

• Other integrals over V are approximated assuming Q is uniform across the cell
Z
Q dV = QP VP
V

• Integrals over S are approximated by summations over cell faces (f) of products of the normal area vector
Sf and Qf , interpolated from cell centres to faces
Z X
dS ⋆ Q = Sf ⋆ Qf
S f

Laplacian discretisation

• laplacian(Gamma, Q) ⇒ ∇ • (Γ∇Q)
Z Z X X
⇒ ∇ (Γ∇Q) dV =
• dS • (Γ∇Q) ≈ Γf Sf • (∇Q)f = Γf |Sf |nf • (∇Q)f
V S f f

• Surface normal gradient snGrad()

nf • (∇Q)f = C∆ d • (∇Q)f + k • (∇Q)f


| {z } | {z }
orthogonal non−orthogonal

= C∆ (QN − QP ) + k • (∇Q)f

f C∆ = 1/|nf • d| (= 1/∆x)
k = nf − C ∆ d
C∆ d

nf d
k
N

Laplacian discretisation (2)

• fvm::laplacian(Gamma, Q)

X
∇ • (Γ∇Q) ⇒ (Γf |Sf |C∆ (QN − QP ) + Γf |Sf |k • (∇Q)f )
f

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


83

• Contribution to matrix and source from face spanning cells 1 and 2, (positive k for owner cell P= 1):
    
−Γf |Sf |C∆ +Γf |Sf |C∆ . . . M1N Q1 −Γf |Sf |k • (∇Q)f
 +Γf |Sf |C∆ −Γf |Sf |C∆ . . . M2N  Q2   +Γf |Sf |k • (∇Q) 
    f 
 .. .. .. ..  .. = .. 
 . . . .  .   . 
MN 1 MN 2 ... MN N QN BN

Gradient and divergence discretisation

• fvc::div(Q) ⇒ ∇ • Q
Z Z X
⇒ ∇ • Q dV = dS • Q ≈ Sf • Qf
V S f

• Qf usually evaluated by linear interpolation

• Must be fvc:: - decreases rank by one (e.g. Q = vector, ∇ • Q = scalar)

• fvc::grad(Q) ⇒ ∇Q
Z Z X
⇒ ∇Q dV = dS Q ≈ Sf Qf
V S f

• Qf usually evaluated by linear interpolation

• Must be fvc:: - increases rank by one (e.g. Q = vector, ∇ • Q = 2nd rank tensor)

• fvc::laplacian(Q) 6= fvc::div(fvc::grad(Q))

Convection - a special case of divergence

• div(phi, Q) ⇒ ∇ • (UQ)
Z Z X X
⇒ ∇ • (UQ) dV = dS • (UQ) ≈ S f • Uf Q f = φ f Qf
V S f f

• Typically implicit in Q: fvm::div(phi, Q), where


phi = (fvc::interpolate(U) & mesh.Sf())

• Interpolation of Q → Qf is critical for stability

– upwind: bounded, 1st-order accurate


(
QP for φf ≥ 0
Qf =
QN for φf < 0

– linear: unbounded, 2nd-order accurate


– Other schemes, e.g. SFCD, limitedLinear, vanLeer, etc., effectively blend between upwind and
linear

Time derivative discretisation

• ddt(rho, Q)

Z
∂(ρQ) ∂(ρQ) ρP QP V − ρoP QoP V o
⇒ dV ≈
∂t V ∂t ∆t

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


84 Appendix - Finite volume discretisation

• Contribution to matrix and source from current time (no superscript) and old time (o superscript) at
P= 1:
   
ρP V /∆t . . . . . . M1N 
Q1
 ρoP QoP V o /∆t
 .. .. 
Q2
 .. 
 . . . . . M2N 



  . 

.. .. ..
  ..  = 
..

 ..   .   
 . . . .   . 
MN 1 MN 2 . . . MN N QN BN

• fvm::ddt(rho, Q) The usual choice — time derivatives almost always implicit

• Euler scheme shown above, first order in time

• Other second-order schemes available including backward differencing and CrankNicolson

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


85

D Appendix - Dynamic code in OpenFOAM


Dynamic Code in OpenFOAM

• Easy way how to extend functionality of OpenFOAM

• Code is defined in your case setup files

• Code gets compiled at the solver start in the case directory

• More complicated snippets are introduced with a #codeStream directive

• Small (typically arithmetic) code snippets are introduced by #calc preprocessing directive

• Boundary conditions can be developed with a codedFixedValue


and codedMixed

• fvOptions source terms can be defined by type codedSource

• function object #coded

Security issue: codeStreams are allowed by default. To turn the functionality off, add to system controlDict:
1 InfoSwitches
2 {
3 // Disallow case-supplied c++ code (#codeStream, codedFixedValue)
4 allowSystemOperations 0;
5 }

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


86 Appendix - Dynamic code in OpenFOAM

Implementation - #codeStream

• Compiler is called when the code snippet directive is found in the dictionary e.g. controlDict:
17 startTime 0;
18 endTime 100;
19 ..
20 writeInterval #codeStream
21 {
22 code
23 #{
24 scalar start = readScalar(dict["startTime"]);
25 scalar end = readScalar(dict["endTime"]);
26 label nDumps = 5;
27 os << ((end-start)/nDumps);
28 #};
29 };

• The #codeStream entry reads the dictionary following it, extracts the code, codeInclude, codeOptions,
codeLibs sections and calculates the SHA1 checksum of the contents.

• Code is copied into the appropriate template into the


$FOAM/etc/codeTemplates/dynamicCode/codeStreamTemplate.C

• Library source files are written to dynamicCode/<SHA1> and compiled using wmake libso

• The resulting library is generated under


dynamicCode/platforms/$WM_OPTIONS/lib
and is loaded (dlopen, dlsym) and the function executed.

Preprocessing directive #calc

• Basically a shorthand for #codeStream

• Returns string containing single C++ expression whose return value is included back to dictionary e.g.
to specify the turbulence properties at the inlet boundary condition, we may use:
17 magUinlet 1;
18 turbIntensity 0.1;
19 inletDiameter 0.1;
20 lengthScale #calc "0.07 * $inletDiameter"
21
22 tkeInlet #calc "1.5*sqr($magUinlet * $turbIntensity)"
23 omegaInlet #calc "sqrt($tkeInlet)/(pow(0.09,0.25)*$lengthScale)"

• . . . and include these into separate file initialConditons


• File with the settings is then introduced to a variable files k and omega with #include
"initialConditions" pre-processing directive (see motorBike tutorial for more details)

• Compilation is done at the beginning of the solver run in the same way like with #codeStream

Boundary condition codedFixedValue

• This BC type is using the same framework as codeStream to specify fixedValueFvPatchField

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


87

• To describe a smooth ramp boundary condition:


17 outlet
18 {
19 type codedFixedValue;
20 value uniform 0;
21 name ramp;
22
23 code
24 #{
25 operator==(min(10, 0.1*this->db().time().value()));
26 #};
27 }

• To be able to use runTimeModifiable feature (code will be read and compiled again at the next iteration),
indirect method must be used. The entry within the code directive must be read from system/codeDict:
1 ramp
2 {
3 code
4 #{
5 operator==(min(10, 0.1*this->db().time().value()));
6 #};
7 }

• Library fvCFD.H and finiteVolume is automatically included

• Other libraries need to be added using the codeInclude, codeLibs, codeOptions sections or provided
with the libs in the system/controlDict:
17 libs
18 (
19 "libmyFavouriteLibrary.so"
20 "libOpenFOAM.so"
21 );

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


88 Appendix - Dynamic code in OpenFOAM

Example: swirl velocity inlet

• Tutorial in $FOAM_TUTORIALS/incompressible/simpleFoam/pipeCyclic
• Introduce swirl to the inlet velocity in 0.org/U:
17 inlet
18 {
19 type codedFixedValue;
20 name swirl;
21
22 code
23 #{
24 const vector axis(1, 0, 0);
25
26 vectorField v(2.0*this->patch().Cf() ^ axis);
27 v.replace(vector::X, 1.0);
28 operator==(v);
29 #};
30 value $internalField;
31 }

• Velocity rotates along x axis

• Axial component is fixed

Example: smoothly ramped fixed value BC

• Exercise: create a BC that smoothly ramps field φ from 0 to φ0 over time τ

φ0
Function φ

0
0 τ
Time t
1
φ = φ0 µ ¶
t
1 + exp −S +6
τ

• . . . using codedFixedValue
• Setting values for:
– τ = 0.4 as scalar rampTime(0.4)
– S as scalar Steepness(12)
– φ0 as vector refValue(1,0,0)
• Using the same framework as codeStream to specify
fixedValueFvPatchField

• To describe a smooth ramp boundary condition:


17 movingWall
18 {
19 type codedFixedValue;
20 value uniform (0 0 0);
21 name rampedFixedValue; // name of generated BC
22 code
23 #{

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


89

24 scalar t = this->db().time().value();
25 scalar rampTime(0.4);
26 scalar steepness(12);
27 vector refValue(1,0,0);
28 vector result(refValue);
29 if (t < rampTime)
30 {
31 result =
32 refValue/(1.0 + exp(-steepness*t/rampTime + 6.0));
33 }
34 else
35 {
36 result = refValue;
37 }
38 operator==(result);
39 #}; // end of code
40 } // end of BC definition

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


90 Appendix - Dynamic code in OpenFOAM

Boundary condition codedMixed 1/3


General Mixed Boundary condition functionality:
• Combines fixedValue and fixedGradient boundary conditions
with a valueFraction
• valueFraction= 1 corresponds to fixedValue
• valueFraction= 0 corresponds to fixedGradient
• We need to provide 3 fields:
– refValue to specify value for case of fixedValue type
– refGrad to specify value for case of fixedGradient type
– valueFraction – w to switch behaviour

µ ¶
∇⊥ x
xp = wxp + (1 − w) xc + ,

where xp are patch values, xc internal field values and ∆ inverse distance from face centre to internal cell
centre

For more details see the source code:


$FOAM_SRC/finiteVolume/fields/fvPatchFields/basic/mixed

Boundary condition codedMixed 2/3


Typical examples of mixed boundary conditions are:
• inletOutlet and outletInlet
• externalCoupledMixed
• freestream
• pressureInletOutletParSlipVelocity
• variableHeightFlowRate
• advective
• . . . and others

To get a list of mixed BCs simply grep for a “mixed” keyword in


$FOAM_SRC/finiteVolume/fields/fvPatchFields/derived

Boundary condition codedMixed 3/3


Excercise: Create Boundary condition for y < 0 of type wall (fixdedValue) and for y > 0 of type inletOutlet
17 partialOutlet
18 {
19 type codedMixed;
20
21 refValue uniform (0 0 0);
22 refGradient uniform (0 0 0);
23 valueFraction uniform 1;
24 redirectType splitInletOutlet; // name of generated bc
25
26 code
27 #{
28
29 // get y compontent of patch face centres
30 const scalarField topMask(pos(this->patch().Cf().component(vector::Y)));
31
32 // reading flux
33 const Field<scalar>& phip =

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


91

34 this->patch().lookupPatchField<surfaceScalarField,scalar>("phi");
35
36 // Set valueFraction to be 1 in bottom and at top if inflow.
37 this->valueFraction() =
38 topMask*(1.0 - pos(phip)) + (1.0-topMask)*1.0;
39 #};
40 }

FunctionObject coded

• Class functionObject is used for on-the-fly postprocessing

• To find full list, go to http://www.openfoam.com -> C++ Documentation. In Doxygen follow Post-
processing in section Using the code.

• Coded functionObject is a type allowing user defined function to post-process or manipulate the data

The framework consists of the following entries

• codeInclude: include section for all your .H files

• codeOptions: include path inserted into EXE_INC in Make/options

• codeLibs: include link into the LIB_LIBS in Make/options

• codeExecute: C++ code executed at runtime (calling execute function)

• codeRead: C++ code executed at reading the dictionary

• codeWrite: C++ code executed at writting


• . . . other sections can be found in:
$FOAM_SRC/postProcessing/functionObjects/utilities/
codedFunctionObject/codedFunctionObject.H

Simple Example: Calculate the average pressure in the domain and print it to Info stream:
1 functions
2 {
3 type coded;
4 functionObjectLibs ("libutilityFunctionObjects.so");
5 name Paverage;
6 outputControl timeStep;
7 outputInterval 2;
8 codeExecute
9 #{
10 const volScalarField& p = mesh().lookupObject<volScalarField>("p");
11 const scalar& t = mesh().time().value();
12 Info<<"averagP " << t <<" " << gAverage(p) << endl;
13 #};
14 }

After starting the solver

• The directory dynamicCode in your case directory is created

• Directory with the name name is created

• Template files functionObjectTemplate.H(.C) and


FilterFunctionObjectTemplate.H(.C) are copied
from $FOAM_ETC/etc/codeTemplates/dynamicCode/

• User input is included into the files

• Files with directives for compiler Make/files and Make/options are created

• Code is compiled
Using dynamicCode for functionObject pAverage at line 5 in
"...pathToTheRunDir/oriffice/steady/system/controlDict.functions.pAverage"

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM


92 Appendix - Dynamic code in OpenFOAM

Example 2: Vorticity calculation


1 functions
2 {
3 curl
4 {
5 // Load the library containing the 'coded' functionObject
6 functionObjectLibs ("libutilityFunctionObjects.so");
7 type coded;
8 // Name of on-the-fly generated functionObject
9 name curl;
10 codeExecute
11 #{
12 if (mesh().time().outputTime())
13 {
14 // Lookup U
15 Info<< "Looking up field U\n" << endl;
16 const volVectorField& U =
17 mesh().lookupObject<volVectorField>("U");
18
19 Info<< " Calculating vorticity" << endl;
20
21 // Create the vorticity field
22 volVectorField vorticity
23 (
24 IOobject
25 (
26 "vorticity",
27 mesh().time().timeName(),
28 mesh(),
29 IOobject::NO_READ
30 ),
31 fvc::curl(U)
32 );
33
34 // Create the vorticity magnitude field
35 volScalarField magVorticity
36 (
37 IOobject
38 (
39 "magVorticity",
40 mesh().time().timeName(),
41 mesh(),
42 IOobject::NO_READ
43 ),
44 mag(vorticity)
45 );
46
47 // Write data to the screen
48 Info<< "vorticity max/min : "
49 << max(magVorticity).value() << " "
50 << min(magVorticity).value() << endl;
51
52 // Write values to result files
53 vorticity.write();
54 magVorticity.write();
55 }
56 #};
57 }
58 }

©2008-2019 OpenCFD Ltd. Copy for Vinay Chandra Sriramula Open∇FOAM

Вам также может понравиться