Академический Документы
Профессиональный Документы
Культура Документы
Foundation Training
OpenCFD Ltd
Notes to workshop
1
2
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.
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
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
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 );
Capabilities
utilities solvers
e.g. blockMesh e.g. simpleFoam
post-processing modelling
e.g. sampling, ... e.g. turbulence, thermo, ...
libOpenFOAM.so
Libraries src dir.
solvers (solver applications) simulate problems in CFD and other engineering mechanics
utilities perform data manipulations, visualisation, mesh processing, etc.
Quality assurance is done by means of consistent development process and thorough testing
OpenFOAM history
OpenFOAM releases
• OpenFOAM (Open source Field Operation And Manipulation) is free open source code released under
the GPL license
• Produced by OpenCFD
• 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
Operation
• 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
Ux = 10.0
50.8 p=0
• No-slip walls (U = 0)
• Open a terminal window by clicking the icon, left of top menu bar
Post-processing a mesh
• Run paraFoam:
>> paraFoam
• General panel:
• Lights panel:
Headlight Set to on, strength 1, white
• Annotation panel:
Orientation Axes Set to on, Interactive, Axes Label Color black
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
– Color by →
– Surface representation.
• 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
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
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
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
• 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.
36 type zeroGradient;
37 }
38
39 lowerWall ... (ditto) ...
40
41 frontAndBack
42 {
43 type empty;
44 }
45 }
• outlet is fixedValue which requires a value; can be anything (pressure is relative), use 0 for convenience
• No-slip walls:
– a fixedValue type
– requires a value
• outlet is zeroGradient
• Powers of: mass, length (L), time (T), temperature, quantity, current, luminosity
• Unit system, e.g. SI, only appears in values of physical constants, e.g. R, pstd
• 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
• User must specify numerical BCs on fields, rather than a physical description. . .
• 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
• 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 }
• In compressible simulations viscosity and other physical parameters are set in different files, mainly in
constant/thermophysicalProperties
1 Mesh processing
Introduction to meshing in OpenFOAM
• automatic meshers
60 mm
y
40 mm
x
60 mm 40 mm
• Laminar
• Lid: U = (1, 0, 0)
• No-slip walls (U = 0)
• 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
13 14 15
1 2
2 3 4
10 11 12
y 0
x 1
0
z
8 9
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 );
• (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
• A data entry can be a string ("hello"), word (hello), integer (3) scalar (3.14), . . .
• . . . a dictionary: curly brackets {...}
{
... keyword entries ...
}
Sf
P
d N
• Face-based description
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;
Internal faces
Patch 0
Patch 1
Boundary faces
startFace
Patch 2
nFaces
Using applications
• By default, they work by: (1) running blockMesh; (2) running the solver
• 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
• Execute fluentMeshToFoam
>> fluentMeshToFoam elbow.msh
Matrix bandwidth
Cell renumbering
• 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
• Co > 1 means the flow can pass through a cell within one time step
OpenFOAM workflow
• Change the mesh, BC, initial conditions, adjust discretisation, employ the function objects of your choice
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.
...
Types of solver
• 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
y
20
x
p = 10→40 Pa
200
200
Dimensions in mm
p = 0 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
• Aim of the tutorial is to show advanced boundary conditions and fields mapping on different mesh
• View the log file in the terminal window with tail command
>> tail -f log
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
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
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 ...
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)
35 }
36
37 outlet2 ... (ditto) ...
38
39 defaultFaces
40 {
41 type kqRWallFunction;
42 value uniform 0;
43 }
44 }
• Boundary conditions are applied to the boundary patches (specified in the $FOAM_CASE/constant/polyMesh/bound
file)
– 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"
2.4 Post-processing
T-Junction: post-processing
• 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 ...
Gnuplot post-processing
• Alternatively:
14
p2
p2
12 p4*100
10
0
0 0.2 0.4 0.6 0.8 1 1.2 1.4 1.6
• 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
• 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
• Typical in OpenFOAM, the .orig file acts as a backup for the file used by the solver alpha.water
• transportProperties contains a list of phases and transport property subditionaries for each phase.
Discretisation schemes
• Discretisation schemes must be set to all terms for each variable we solve differential equation for
• 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.
• OpenFOAM’s interface tracking solvers use OpenCFD’s multidimensional universal limiter for explicit
solution (MULES) method
• ⇒ choice of convection scheme not restricted to those that are strongly stable or bounded, e.g. upwind
differencing
• Geometry and associated fields are broken into pieces and allocated to separate processors
Domain decomposition
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
• Running on a cluster, a user wishes to run from machine aaa on the following machines: aaa; bbb, which
has 2 processors; and ccc
• reconstructPar utility: reassembles decomposed fields and mesh from processor<n> directories into
normal time directories
• . . . in Paraview in Properties window, user must select Decomposed in Case type list to see the whole
domain
Results
Creating an animation
• The case can be animated in ParaView by clicking Play in the animation toolbars
– 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
• 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
• 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
Function objects
– 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
• 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)"
Dynamic code
• Code is compiled and linked to executable at the start of utility or solver execution
• 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
4 Programming background
4.1 C++ overview
OpenFOAM Programming: language in general
– 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
– Symbols can express further concepts, e.g. the field of velocity magnitude by |U|
∂ρU
+ ∇ • ρUU + ∇ • ρR = − ∇p
| ∂t
{z } | {z } | {z } |{z}
1 2 3 4
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
Class hierarchy
Classes Functions
List<Type> 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";
Compiled Compiled
Test-vector Linked OpenFOAM.so
Executable -l option Library
• Public functions (and data) accessible from outside of the class, including
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
• 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
• 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
• Uses a common UNIX scripting syntax of a backslash (\) to continue across lines
• 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)
wmake: compiling
• To compile, change to the directory tree containing the Make folder and type
>> wmake
• Sometimes after making code changes, or before packing a solver to send elsewhere, .dep files need
removing
• The wrmdep script also removes .dep files recursively down a directory tree
• Utilities and basic solvers provide the easiest introduction to OpenFOAM programming because
• 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
• 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
• 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
• 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
fvSchemes
fvMesh mesh mesh2
fvSolution
• 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
Info statements
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 );
Access functions
• Can be built from sources using doxygen (may require root permission; ensure OpenFOAM env variables
are set)
>> cd $WM_PROJECT_DIR/doc/Doxygen
>> doxygen
• 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.
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
5 Solver development
5.1 Modifying a solver
Solver source code
• The icoFoam.C file begins with #include files discussed previously until. . .
76 # include "createFields.H"
• 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 );
Dictionary lookup
1. Creating an IOdictionary
2. Looking up entries with the .lookup("keyword") function
• 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();
$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 );
Meshes
Sf
P
d N
Tensor fields
Field algebra
• There are more operators, like transcendental scalar functions, sin, exp etc.
Field interpolation
|nf • dfN |
Qf = wf QP + (1 − wf )QN , wf =
|nf • d|
dfN
nf d
N
volVectorField fvMesh
z}|{ z }| {
linearInterpolate( U ) & mesh .Sf()
| {z } |{z} | {z }
surfaceVectorField •
surfaceVectorField
• 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));
Discretisation
– [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
• OpenFOAM has functions for derivatives, e.g. div, grad, laplacian, curl
• To discretise a term into matrix equation you wish to solve, prefix with fvm::
• ⇒ There are only 4 terms that can form matrix coefficients, i.e. can “be” fvm::
• Convective derivative: fvm::div function with surfaceScalarField flux (phi) as the 1st argument
• Equation (explicit) source terms can be calculated using the following functions
• 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 );
• Manipulation of [U Eqn]]
"+ ◦ ◦ #" # " #
+ ◦ ◦
◦ ◦
◦
+
+ ◦
U = B
◦ ◦ +
"+ #" # " # " ◦ ◦
#" #
+ ◦◦
+ U = B − ◦◦ U
+ ◦ ◦
+ ◦ ◦
| {z } | {z }
A H(U)
AU = − ∇p + H
Equations in PISO
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
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
PIMPLE algorithm
• Can run pseudo-transient: big time steps to reach steady-state with minimal under-relaxation
∂T
+ ∇ • (UT ) − ∇ • DT ∇T = 0
∂t
• ⇒ 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 );
• Run icoThermalFoam
>> icoThermalFoam
cavityClippedThermal: results
• IOdictionary class stores data file (dictionaries) on database, from which keywords can be looked up
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
• 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
Field mapping
• Fields can be mapped from one mesh to another with mapFields utility
Coincident patches:
can be mapped using patchMap
• 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.
t=0 t = 0.4
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
wall wall
baffle
fan
cyclic cyclic
fan_half0 fan_half1
• Step 1: identify mesh faces that become baffle and fan, using topoSet
• faceZone: faceSet with orientation, i.e. which direction the faces “point”
• 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 ...
69 }
70
71 {
72 name baffleFaces;
73 type faceZoneSet;
74 action new;
75 source setToFaceZone;
76 sourceInfo
77 {
78 faceSet baffleFaceSet;
79 }
80 }
81 );
• 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 }
100 }
101 }
102 }
103 }
• 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
= C∆ (QN − QP ) + k • (∇Q)f
f C∆ = 1/|nf • d| (= 1/∆x)
k = nf − C ∆ d
C∆ d
nf d
k
N
• fvm::laplacian(Gamma, Q)
X
∇ • (Γ∇Q) ⇒ (Γf |Sf |C∆ (QN − QP ) + Γf |Sf |k • (∇Q)f )
f
• 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
• fvc::div(Q) ⇒ ∇ • Q
Z Z X
⇒ ∇ • Q dV = dS • Q ≈ Sf • Qf
V S f
• fvc::grad(Q) ⇒ ∇Q
Z Z X
⇒ ∇Q dV = dS Q ≈ Sf Qf
V S f
• Must be fvc:: - increases rank by one (e.g. Q = vector, ∇ • Q = 2nd rank tensor)
• fvc::laplacian(Q) 6= fvc::div(fvc::grad(Q))
• div(phi, Q) ⇒ ∇ • (UQ)
Z Z X X
⇒ ∇ • (UQ) dV = dS • (UQ) ≈ S f • Uf Q f = φ f Qf
V S f f
• ddt(rho, Q)
Z
∂(ρQ) ∂(ρQ) ρP QP V − ρoP QoP V o
⇒ dV ≈
∂t V ∂t ∆t
• 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
• Small (typically arithmetic) code snippets are introduced by #calc preprocessing directive
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 }
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.
• Library source files are written to dynamicCode/<SHA1> and compiled using wmake libso
• 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)"
• Compilation is done at the beginning of the solver run in the same way like with #codeStream
• 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 }
• 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 );
• 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 }
φ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
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
µ ¶
∇⊥ 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
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
• 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
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 }
• 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"