Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
219 views

Openfoamtut 1

Uploaded by

Warstilide49
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
219 views

Openfoamtut 1

Uploaded by

Warstilide49
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1002

OpenFOAM® Introductory Training

Online session – 2020 Edition


This work is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0)

To view a copy of this license, visit


http://creativecommons.org/licenses/by-sa/4.0/

• A help is needed, and much appreciated.


• If you find errors, have suggestions for better wording, figures, or new material, let us know.
• Also, if you find a tutorial that does not work, please let us know.
• Follow-up problems, questions, and suggestions at guerrero@wolfdynamics.com
Disclaimer

This offering is not approved or endorsed by OpenCFD Limited, the


producer of the OpenFOAM software and owner of the OPENFOAM® and
OpenCFD® trademarks.

Wolf Dynamics makes no warranty, express or implied, about the


completeness, accuracy, reliability, suitability, or usefulness of the
information disclosed in this training material. This training material is
intended to provide general information only. Any reliance the final user
place on this training material is therefore strictly at his/her own risk. Under
no circumstances and under no legal theory shall Wolf Dynamics be liable
for any loss, damage or injury, arising directly or indirectly from the use or
misuse of the information contained in this training material.

Revision 1-2020
JG
Acknowledgements
This training material and tutorials are based upon personal experience, OpenFOAM® source
code, OpenFOAM® user guide, OpenFOAM® programmer’s guide, and presentations from
previous OpenFOAM® training sessions and OpenFOAM® workshops.

We gratefully acknowledge the following OpenFOAM® users for sharing online their material or for
giving us their consent to use their material:

• Henry Weller and Chris Greenshields. The OpenFOAM Foundation.


• Hrvoje Jasak and Henrik Rusche. Wikki Ltd.
• Eugene de Villiers, Paolo Geremia, and Dan Combest. Engys.
• Hakan Nilsson. Chalmers University of Technology.
• Eric Paterson. Pennsylvania State University.
• Gavin Tabor. University of Exeter.
• Fumiya Nozaki. Yokohama, Japan.
• Marwan Darwish. American University of Beirut.
• Kevin Maki. University of Michigan.
• Tobias Holzmann. HolzmannCFD.
Acknowledgements
The following people have contributed directly to the development of this training material:

• Edoardo Alinovi.
• Matteo Bargiacchi.
• Mattia Cavaiola.
• Peyman Davvalo Khongar.
• Sehrish Naqvi.
• Damiano Natali.
• Stefano Olivieri.
• Biniyam Sishah.
• Giuseppe Zampogna.
On the training material
The following typographical conventions are used in this
training material
• Text in Courier new font indicates Linux commands that should be typed literally by the user
in the terminal.
• Text in Courier new bold font indicates directories.
• Text in Courier new italic font indicates human readable files or ascii files.
• Text in Arial bold font indicates program elements such as variables, function names, classes,
statements and so on. It also indicate environment variables, and keywords. They also
highlight important information.
• Text in Arial underline in blue font indicates URLs and email addresses.
• This icon indicates a warning or a caution.
• This icon indicates a tip, suggestion, or a general note.
• This icon indicates a folder or directory.
• This icon indicates a human readable file (ascii file).
• This icon indicates that the figure is an animation (animated gif).
• These characters $> indicate that a Linux command should be typed literally by the user in the
terminal.
On the training material
The following typographical conventions are used in this
training material
• Large code listing, ascii files listing, and screen outputs can be written in
a square box, as follows:

1 #include <iostream>
2 using namespace std;
3
4 // main() is where program execution begins. It is the main function.
5 // Every program in c++ must have this main function declared
6
7 int main ()
8 {
9 cout << "Hello world"; //prints Hello world
10 return 0; //returns nothing
11 }

• To improve readability, the text might be colored.


• The font can be Courier new or Arial bold.
• And when required, the line number will be shown.
On the training material
Training material
• In the USB key you will find all the training material (tutorials, slides, quick reference guides, OpenFOAM®
user guide, OpenFOAM® programmers manual, and lectures notes).
• You can extract the training material wherever you want. However, we highly recommend to extract all the
training material in your OpenFOAM® user directory.
• From now on, we will refer to the directory where you extracted the training material as,
• $PTOFC
(abbreviation of Path To OpenFOAM® Course)

• To uncompress the tutorials go to the directory where you copied the training material and then type in the
terminal,
• $> tar –zxvf file_name.tar.gz

• In every single tutorial, you will find the file README.FIRST. In this file you will find the general instructions of
how to run the case. You will also find some additional comments.
• In some cases, you will also find additional files with the extension .sh. These files can be used to run the
case automatically, but we highly recommend to open the README.FIRST file and type the commands in the
terminal, in this way you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
• You will find the automatic scripts in the cases explained in the lectures notes and some random cases.
• A word of caution, use the tutorials included in the training material just for recreational, instructional,
or learning purposes and not for validation, benchmarking or as standard practices.
On the training material
Exercises
• At the end of each section, you will find an exercise section.
• The exercise section is optional, self-paced, and do it at anytime.
• The proposed exercises are designed to test your knowledge and to
reinforce the concepts addressed during the lectures.
• All the concepts to be addressed in the exercise sections have been treated
in the lecture notes, so the reader should not have problems answering the
questions.
• If you have doubts, do not hesitate in asking.
• To help you answering the exercises, we might give you a few tips.
• And if it is necessary, the solution will be given.
Housekeeping issues
• What OpenFOAM® version are we going to use?
• During this training we are going to use OpenFOAM® version 8.
• The one developed by OpenCFD Ltd (http://www.openfoam.org/).

• What Linux flavor should I use?


• We use OpenSUSE 15.1 or 15.2, but you are free to use any Linux flavor.

• What Linux shell should I use?


• During this training we are going to use the BASH shell. If you want to know what shell
you are using, type in the terminal
• $> echo $SHELL
• If the output is /bin/bash, you are using BASH shell.
• If your output is something else, you are not using BASH shell. In this case, to start using
BASH shell type in the terminal,
• $> bash
• If you do not know what is the terminal or how to use Linux, do not worry we are going to
give a quick introduction later.
Training agenda
Module 0. Module 5.
• Training agenda • Sampling and plotting
• On the training material • Data conversion
• Housekeeping issues
• Additional information Module 6.
• The finite volume method. A crash introduction
Module 1. • On the CFL number
• Introduction to OpenFOAM® • Boundary conditions and initial conditions
• A few OpenFOAM® simulations • Unsteady and steady simulations
• Library organization • Assessing convergence
• OpenFOAM® 101 – My first tutorial • Velocity pressure-coupling
• Linear solvers
Module 2.
Module 7.
• Solid modeling for CFD – Introduction to Onshape
• Implementing boundary conditions and initial conditions using
codeStream
Module 3.
• Meshing preliminaries Module 8.
• Mesh quality assessment • Advanced modeling capabilities:
• Meshing in OpenFOAM® – blockMesh and snappyHexMesh • Turbulence modeling
• Mesh conversion and manipulation • Multiphase flows
• Compressible flows
Module 4. • Moving reference frames and sliding grids
• Running in parallel • Moving bodies and rigid body motion
• Source terms and passive scalars
Training agenda
Week 1.
• Course presentation, introduction to OpenFOAM®, running my first simulations, running in parallel

Week 2.
• Solid modeling using Onshape, mesh generation, mesh quality assessment, qualitative and quantitative
postprocessing, scientific visualization

Week 3.
• Introduction to the finite volume method, numerical playground, best standard practices in CFD and
OpenFOAM®, implementing boundary conditions and initial conditions using codeStream

Week 4.
• Implementing boundary conditions and initial conditions using codeStream (continuation), advanced physical
models (turbulence, multiphase, compressible flows, dynamic meshes, source terms).

Week 5.
• Advanced physical models (continuation), extra topics (supplements), tips and tricks, closing remarks
Training agenda
Week 1.
• Module 0, Module 1, Module 4

Week 2.
• Module 2, Module 3, Module 5

Week 3.
• Module 6, Module 7

Week 4.
• Module 7, Module 8

Week 5.
• Module 8, extra topics
Training agenda

• The training agenda is organized in such a way that we will address the whole CFD simulation workflow.
Module 1
OpenFOAM® overview – First tutorial –
Working our way in OpenFOAM®

1
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

2
OpenFOAM® brief overview
General description:
• OpenFOAM® stands for Open Source Field Operation and Manipulation.
• OpenFOAM® is first and foremost a C++ library used to solve partial
differential equations (PDEs), and ordinary differential equations (ODEs).
• It comes with several ready-to-use or out-of-the-box solvers, pre-processing
utilities, and post-processing utilities.
• It is licensed under the GNU General Public License (GPL). That means it is
freely available and distributed with the source code.
• It can be used in massively parallel computers. No need to pay for separate
licenses.
• It is under active development.
• It counts with a wide-spread community around the world (industry,
academia and research labs).

3
OpenFOAM® brief overview
Multi-physics simulation capabilities:
• OpenFOAM® has extensive multi-physics simulation capabilities, among
others:
• Computational fluid dynamics (incompressible and compressible flows).
• Computational heat transfer and conjugate heat transfer.
• Combustion and chemical reactions.
• Multiphase flows and mass transfer.
• Particle methods (DEM, DSMC, MD) and lagrangian particles tracking.
• Stress analysis and fluid-structure interaction.
• Rotating frames of reference, arbitrary mesh interface, dynamic mesh
handling, and adaptive mesh refinement.
• 6 DOF solvers, ODE solvers, computational aero-acoustics,
computational electromagnetics, computational solid mechanics, MHD.

4
OpenFOAM® brief overview
Physical modeling library:
• OpenFOAM® comes with many physical models, among others:
• Extensive turbulence modeling capabilities (RANS, DES and LES).
• Transport/rheology models. Newtonian and non-Newtonian viscosity
models.
• Thermophysical models and physical properties for liquids and gases.
• Source terms models.
• Lagrangian particle models.
• Interphase momentum transfer models for multiphase flows.
• Combustion, flame speed, chemical reactions, porous media, radiation,
phase change.

5
OpenFOAM® brief overview
Under the hood you will find the following:
• Finite Volume Method (FVM) based solver.
• Collocated polyhedral unstructured meshes.
• Second order accuracy in space and time. Many discretization schemes
available (including high order methods).
• Steady and transient solvers available.
• Pressure-velocity coupling via segregated methods (SIMPLE and PISO).
• But coupled solvers are under active development.
• Massive parallelism through domain decomposition.
• It comes with its own mesh generation tools.
• It also comes with many mesh manipulation and conversion utilities.
• It comes with many post-processing utilities.
• All components implemented in library form for easy re-use.
6
OpenFOAM® brief overview
OpenFOAM® vs. Commercial CFD applications:
• OpenFOAM® capabilities mirror those of commercial CFD applications.
• The main differences with commercial CFD applications are:
• There is no native GUI.
• It does not come with predefined setups. The users need to have a basic
understanding of the CFD basics and be familiar with OpenFOAM® command
line interface (CLI).
• Knowing your way around the Linux bash shell is extremely useful.
• It is not a single executable. Depending of what you are looking for, you will
need to execute a specific application from the CLI.
• It is not well documented, but the source code is available.
• Access to complete source = no black magic. But to understand the source
code you need to know object-oriented programming and C++.
• Solvers can be tailored for a specific need, therefore OpenFOAM® is ideal for
research and development.
• It is free and has no limitation on the number of cores you can use.
7
OpenFOAM® brief overview
Developing new solvers (in case you need it):
• As the user has complete access to the source code, she/he has total
freedom to modify existing solvers or use them as the starting point for new
solvers.
• New solvers can be easily implemented using OpenFOAM® high level
programming, e.g.:

solve
(
fvm::ddt(T)
+ fvm::div(phi,T)
- fvm::laplacian(nu,T)
==
0
);

Correspondence between the implementation and the original equation is clear.

8
OpenFOAM® brief overview

OpenFOAM® is an excellent piece of C++


and software engineering. Decent piece of
CFD code.
H. Jasak

9
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

10
OpenFOAM® directory organization
$WM_PROJECT_DIR If you installed OpenFOAM® in the default location, the
├── Allwmake environment variable $WM_PROJECT_DIR should point
├── applications to the following directory (depending on the installed
version):
├── bin
├── COPYING
├── doc $HOME/OpenFOAM/OpenFOAM-8
├── etc or
├── platforms $HOME/OpenFOAM/OpenFOAM-dev
├── README.org
├── src In this directory you will find all the files containing
├── tutorials OpenFOAM® installation.
└── wmake
In this directory you will also find additional files (such as
README.org, COPYING, etc.), but the most important
one is Allwmake, which compiles OpenFOAM®.

11
OpenFOAM® directory organization
$WM_PROJECT_DIR OpenFOAM® environment variables
├── Allwmake
├── applications The entries starting with the symbol $ are environment
├── bin variables. You can find out the value of an environment
├── COPYING variable by echoing its value, for example:
├── doc $> echo $WM_PROJECT_DIR
├── etc
├── platforms
will print out the following information on the terminal,
├── README.org
$HOME/OpenFOAM/OpenFOAM-8
├── src
├── tutorials
└── wmake To list all the environment variables type in the terminal
window,
$> env

To list all the environment variables related to


OpenFOAM®, type in the terminal:
$> env | grep –i “OpenFOAM”
12
OpenFOAM® directory organization
$WM_PROJECT_DIR OpenFOAM® aliases
├── Allwmake
├── applications
You can go to any of these directories by using the
├── bin predefined aliases set by OpenFOAM® (refer to
├── COPYING $WM_PROJECT_DIR/etc/config.sh/aliases or
├── doc $WM_PROJECT_DIR/etc/config.csh/aliases).
├── etc Just to name a few of the aliases defined:
├── platforms alias foam=‘cd $WM_PROJECT_DIR’
├── README.org alias app=‘cd $FOAM_APP’
├── src alias src=‘cd $FOAM_SRC’
├── tutorials
alias tut=‘cd $FOAM_TUTORIALS’
└── wmake

For a complete list type alias in the terminal.

To list all the aliases related to OpenFOAM®, type in the


terminal:
$> alias | grep -i “FOAM”
13
OpenFOAM® directory organization
$WM_PROJECT_DIR
├── Allwmake Let us study each directory inside
├── applications
├── bin $WM_PROJECT_DIR
├── COPYING
├── doc
├── etc • Any modification you add to the source code in
├── platforms WM_PROJECT_DIR will affect the whole library.
├── README.org • Unless you know what are you doing, do not
├── src modify anything in the original installation
├── tutorials ($WM_PROJECT_DIR), except for updates!
└── wmake

14
OpenFOAM® directory organization
The applications directory
$WM_PROJECT_DIR/applications
├── Allwmake
├── solvers
├── test
└── utilities

Let us visit the applications directory. Type in the terminal app or


$> cd $WM_PROJECT_DIR/applications. You will find the following sub-directories:
• solvers, which contains the source code for the distributed solvers.
• test, which contains the source code of several test cases that show the usage of
some of the OpenFOAM® classes.
• utilities, which contains the source code for the distributed utilities.
There is also an Allwmake script, which will compile all the content of solvers and
utilities. To compile the test cases in test go to the desired test case directory and
compile it by typing wmake.

15
OpenFOAM® directory organization
The bin directory
$WM_PROJECT_DIR/bin/ Let us visit the bin directory:
├── foamCleanPolyMesh
• The bin directory contains many shell
├── foamCleanTutorials scripts, such as foamNew, foamLog,
├── foamCloneCase foamJob, foamNewApp, etc.
├── foamJob
├── foamLog • This directory also contains the script
paraFoam that will launch paraView.
├── foamMonitor
├── foamNew
├── foamNewApp
├── foamNewBC
├── foamNewFunctionObject
├── paraFoam
├── ...
└── tools

The directory tree is not complete


16
OpenFOAM® directory organization
The doc directory
$WM_PROJECT_DIR/doc/ Let us visit the doc directory:
├── Allwmake
• The doc directory contains the documentation
├── codingStyleGuide.org
of OpenFOAM®, namely; user guide,
├── Doxygen programmer’s guide and Doxygen generated
├── Guides documentation in html format.
└── tools
• The Doxygen documentation needs to be
compiled by typing Allwmake doc in
$WM_PROJECT_DIR.

• You can access the Doxygen documentation


online, http://cpp.openfoam.org/v8

17
OpenFOAM® directory organization
The etc directory
$WM_PROJECT_DIR/etc/ Let us visit the etc directory:
├── bashrc
• The etc directory contains the environment
├── caseDicts
files, global OpenFOAM® instructions,
├── cellModels templates, and the default thermochemical
├── codeTemplates database thermoData/thermoData
├── config.csh
• In the directory caseDicts, you will find many
├── config.sh
templates related to the input files used to setup
├── controlDict a case in OpenFOAM®. We recommend you
├── cshrc take some time and explore these files.
├── paraFoam
├── README.org • It also contains the super dictionary
controlDict, where you can set several
├── templates debug flags and the defaults units.
└── thermoData

18
OpenFOAM® directory organization
The platforms directory
$WM_PROJECT_DIR/platforms/
├── linux64GccDPInt32Opt
│ ├── applications
│ ├── bin
│ ├── lib
│ └── src
└── linux64GccDPInt32OptSYSTEMOPENMPI
└── src

Let us visit the platforms directory.


• This directory contains the binaries generated when compiling the applications
directory and the libraries generated by compiling the source code in the src directory.
• After compilation, the binaries will be located in the directory
$WM_PROJECT_DIR/platforms/linux64GccDPInt32OptSYSTEMOPENMPI/bin
$WM_PROJECT_DIR/platforms/linux64GccDPOpt/lib).
• After compilation, the libraries will be located in the directory
$WM_PROJECT_DIR/platforms/linux64GccDPInt32OptSYSTEMOPENMPI/lib
19
OpenFOAM® directory organization
The src directory
$WM_PROJECT_DIR/src Let us visit the src directory. Type in the terminal
├── Allwmake src or $> cd $WM_PROJECT_DIR/src
├── combustionModels
├── finiteVolume • This directory contains the source code for all
├── fvOptions the foundation libraries, this is the core of
├── lagrangian OpenFOAM®.
├── ... • It is divided in different subdirectories and each
├── OpenFOAM of them can contain several libraries.
├── parallel
├── MomentumTransportModels A few interesting directories are:
├── sampling • OpenFOAM. This core library includes the
├── sixDoFRigidBodyMotion definitions of the containers used for the
├── thermophysicalModels operations, the field definitions, the declaration
├── transportModels of the mesh and mesh features such as zones
and sets.
└── waves

The directory tree is not complete


20
OpenFOAM® directory organization
The src directory
$WM_PROJECT_DIR/src A few interesting directories are:
├── Allwmake • finiteVolume. This library provides all the
├── combustionModels classes needed for the finite volume
├── finiteVolume discretization, such as mesh handling, finite
├── fvOptions volume discretization operators (divergence,
laplacian, gradient, fvc/fvm and so on), and
├── lagrangian boundary conditions. In the directory
├── ... finiteVolume/lnInclude you also find the
├── OpenFOAM very important file fvCFD.H, which is included
├── parallel in most applications.
├── MomentumTransportModels • MomentumTransportModels, which contains
├── sampling many turbulence models.
├── sixDoFRigidBodyMotion • sixDoFRigidBodyMotion. This core library
├── thermophysicalModels contains the solver for rigid body motion.

├── transportModels • transportModels. This core library contains


many transport models.
└── waves

The directory tree is not complete


21
OpenFOAM® directory organization
The tutorials directory
$WM_PROJECT_DIR/tutorials/ Let us visit the tutorials directory. Type in the
├── Allclean terminal tut or
├── Allrun $> cd $WM_PROJECT_DIR/tutorials
├── Alltest
├── basic
├── combustion • The tutorials directory contains example
├── compressible cases for each solver. These are the tutorials
├── discreteMethods distributed with OpenFOAM®.
├── DNS
• They are organized according to the physics
├── electromagnetics
involved.
├── financial
├── heatTransfer • Use these tutorials as the starting point to
├── incompressible develop you own cases.
├── IO
├── lagrangian • A word of caution, do not use these
├── mesh tutorials as best practices, they are
├── multiphase there just to show how to use the
applications.
├── resources
└── stressAnalysis 22
OpenFOAM® directory organization
The wmake directory
$WM_PROJECT_DIR/wmake/ Let us visit the wmake directory.
├── makefiles
├── platforms • OpenFOAM® uses a special make
├── rules command: wmake
├── scripts
├── src • wmake understands the file structure in
├── wclean OpenFOAM® and uses default compiler
├── wcleanLnIncludeAll directives set in this directory.
├── wcleanPlatform
• If you add a new compiler name in
├── wdep OpenFOAM® bashrc file, you should also
├── wmake tell wmake how to interpret that name.
├── ...
├── wmakeFilesAndOptions • In wmake/rules you will find the default
├── wmakeLnInclude settings for the available compilers.
├── wmakeLnIncludeAll
├── ... • In this directory, you will also find a few
└── wrmo scripts that are useful when organizing your
files for compilation, or for cleaning up.
The directory tree is not complete
23
OpenFOAM® directory organization
OpenFOAM® user directory
$HOME/OpenFOAM/
├── $WM_PROJECT_USER_DIR
└── $WM_PROJECT_DIR

• Let us now study OpenFOAM® user directory $WM_PROJECT_USER_DIR


• When working with OpenFOAM®, you can put your files wherever you want.
• To keep things in order, it is recommended to put your cases in your
OpenFOAM® user directory or $WM_PROJECT_USER_DIR.
• It is also recommended to put your modified solvers, utilities, and libraries in
your OpenFOAM® user directory or $WM_PROJECT_USER_DIR. This is done so
you do not modify anything in the original installation.
• If you followed the standard installation instructions, the variable
$WM_PROJECT_USER_DIR should point to the directory
$HOME/OpenFOAM/USER_NAME-8, where USER_NAME is the name of the
user (e.g., johnDoe).
24
OpenFOAM® directory organization
Looking for information in OpenFOAM® source code
• To locate files you can use the find command.
• If you want to locate a directory inside $WM_PROJECT_DIR that contains the string fvPatch in
its name, you can proceed as follows,
• $> find $WM_PROJECT_DIR –type d -name “*fvPatch*”

Where to look for Look for Case Look for this


directories sensitive (using wildcards)

• If you want to locate a file inside $WM_PROJECT_DIR that contains the string fvPatch in its
name, you can proceed as follows,
• $> find $WM_PROJECT_DIR –type f -name “*fvPatch*”

Where to look for Look for Case Look for this


files sensitive (using wildcards)

• If you want to find a string inside a file, you can use the grep command.
• For example, if you want to find the string LES inside all the files within the directory
$FOAM_SOLVERS, you can proceed as follows,
• $> grep -r -n “LES” $FOAM_SOLVERS
The argument -r means recursive and -n will output the line number.
25
OpenFOAM® directory organization
Looking for information in OpenFOAM® source code
• Dictionaries are input files required by OpenFOAM®.
• As you can imagine, there are many dictionaries in OpenFOAM®. The easiest way to find all of
them is to do a local search in the installation directory as follows,
• For instance, if you are interested in finding all the files that end with the Dict word in the
tutorials directory, in the terminal type:
• $> find $FOAM_TUTORIALS -name “*Dict”
(Case sensitive search)
• $> find $FOAM_TUTORIALS –iname ‘*dict’
(Non-case sensitive search)

• When given the search string, you can use single quotes ‘ ’ or double-quotes “ ” (do not mixed
them).
• We recommend to use single quotes, but it is up to you.

26
OpenFOAM® directory organization
Looking for information in OpenFOAM® source code
• A few more advanced commands to find information in your OpenFOAM® installation.
• To find which tutorial files use the boundary condition slip:
• $> find $FOAM_TUTORIALS -type f | xargs grep -sl ‘ slip’
This command will look for all files inside the directory $FOAM_TUTORIALS, then the
output is used by grep to search for the string slip.

• To find where the source code for the boundary condition slip is located:
• $> find $FOAM_SRC -name “*slip*”

• To find what applications do not run in parallel:


• $> find $WM_PROJECT_DIR -type f | xargs grep -sl ‘noParallel’

• OpenFOAM® understands REGEX syntax.

27
OpenFOAM® directory organization
Environment variables
• Remember, OpenFOAM® uses its own environment variables.
• OpenFOAM® environment settings are contained in the OpenFOAM-8/etc directory.
• If you installed OpenFOAM® in the default location, they should be in:
• $HOME/OpenFOAM/OpenFOAM-8/etc
• If you are running bash or ksh (if in doubt type in the terminal echo $SHELL), you sourced the
$WM_PROJECT_DIR/etc/bashrc file by adding the following line to your $HOME/.bashrc
file:
• source $HOME/OpenFOAM/OpenFOAM-8/etc/bashrc

• By sourcing the file $WM_PROJECT_DIR/etc/bashrc, we start to use OpenFOAM®


environment variables.
• By default, OpenFOAM® uses the system compiler and the system MPI compiler.
• When you use OpenFOAM® you are using its environment settings, that is, its
path to libraries and compilers. So if you are doing software developing, and
you are having compilation problems due to conflicting libraries or missing
compilers, try to unload OpenFOAM® environment variables

28
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

29
Directory structure of an OpenFOAM® application/utility

Directory structure of a general solver


$WM_PROJECT_DIR/applications/solvers/solverName/
├── createFields.H
├── appName.C
└── Make
├── files
└── options

The $WM_PROJECT_DIR/applications/solvers/solverName/ directory contains the


source code of the solver.
• solverName/appName.C: is the actual source code of the solver.
• solverName/createFields.H: declares all the field variables and initializes the solution.
• The Make directory contains compilation instructions.
• Make/files: names all the source files (.C), it specifies the solverName name and
location of the output file.
• Make/options: specifies directories to search for include files and libraries to link the
solver against.
30
Directory structure of an OpenFOAM® application/utility

Directory structure of a general utility


$WM_PROJECT_DIR/applications/utilities/utilityName/
├── utility_dictionary
├── utilityName.C
├── header_files.H
└── Make
├── files
└── options

The $WM_PROJECT_DIR/utilities/utilityName/ directory contains the source code of


the utility.
• utilityName/utilityName.C: is the actual source code of the application.
• utilityName/header_files.H: header files required to compile the application.
• utilityName/utility_dictionary: application’s master dictionary.
• The Make directory contains compilation instructions.
• Make/files: names all the source files (.C), it specifies the utilityName name
and location of the output file.
• Make/options: specifies directories to search for include files and libraries to link the
solver against. 31
Directory structure of an OpenFOAM® application/utility
• For your own solvers and utilities, it is recommended to put the source code
in the directory $WM_PROJECT_USER_DIR following the same structure as
in $WM_PROJECT_DIR/applications/solvers and
$WM_PROJECT_DIR/utilities/.
• Also, you will need to modify the files Make/files and Make/options to
point to the new name and location of the compiled binaries and libraries to
link the solver against.
• You can do anything you want to your own copies, so you do not risk
messing things up.
• This is done so you do not modify anything in the original installation, except
for updates!

32
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

33
Applications/utilities in OpenFOAM®
• OpenFOAM® is not a single executable.
• Depending of what you want to do, you will need to use a specific application and
there are many of them.
• If you are interested in knowing all the solvers, utilities, and libraries that come with
your OpenFOAM® distribution, read the applications and libraries section in the user
guide (chapter 3).
• In the directory $WM_PROJECT_DIR/doc you will find the documentation in pdf
format.
• You can also access the online user guide. Go to the link
http://cfd.direct/openfoam/user-guide/#contents, then go to chapter 3 (applications
and libraries).
• If you want to get help on how to run an application, type in terminal

1. $> application_name -help

• The option –help will not run the application; it will only show all the options
available.
• You can also get all the help you want from the source code. 34
Applications/utilities in OpenFOAM®
• You will find all the applications in the directory $FOAM_SOLVERS (you can use the
alias sol to go there).
• You will find all the utilities in the directory $FOAM_UTILITIES (you can use the alias
util to go there).
• For example, in the directory $FOAM_SOLVERS, you will find the directories containing
the source code for the solvers available in the OpenFOAM® installation (version 8):

• basic • financial
• combustion • heatTransfer
• compressible • incompressible
• discreteMethods • lagrangian
• DNS • multiphase
• electromagnetics • stressAnalysis

• The solvers are subdivided according to the physics they address.


• The utilities are also subdivided in a similar way.
35
Applications/utilities in OpenFOAM®
• For example, in the sub-directory incompressible you will find several sub-
directories containing the source code of the following solvers:

• adjointShapeOptimizationFoam • pimpleFoam
• boundaryFoam • pisoFoam
• icoFoam • shallowWaterFoam
• nonNewtonianIcoFoam • simpleFoam

• Inside each directory, you will find a file with the extension *.C and the same name
as the directory. This is the main file, where you will find the top-level source code
and a short description of the solver or utility.
• For example, in the file incompressible/icoFoam/icoFoam.C you will find the
following description:

Transient solver for incompressible, laminar flow of Newtonian fluids.

36
Applications/utilities in OpenFOAM®
• Remember, OpenFOAM® is not a single executable.
• You will need to find the solver or utility that best fit what you want to do.
• A few solvers that we will use during this course:
• icoFoam: laminar incompressible unsteady solver. Be careful, do not use this
solver for production runs as it has many limitations.
• simpleFoam: incompressible steady solver for laminar/turbulent flows.
• pimpleFoam: incompressible unsteady solver for laminar/turbulent flows.
• rhoSimpleFoam: compressible steady solver for laminar/turbulent flows.
• rhoPimpleFoam: unsteady compressible solver for (laminar/turbulent flows.
• interFoam: unsteady multiphase solver for separated flows using the VOF
method (laminar and turbulent flows).
• laplacianFoam: Laplace equation solver.
• potentialFoam: potential flow solver.
• scalarTransportFoam: steady/unsteady general transport equation solver.

37
Applications/utilities in OpenFOAM®
• Take your time and explore the source code.
• Also, while exploring the source code be careful not to add unwanted modifications in
the original installation.
• If you modify the source code, be sure to do the modifications in your user directory
instead of the main source code.

38
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

39
Directory structure of an OpenFOAM® case
Directory structure of a general case
case_name • OpenFOAM® uses a very particular directory
├── 0 structure for running cases.
│ ├── p • You should always follow the directory structure,
│ └── U otherwise, OpenFOAM® will complain.
├── constant • To keep everything in order, the case directory is
│ ├── polyMesh often located in the path
$WM_PROJECT_USER_DIR/run.
│ │ ├── boundary
│ │ ├── faces • This is not compulsory but highly advisable. You can
copy the case files anywhere you want.
│ │ ├── neighbour
• The name of the case directory is given by the user
│ │ ├── owner (do not use white spaces or strange symbols).
│ │ └── points
• Depending of the solver or application you would like
│ └── transportProperties to use, you will need different files in each sub-
├── system directory.
│ ├── controlDict • Remember, you always run the applications and
│ ├── fvSchemes utilities in the top level of the case directory (the
│ └── fvSolution directory with the name case_name). Not in the
directory system, not in the directory constant, not
└── time_directories in the directory 0.

40
Directory structure of an OpenFOAM® case
Directory structure of a general case
case_name case_name: the name of the case directory is given by
├── 0 the user (do not use white spaces or strange
│ ├── p symbols).

│ └── U This is the top-level directory, where you run the


applications and utilities.
├── constant
│ ├── polyMesh system: contains run-time control and solver
numerics.
│ │ ├── boundary
constant: contains physical properties,
│ │ ├── faces
turbulence modeling properties, advanced physics
│ │ ├── neighbour and so on.
│ │ ├── owner constant/polyMesh: contains the
│ │ └── points polyhedral mesh information.
│ └── transportProperties 0: contains boundary conditions (BC) and initial
├── system conditions (IC).
│ ├── controlDict time_directories: contains the solution and
│ ├── fvSchemes derived fields. These directories are created by the
│ └── fvSolution solver automatically and according to the preset
saving frequency, e.g., 1, 2, 3, 4, … , 100.
└── time_directories

41
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

42
Running my first OpenFOAM® case setup blindfold
Before we start – Always remember the directory structure
case_name
├── 0
├── constant
│ └── polyMesh
├── system
└── time_directories

• To keep everything in order, the case directory is often located in the path
$WM_PROJECT_USER_DIR/run.
• This is not compulsory but highly advisable, you can put the case in any directory of your preference.
• The name of the case directory if given by the user (do not use white spaces).
• You run the applications and utilities in the top level of this directory.
• The directory system contains run-time control and solver numerics.
• The directory constant contains physical properties, turbulence modeling properties, advanced physics
and so on.
• The directory constant/polyMesh contains the polyhedral mesh information.
• The directory 0 contains boundary conditions (BC) and initial conditions (IC).
43
Running my first OpenFOAM® case setup blindfold
Before we start – Setting OpenFOAM® cases
• As you will see, it is quite difficult to remember all the dictionary files needed to run
each application.
• It is even more difficult to recall the compulsory and optional entries of each input file.
• When setting a case from scratch in OpenFOAM®, what you need to do is find a
tutorial or a case that close enough does what you want to do and then you can adapt
it to your physics.
• Having this in mind, you have two sources of information:
• $WM_PROJECT_DIR/tutorials
(The tutorials distributed with OpenFOAM®)

• $PTOFC
(The tutorials used during this training)

• If you use a GUI, things are much easier. However, OpenFOAM® does not come
with a native GUI interface.
• We are going to do things in the hard way (and maybe the smart way), we are going
to use the Linux terminal
44
Running my first OpenFOAM® case setup blindfold
Flow in a lid-driven square cavity – Re = 100
Incompressible flow

Physical and numerical side of the


problem:
• The governing equations of the problem are the
incompressible laminar Navier-Stokes equations.
• We are going to work in a 2D domain, but the
problem can be easily extended to 3D.
• To find the numerical solution we need to
discretize the domain (mesh generation), set the
boundary and initial conditions, define the flow
properties, setup the numerical scheme and solver
settings, and set runtime parameters (time step,
simulation time, saving frequency and so on).
• For convenience, when dealing with
incompressible flows we will use relative pressure.
• All the dictionaries files have been already preset.

45
Running my first OpenFOAM® case setup blindfold
Workflow of the case

blockMesh

icoFoam functionObjects

sampling paraview

46
Running my first OpenFOAM® case setup blindfold
A word of caution about the solver icoFoam

• The solver icoFoam is targeted for laminar incompressible unsteady solver.


• We do not recommend the use of this solver for production runs as it has no
modeling capabilities and limited post-processing features.
• Instead of using icoFoam, you are better of with pisoFoam or pimpleFoam.

47
Running my first OpenFOAM® case setup blindfold
At the end of the day, you should get something like this

Mesh (very coarse and 2D)

Pressure field (relative pressure) Velocity magnitude field


48
Running my first OpenFOAM® case setup blindfold
At the end of the day, you should get something like this
Y centerline

• And as CFD is not only about pretty colors, we should also


validate the results
X centerline

High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 49
Running my first OpenFOAM® case setup blindfold

• Let us run our first case. Go to the directory:

$PTOFC/101OF/cavity2D

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.

50
Running my first OpenFOAM® case setup blindfold
Loading OpenFOAM® environment

• If you are using the lab workstations, you will need to source OpenFOAM® (load
OpenFOAM® environment).

• To source OpenFOAM®, type in the terminal:


• $> of8

• To use PyFoam (a plotting utility) you will need to source it. Type in the terminal:
• $> anaconda3

• Remember, every time you open a new terminal window you need to source
OpenFOAM® and PyFoam.
• Also, you might need to load OpenFOAM® again after loading PyFoam.
• By default, when installing OpenFOAM® and PyFoam you do not need to do this.
This is our choice as we have many things installed and we want to avoid conflicts
between applications.
51
Running my first OpenFOAM® case setup blindfold
What are we going to do?
• We will use the lid-driven square cavity tutorial as a general example to show you how to set up
and run solvers and utilities in OpenFOAM®.
• In this tutorial we are going to generate the mesh using blockMesh.
• After generating the mesh, we will look for topological errors and assess the mesh quality. For
this we use the utility checkMesh. Later on, we are going to talk about what is a good mesh.
• Then, we will find the numerical solution using icoFoam, which is a transient solver for
incompressible, laminar flow of Newtonian fluids. By the way, we hope you did not forget where
to look for this information.
• And we will finish with some quantitative post-processing and qualitative visualization using
paraFoam and OpenFOAM® utilities.
• While we run this case, we are going to see a lot of information on the screen (standard output
stream or stdout), but it will not be saved. This information is mainly related to convergence of
the simulation, we will talk about this later on.
• A final word, we are going to use the solver icoFoam but have in mind that this is a very basic
solver with no modeling capabilities and limited post-processing features.
• Therefore, is better to use pisoFoam or pimpleFoam which are equivalent to icoFoam but
with many more features.

52
Running my first OpenFOAM® case setup blindfold
Running the case blindfold
• Let us run this case blindfold.
• Later we will study in detail each file and directory.
• Remember, the variable $PTOFC is pointing to the path where you unpacked the
tutorials.
• You can create this environment variable or write down the path to the directory.
• In the terminal window type:

1. $> cd $PTOFC/101OF/cavity

2. $> ls –l
3. $> blockMesh
4. $> checkMesh
5. $> icoFoam
6. $> postProcess -func sampleDict -latestTime
7. $> gnuplot gnuplot/gnuplot_script
8. $> paraFoam
53
Running my first OpenFOAM® case setup blindfold
Running the case blindfold
• In step 1 we go to the case directory. Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
• In step 2 we just list the directory structure (this step is optional). Does it look familiar to you? In
the directory 0 you will the initial and boundary conditions, in the constant directory you will
find the mesh information and physical properties, and in the directory system you will find the
dictionaries that controls the numerics, runtime parameters and sampling.
• In step 3 we generate the mesh.
• In step 4 we check the mesh quality. We are going to address how to assess mesh quality later
on.
• In step 5 we run the simulation. This will show a lot information on the screen, the standard
output stream will not be saved.
• In step 6 we use the utility postProcess to do some sampling only of the last saved solution
(the latestTime flag). This utility will read the dictionary file named sampleDict located in
the directory system.
• In step 7 we use a gnuplot script to plot the sampled values. Feel free to take a look and reuse
this script.
• Finally, in step 8 we visualize the solution using paraFoam. In the next slides we are going to
briefly explore this application.
54
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam

Menu Bar
Toolbars

Pipeline Browser

Properties panel

Apply button
Press this button to
load the case or to
apply a filter

3D View/Canvas
Advanced Toggle
55
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Toolbars
• Main Controls

• VCR Controls (animation controls)

• Current Time Controls

• Active Variable Controls

• Representation Toolbar

• Camera Controls (view orientation)

• Center Axes Controls

• Common Filters

• Data Analysis Toolbar


56
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Mesh visualization
Select Surface With Edges in the Representation Toolbar Fit to screen Select the -Z view

Select Solid Color in the


Active Variable Controls

Click on the eyeball in


the Pipeline Browser to
hide/unhide the object

Select mesh parts to visualize.


By default it will automatically
select internalMesh

Select the volume fields to


visualize. By default it will select
U and p

57
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – 3D View and mouse interaction
Select view orientation in the Camera Controls

Mouse interaction in the


3D view

Rotate

Zoom

Pan

Zoom

3D View/Canvas

58
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Fields visualization
Select Last Frame in the VCR Controls Current Time Controls

Select U in Active Variable Controls

Turn on/off color bar

Select Surface in the


Representation Toolbar

Select Magnitude in the


drop down menu

Select volume fields to visualize.


By default it will select U and p.

59
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters
• Filters are functions that generate, extract or derive features from the input data.
• They are attached to the input data.
• You can access the most commonly used filters from the Common Filters toolbar

• You can access all the filters from the menu Filter.

60
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters

Filters are attached


to the input data

• Even if the case is 2D, it will be


visualized as if it were a 3D case.
• Notice that there is only one cell in
the Z direction.
• Let us use the slice filter. This filter
will create a cut plane.
• Let us create a slice normal to the
Z direction.

61
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Slice filter

1. Select the Slice filter

If you want to erase a filter,


right click on it and select
Delete

4. Press Apply

3. Optional - Turn off the


option Show Plane

2. Select the direction Z Normal.


Additionally you can choose the
origin of the plane (by default is the
mid section)

62
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Glyph filter
4. Color the colors using Solid Color
1. Select the Glyph filter. This
filter will be applied on the
Slice1 filter

Notice that the filter


Glyph was applied on
the Slice1 filter.

3. Press Apply

2. Filter options

Notice that the vectors are plotted in the


cell vertices. To plot the vectors at the
cell centers, use the filter cell
centers and replot the vectors.

63
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Plot Over Line filter
1.a. Select the Plot Over Line
filter.

1.b. Alternative, you can select Plot


Over Line filter from the Data
Analysis Toolbar

(0.5, 1, 1)

Notice that we are using the filter in


a clean Pipeline

3. Press Apply

(0.5, 0, 1)
2. Enter the coordinates of the line

Line

64
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters
4. Optional – Use the VCR Control to change the frame.
The line chart view will be updated automatically

3. Optional - To save the


sampled data in CSV
format, click on the filter.
Then click on the File
menu and select the
option Save Data

2. Select the variables to


plot in the line chart view

1. Click on the line chart view (the blue frame indicates that it is the active view)

65
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• In the previous case, we ran the simulation but we did not save the standard output
stream (stdout) in a log file.

• We just saw the information on-the-fly.

• Our advice is to always save the standard output stream (stdout) in a log file.

• It is of interest to always save the log as if something goes wrong and you would like
to do troubleshooting, you will need this information.

• Also, if you are interested in plotting the residuals you will need the log file.

• By the way, if at any point you ask us what went wrong with your simulation, it is likely
that we will ask you for this file.

• We might also ask for the standard error stream (stderr).

66
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• There are many ways to save the log files.
• From now on, we will use the Linux tee command to save log files.
• To save a log file of the simulation or the output of any utility, you can proceed as
follows:

1. $> foamCleanTutorials
2. $> blockMesh | tee log.blockMesh
3. $> checkMesh | tee log.checkMesh
4. $> icoFoam | tee log.icoFoam

The vertical bar or pipelining operator is used to concatenate commands

• You can use your favorite text editor to read the log file (e.g., gedit, vi, emacs).

67
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• In step 1 we erase the mesh and all the folders, except for 0, constant and system. This
script comes with your OpenFOAM® installation.
• In step 2, we generate the mesh using the meshing tool blockMesh. We also redirect the
standard output to an ascii file with the name log.blockMesh (it can be any name). The tee
command will redirect the screen output to the file log.blockMesh and at the same time will
show you the information on the screen.
• In step 3 we check the mesh quality. We also redirect the standard output to an ascii file with the
name log.checkMesh (it can be any name).
• In step 4 we run the simulation. We also redirect the standard output to an ascii file with the
name log.icoFoam (it can be any name). Remember, the tee command will redirect the
screen output to the file log.icoFoam and at the same time will show you the information on
the screen.
• To postprocess the information contained in the solver log file log.icoFoam, we can use the
utility foamLog. Type in the terminal:
• $> foamLog log.icoFoam
• This utility will extract the information inside the file log.icoFoam. The extracted information is
saved in an editable/plottable format in the directory logs.
• At this point we can use gnuplot to plot the residuals. Type in the terminal:
• $> gnuplot 68
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• To plot the information extracted with foamLog using gnuplot, we can proceed as
follows (remember, at this point we are using the gnuplot prompt):
1. gnuplot> set logscale y
Set log scale in the y axis

2. gnuplot> plot ‘logs/p_0’ using 1:2 with lines


Plot the file p_0 located in the directory logs, use columns 1 and 2 in the file p_0, use lines to output the plot.

3. gnuplot> plot ‘logs/p_0’ using 1:2 with lines, ‘logs/pFinalRes_0’ using 1:2 with lines
Here we are plotting to different files. You can concatenate files using comma (,)

4. gnuplot> reset
To reset the scales

5. gnuplot> plot ‘logs/CourantMax_0’ u 1:2 w l


To plot file CourantMax_0. The letter u is equivalent to using. The letters w l are equivalent to with lines

6. gnuplot> set logscale y

7. gnuplot> plot [30:50][] ‘logs/Ux_0’ u 1:2 w l title ‘Ux’,‘logs/Uy_0’ u 1:2 w l title ‘Uy’
Set the x range from 30 to 50 and plot tow files and set legend titles

8. gnuplot> exit
To exit gnuplot

69
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• The output of step 3 is the following:

• The fact that the initial residuals (red line) are dropping to the same value of the final
residuals (monotonic convergence), is a clear indication of a steady behavior.
70
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files and plotting the residuals
• It is also possible to plot the log information on the fly.
• The easiest way to do this is by using PyFoam (you will need to install it):
• $> pyFoamPlotRunner.py [options] <foamApplication>
• If you are using the lab workstations, you will need to source PyFoam. To source PyFoam, type in the
terminal:
• $> anaconda3
• If you need help or want to know all the options available,
• $> pyFoamPlotRunner.py –-help
• To run this case with pyFoamPlotRunner.py, in the terminal type:
• $> pyFoamPlotRunner.py icoFoam
• If you do not feel comfortable using pyFoamPlotRunner.py to run the solver, it is also possible to plot the
information saved in the log file using PyFoam.
• To do so you will need to use the utility pyFoamPlotWatcher.py. For example,
• $> icoFoam | tee log.icoFoam
• Then, in a new terminal window launch pyFoamPlotWatcher, as follows,
• $> pyFoamPlotWatcher.py log.icoFoam
• You can also use pyFoamPlotWatcher.py to plot the information saved in an old log file.

71
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files and plotting the residuals
• This is a screenshot on my computer. In this case, pyFoamPlotRunner is plotting
the initial residuals and continuity errors on the fly.

72
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• Your simulation will automatically stop at the time value you set using the keyword endTime in
the controlDict dictionary.
endTime 50;
• If for any reason you want to stop your simulation before reaching the value set by the keyword
endTime, you can change this value to a number lower than the current simulation time (you
can use 0 for instance). This will stop your simulation, but it will not save your last time-step or
iteration, so be careful.
1 /*--------------------------------*- C++ -*----------------------------------*\
2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 8 |
5 | \\ / A nd | Web: www.OpenFOAM.org |
6 | \\/ M anipulation | |
7 \*---------------------------------------------------------------------------*/
8 FoamFile
9 {
10 version 2.0;
11 format ascii;
12 class dictionary;
13 object controlDict;
14 }
15 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
16
17 application icoFoam;
18
19 startFrom startTime;
20
21 startTime 0;
22
23 stopAt endTime;
24
25 endTime 50;
73
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• If you want to stop the simulation and save the solution, in the controlDict dictionary made
the following modification,
stopAt writeNow;
This will stop your simulation and will save the current time-step or iteration.

1 /*--------------------------------*- C++ -*----------------------------------*\


2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 8 |
5 | \\ / A nd | Web: www.OpenFOAM.org |
6 | \\/ M anipulation | |
7 \*---------------------------------------------------------------------------*/
8 FoamFile
9 {
10 version 2.0;
11 format ascii;
12 class dictionary;
13 object controlDict;
14 }
15 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
16
17 application icoFoam;
18
19 startFrom startTime;
20
21 startTime 0;
22
23 stopAt writeNow;
24
25 endTime 50;

74
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• The previous modifications can be done on-the-fly, but you will need to set the
keyword runTimeModifiable to true in the controlDict dictionary.
• By setting the keyword runTimeModifiable to true, you will be able to modify most of
the dictionaries on-the-fly.

1 /*--------------------------------*- C++ -*----------------------------------*\


2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 8 |
5 | \\ / A nd | Web: www.OpenFOAM.org |
6 | \\/ M anipulation | |
7 \*---------------------------------------------------------------------------*/
8 FoamFile
9 {
10 version 2.0;
11 format ascii;
12 class dictionary;
13 object controlDict;
14 }

44
45 runTimeModifiable true;
46

75
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• You can also kill the process. For instance, if you did not launch the solver in background, go to its terminal
window and press ctrl-c. This will stop your simulation, but it will not save your last time-step or iteration, so
be careful.
• If you launched the solver in background, just identify the process id using top or htop (or any other process
manager) and terminate the associated process. Again, this will not save your last time-step or iteration.
• To identify the process id of the OpenFOAM® solver or utility, just read screen. At the beginning of the output
screen, you will find the process id number.

/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 8 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 4.x-e964d879e2b3
Exec : icoFoam
Date : Mar 11 2017
Time : 23:21:50
Host : "linux-ifxc"
PID : 3100 Process id number
Case : /home/joegi/my_cases_course/5x/101OF/cavity
nProcs : 1
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

76
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• When working locally, we usually proceed in this way:

• $> icoFoam | tee log.icofoam

This will run the solver icoFoam (by the way, this works for any solver or utility), it will save the
standard output stream in the file log.icofoam and will show the solver output on the fly.

• If at any moment we want to stop the simulation, and we are not interested in saving the last
time-step, we press ctrl-c.

• If we are interested in saving the last time step, we modify the controlDict dictionary and
add the following keyword
stopAt writeNow;

• Remember, this modification can be done on the fly. However, you will need to set the keyword
runTimeModifiable to yes in the controlDict dictionary.

77
Running my first OpenFOAM® case setup blindfold
Cleaning the case folder
• If you want to erase the mesh and the solution in the current case folder, you can type in the
terminal,
$> foamCleanTutorials

If you are running in parallel, this will also erase the processorN directories. We will talk about
running in parallel later.

• If you are looking to only erase the mesh, you can type in the terminal,
$> foamCleanPolyMesh

• If you are only interested in erasing the saved solutions, in the terminal type,
$> foamListTimes -rm

• If you are running in parallel and you want to erase the solution saved in the processorN
directories, type in the terminal,
$> foamListTimes –rm -processor
78
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

79
A deeper view to my first OpenFOAM® case setup
• We will take a close look at what we did by looking at the case files.
• The case directory originally contains the following sub-directories: 0, constant, and
system. After running icoFoam it also contains the time step directories 1, 2, 3,
..., 48, 49, 50, the post-processing directory postProcessing, and the
log.icoFoam file (if you chose to redirect the standard output stream).
• The time step directories contain the values of all the variables at those time
steps (the solution). The 0 directory is thus the initial condition and boundary
conditions.
• The constant directory contains the mesh and dictionaries for thermophysical,
turbulence models and advanced physical models.
• The system directory contains settings for the run, discretization schemes and
solution procedures.
• The postProcessing directory contains the information related to the
functionObjects (we are going to address functionObjects later).
• The icoFoam solver reads these files and runs the case according to those
settings.

80
A deeper view to my first OpenFOAM® case setup
• Before continuing, we want to point out the following:
• Each dictionary file in the case directory has a header.
• Lines 1-7 are commented.
• You should always keep lines 8 to 14, if not, OpenFOAM® will complain.
• According to the dictionary you are using, the class keyword (line 12)
will be different. We are going to talk about this later on.
• From now on and unless it is strictly necessary, we will not show the
header when listing the dictionaries files.

1 /*--------------------------------*- C++ -*----------------------------------*\


2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 8 |
5 | \\ / A nd | Web: www.OpenFOAM.org |
6 | \\/ M anipulation | |
7 \*---------------------------------------------------------------------------*/
8 FoamFile
9 {
10 version 2.0;
11 format ascii;
12 class dictionary;
13 object controlDict;
14 }

81
A deeper view to my first OpenFOAM® case setup

Let us explore the case directory

82
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)

• In this directory you will find the sub-directory polyMesh and the dictionary file
transportProperties.
• The transportProperties file is a dictionary for the dimensioned scalar nu, or the
kinematic viscosity.

17 nu nu [ 0 2 -1 0 0 0 0 ] 0.01; //Re 100


18 //nu nu [ 0 2 -1 0 0 0 0 ] 0.001; //Re 1000

• Notice that line 18 is commented.


• The values between square bracket are the units.
• OpenFOAM® is fully dimensional. You need to define the dimensions for
each field dictionary and physical properties defined.
• Your dimensions shall be consistent.
83
A deeper view to my first OpenFOAM® case setup

Dimensions in OpenFOAM® (metric system)

No. Property Unit Symbol

1 Mass Kilogram kg

2 Length meters m

3 Time second s

4 Temperature Kelvin K

5 Quantity moles mol

6 Current ampere A

7 Luminuous intensity candela cd

[ 1 (kg), 2 (m), 3 (s), 4 (K), 5 (mol), 6 (A), 7 (cd)]

84
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)

• Therefore, the dimensioned scalar nu or the kinematic viscosity,

17 nu nu [ 0 2 -1 0 0 0 0 ] 0.01;

has the following units

[ 0 m^2 s^-1 0 0 0 0 ]

Which is equivalent to

85
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)

• In this case, as we are working with an incompressible flow, we only need to define
the kinematic viscosity.

• Later on, we will ask you to change the Reynolds number, to do so you can change
the value of nu. Remember,

• You can also change the free stream velocity U or the reference length L.
86
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)

• Depending on the physics involved and models used, you will need to define more
variables in the dictionary transportProperties.
• For instance, for a multiphase case you will need to define the density rho and
kinematic viscosity nu for each single phase. You will also need to define the surface
tension .
• Also, depending of your physical model, you will find more dictionaries in the constant
directory.
• For example, if you need to set gravity, you will need to create the dictionary g.
• If you work with compressible flows you will need to define the dynamic viscosity mu,
and many other physical properties in the dictionary thermophysicalProperties.
• As we are not dealing with compressible flows (for the moment), we are not going into
details.

87
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh directory
(and by the way, open each file and go thru its content)

• In this case, the polyMesh directory is initially empty. After generating the mesh, it
will contain the mesh in OpenFOAM® format.
• To generate the mesh in this case, we use the utility blockMesh. This utility reads
the dictionary blockMeshDict located in the system folder.
• We will briefly address a few important inputs of the blockMeshDict dictionary.
• Do not worry, we are going to revisit this dictionary during the meshing session.
• However, have in mind that rarely you will use this utility to generate a mesh for
complex geometries.
• Go to the directory system and open blockMeshDict dictionary with your favorite
text editor, we will use gedit.

88
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary
• The blockMeshDict dictionary first defines a list with a number of vertices:
• The keyword convertToMeters (line 17), is a scaling factor. In this case
17 convertToMeters 1;
18
we do not scale the dimensions.
19 xmin 0;
20 xmax 1; • In the section vertices (lines 37-58), we define the vertices coordinates of
21 ymin 0; the geometry. In this case, there are eight vertices defining the geometry.
22 ymax 1;
23 zmin 0;
OpenFOAM® always uses 3D meshes, even if the simulation is 2D.
24 zmax 1;
25 • We can directly define the vertex coordinates in the section vertices
26 xcells 20; (commented lines 49-56), or we can use macro syntax.
27 ycells 20;
28 zcells 1; • Using macro syntax we first define a variable and its value (lines 19-24),
29
37 vertices and then we can use them by adding the symbol $ to the variable name
38 ( (lines 39-46).
39 ($xmin $ymin $zmin) //vertex 0
40 ($xmax $ymin $zmin) //vertex 1 • In lines 26-28, we define a set of variables that will be used at a later time.
41 ($xmax $ymax $zmin) //vertex 2
42 ($xmin $ymax $zmin) //vertex 3 These variables are related to the number of cells in each direction.
43 ($xmin $ymin $zmax) //vertex 4
44 ($xmax $ymin $zmax) //vertex 5 • Finally, notice that the vertex numbering starts from 0 (as the counters in
45 ($xmax $ymax $zmax) //vertex 6 c++). This numbering applies for blocks as well.
46 ($xmin $ymax $zmax) //vertex 7
47
48 /*
49 (0 0 0)
50 (1 0 0)
51 (1 1 0)
52 (0 1 0)
53 (0 0 0.1)
54 (1 0 0.1)
55 (1 1 0.1)
56 (0 1 0.1)
57 */
58 );

89
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary
• The blockMeshDict dictionary also defines the boundary patches:

• In the section boundary, we define all the surface


71 boundary
72 (
patches where we want to apply boundary conditions.
73 movingWall Name
74 { • This step is of paramount importance, because if we do
75 type wall; Type
76 faces not define the surface patches, we will not be able to
77 (
Connectivity
apply the boundary conditions.
78 (3 7 6 2)
79 );
80 } • For example:
81 fixedWalls
82 { • In line 73 we define the patch name movingWall
83 type wall;
84 faces (the name is given by the user).
85 (
86 (0 4 7 3) • In line 75 we give a base type to the surface patch.
87 (2 6 5 1)
88 (1 5 4 0) In this case wall (do not worry we are going to talk
89
90 }
);
about this later on).
91 frontAndBack
92 { • In line 78 we give the connectivity list of the
93
94
type empty;
faces
vertices that made up the surface patch or face,
95 ( that is, (3 7 6 2). Have in mind that the vertices
96 (0 3 2 1)
97 (4 5 6 7) need to be neighbors and it does not matter if the
98
99 }
);
ordering is clockwise or counterclockwise.
100 );
• Remember, faces are defined by a list of 4 vertex
numbers, e.g., (3 7 6 2).
90
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary

• To sum up, the blockMeshDict dictionary generates in this case a single block with:
• X/Y/Z dimensions: 1.0/1.0/1.0
• Cells in the X, Y and Z directions: 20 x 20 x 1 cells.
• One single hex block with straight lines.
• Patch type wall and patch name fixedWalls at three sides.
• Patch type wall and patch name movingWall at one side.
• Patch type empty and patch name frontAndBack patch at two sides.

• If you are interested in visualizing the actual block topology, you can use paraFoam
as follows,
• $> paraFoam –block

91
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary

• As you can see, the blockMeshDict dictionary can be really tricky.


• If you deal with really easy geometries (rectangles, cylinders, and so on), then you
can use blockMesh to do the meshing, but this is the exception rather than the rule.
• When using snappyHexMesh, (a body fitted mesher that comes with OpenFOAM®)
you will need to generate a background mesh using blockMesh. We are going to
deal with this later on.
• Our best advice is to create a template and reuse it.
• Also, take advantage of macro syntax for parametrization, and #calc syntax to
perform inline calculations (lines 30-35 in the blockMeshDict dictionary we just
studied).
• We are going to deal with #codeStream syntax and #calc syntax during the
programming session.

92
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• First of all, this file is automatically generated after you create the mesh
using blockMesh or snappyHexMesh, or when you convert the mesh from
a third-party format.
• In this file, the geometrical information related to the base type patch of
each boundary (or surface patch) of the domain is specified.
• The base type boundary condition is the actual surface patch where we are
going to apply a numerical type boundary condition (or numerical boundary
condition).
• The numerical type boundary condition assign a field value to the surface
patch (base type).
• We define the numerical type patch (or the value of the boundary
condition), in the directory 0 or time directories.

93
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• In this case, the file boundary is divided as follows

18 3 Number of surface patches


19 (
20 movingWall
In the list bellow there must be 3 patches
21 { definition.
22 type wall;
23 inGroups 1(wall); movingWall
24 nFaces 20;
25 startFace 760;
26 } frontAndBack
27 fixedWalls
28 {
29 type wall;
30 inGroups 1(wall);
31 nFaces 60;
32 startFace 780;
33 }

fixedWall
fixedWall
34 frontAndBack
35 {
36 type empty;
37 inGroups 1(empty);
38 nFaces 800;
39 startFace 840;
40 }
41 )
frontAndBack

fixedWall

94
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• In this case, the file boundary is divided as follows

18 3
19 ( Name and type of the surface patches
20 movingWall Name
21 {
22 type wall; Type • The name and type of the patch is given by
23 inGroups 1(wall);
24 nFaces 20; the user.
25 startFace 760;
26 } • In this case the name and type was assigned
27 fixedWalls in the dictionary blockMeshDict.
28 {
29 type wall; • You can change the name if you do not like it.
30 inGroups 1(wall);
31 nFaces 60; Do not use strange symbols or white spaces.
32 startFace 780;
33 } • You can also change the base type. For
34 frontAndBack instance, you can change the type of the
35 {
36 type empty;
patch movingWall from wall to patch.
37 inGroups 1(empty);
38 nFaces 800;
• When converting the mesh from a third party
39 startFace 840; format, OpenFOAM® will try to recover the
40 } information from the original format. But it
41 )
might happen that it does not recognizes the
base type and name of the original file. In this
case you will need to modify this file manually.

95
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• In this case, the file boundary is divided as follows

18 3 inGroups keyword
19 ( • This keyword is optional. You can erase this information safely.
20 movingWall
21 { • It is used to group patches during visualization in
22 type wall; ParaView/paraFoam. If you open this mesh in paraFoam you will
23 inGroups 1(wall); see that there are two groups, namely: wall and empty.
24 nFaces 20;
25 startFace 760; • As usual, you can change the name.
26 } • If you want to put a surface patch in two groups, you can proceed
27 fixedWalls
as follows:
28 {
29 type wall; 2(wall wall1)
30 inGroups 1(wall);
31 nFaces 60;
In this case the surface patch belongs to the groups wall and
32 startFace 780; wall1.
33 } • Groups can have more than one patch.
34 frontAndBack
35 {
36 type empty; nFaces and startFace keywords
37 inGroups 1(empty);
38 nFaces 800; • Unless you know what you are doing, you do not need to
39 startFace 840; modify this information.
40 }
41 ) • This information is related to the starting face and ending face of
the boundary patch in the mesh data structure.
• This information is created automatically when generating the
mesh or converting the mesh.

96
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
• There are a few base type patches that are constrained or paired. This means that the type
should be the same in the boundary file and in the numerical boundary condition defined in the
field files, e.g., the files 0/U and 0/p.
• In this case, the base type of the patch frontAndBack (defined in the file boundary), is
consistent with the numerical type patch defined in the field files 0/U and 0/p. They are of
the type empty.
• Also, the base type of the patches movingWall and fixedWalls (defined in the file boundary),
is consistent with the numerical type patch defined in the field files 0/U and 0/p.
• This is extremely important, especially if you are converting meshes as not always the type of
the patches is set as you would like.
• Hence, it is highly advisable to do a sanity check and verify that the base type of the patches
(the type defined in the file boundary), is consistent with the numerical type of the patches
(the patch type defined in the field files contained in the directory 0 (or whatever time directory
you defined the boundary and initial conditions).
• If the base type and numerical type boundary conditions are not consistent, OpenFOAM® will
complain.
• Do not worry, we are going to address boundary conditions later on.

97
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• The following base type boundary conditions are constrained or paired.


That is, the type needs to be same in the boundary dictionary and field
variables dictionaries (e.g. U, p).

constant/polyMesh/boundary 0/U - 0/p (IC/BC)

symmetry symmetry
symmetryPlane symmetryPlane
empty empty
wedge wedge
cyclic cyclic
processor processor

98
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• The base type patch can be any of the numerical or derived type
boundary conditions available in OpenFOAM®. Mathematically speaking;
they can be Dirichlet, Neumann or Robin boundary conditions.

constant/polyMesh/boundary 0/U - 0/p (IC/BC)

fixedValue
zeroGradient
inletOutlet
slip
patch
totalPressure
supersonicFreeStream
and so on …
Refer to the doxygen documentation for a list of all numerical
type boundary conditions available.

99
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• The wall base type boundary condition is defined as follows:

constant/polyMesh/boundary 0/U (IC/BC) 0/p (IC/BC)

type fixedValue;
wall zeroGradient
value uniform (U V W);

• This boundary condition is not contained in the patch base type boundary
condition group, because specialize modeling options can be used on this
boundary condition.
• An example is turbulence modeling, where turbulence can be generated or
dissipated at the walls.
100
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary

• The name of the base type boundary condition and the name of the
numerical type boundary condition needs to be the same, if not,
OpenFOAM® will complain.
• Pay attention to this, specially if you are converting the mesh from another
format.

constant/polyMesh/boundary 0/U (IC/BC) 0/p (IC/BC)

movingWall movingWall movingWall


fixedWalls fixedWalls fixedWalls
frontAndBack frontAndBack frontAndBack

• As you can see, all the names are the same across all the dictionary files.
101
A deeper view to my first OpenFOAM® case setup
The system directory
(and by the way, open each file and go thru its content)

• The system directory consists of the following compulsory dictionary files:


• controlDict
• fvSchemes
• fvSolution
• controlDict contains general instructions on how to run the case.
• fvSchemes contains instructions for the discretization schemes that will be used for the
different terms in the equations.
• fvSolution contains instructions on how to solve each discretized linear equation system.
• Do not worry, we are going to study in details the most important entries of each dictionary (the
compulsory entries).
• If you forget a compulsory keyword or give a wrong entry to the keyword, OpenFOAM® will
complain and it will let you what are you missing. This applies for all the dictionaries in the
hierarchy of the case directory.
• There are many optional parameters, to know all of them refer to the doxygen documentation or
the source code. Hereafter we will try to introduce a few of them.
• OpenFOAM® will not complain if you are not using optional parameters, after all, they are
optional. However, if the entry you use for the optional parameter is wrong OpenFOAM® will let
you know.
102
A deeper view to my first OpenFOAM® case setup
The controlDict dictionary
• The controlDict dictionary contains runtime simulation controls, such
as, start time, end time, time step, saving frequency and so on.
17 application icoFoam; • Most of the entries are self-explanatory.
18
19 startFrom startTime; • This case starts from time 0 (keyword startFrom – line 19 – and
20
21 startTime 0; keyword startTime – line 21 –). If you have the initial solution in a
22 different time directory, just enter the number in line 21.
23 stopAt endTime;
24
25 endTime 50;
• The case will stop when it reaches the desired time set using the keyword
26 stopAt (line 23).
27 deltaT 0.01;
28 • It will run up to 50 seconds (keyword endTime – line 25 –).
29 writeControl runTime;
30
31 writeInterval 1; • The time step of the simulation is 0.01 seconds (keyword deltaT
32 – line 27 –).
33 purgeWrite 0;
34
35 writeFormat ascii;
• It will write the solution every second (keyword writeInterval – line 31 –)
36 of simulation time (keyword runTime – line 29 –).
37 writePrecision 8;
38 • It will keep all the solution directories (keyword purgeWrite – line 33 –).
39 writeCompression off;
40 If you want to keep only the last 5 solutions just change the value to 5.
41 timeFormat general;
42 • It will save the solution in ascii format (keyword writeFormat – line 35 –)
43 timePrecision 6;
44
with a precision of 8 digits (keyword writePrecision – line 37 –).
45 runTimeModifiable true;
• And as the option runTimeModifiable (line 45) is on (true), we can
modify all these entries while we are running the simulation.
• FYI, you can modify the entries on-the-fly for most of the dictionaries files.

103
A deeper view to my first OpenFOAM® case setup
The controlDict dictionary
• So how do we know what options are available for each keyword?
• The hard way is to refer to the source code.
• The easy way is to use the banana method.
17 application icoFoam;
18 • So what is the banana method? This method consist in inserting a dummy word
19 startFrom startTime;
20
(that does not exist in the installation) and let OpenFOAM® list the available
21 startTime 0; options.
22
23 stopAt banana; • For example. If you add banana in line 23, you will get this output:
24
25 endTime 50;
banana is not in enumeration
26 4
27 deltaT 0.01;
28 (
29 writeControl runTime;
30 nextWrite
31 writeInterval 1;
32 writeNow
33 purgeWrite 0;
34
noWriteNow
35 writeFormat ascii; endTime
36
37 writePrecision 8; )
38
39 writeCompression off; • So your options are nextWrite, writeNow, noWriteNow, endTime
40
41 timeFormat general; • And how do we know that banana does not exist in the source code? Just type in
42 the terminal:
43 timePrecision 6;
44 • $> src
45 runTimeModifiable true;
• $> grep –r –n banana .
• If you see some bananas in your output someone is messing around with your
installation.
• Remember, you can use any dummy word, but you have to be sure that it does
not exist in OpenFOAM®.
104
A deeper view to my first OpenFOAM® case setup
The controlDict dictionary

• If you forget a compulsory keyword, OpenFOAM® will tell you what


17
18
application icoFoam; are you missing.
19 startFrom startTime;
20 • So if you comment line 25, you will get this output:
21 startTime 0;
22
23 stopAt endTime;
24 --> FOAM FATAL IO ERROR
25 //endTime 50;
26 keyword endTime is undefined in dictionary …
27 deltaT 0.01;
28
29 writeControl runTime;
30 • This output is just telling you that you are missing the keyword
31 writeInterval 1;
32 endTime.
33 purgeWrite 0;
34
35 writeFormat ascii;
36
37 writePrecision 8; • Do not pay attention to the words FATAL ERROR, maybe the
38
39 writeCompression off;
developers of OpenFOAM® exaggerated a little bit.
40
41 timeFormat general;
42
43 timePrecision 6;
44
45 runTimeModifiable true;

105
A deeper view to my first OpenFOAM® case setup
The fvSchemes dictionary

• The fvSchemes dictionary contains the information related to


17 ddtSchemes the discretization schemes for the different terms appearing in
18
19
{
default backward;
the governing equations.
20 }
21 • As for the controlDict dictionary, the parameters can be
22
23
gradSchemes
{
changed on-the-fly.
24 default Gauss linear;
25 grad(p) Gauss linear; • Also, if you want to know what options are available, just use
26
27
}
the banana method.
28 divSchemes
29 { • In this case we are using the backward method for time
30
31
default
div(phi,U)
none;
Gauss linear;
discretization (ddtSchemes). For gradients discretization
32 (gradSchemes) we are using Gauss linear method. For the
33 div((nuEff*dev2(T(grad(U))))) Gauss linear;
34 } discretization of the convective terms (divSchemes) we are
35
36 laplacianSchemes
using linear interpolation for the term div(phi,U).
37 {
38 //default Gauss linear orthogonal; • For the discretization of the Laplacian (laplacianSchemes and
39
40 }
default Gauss linear limited 1;
snGradSchemes) we are using the Gauss linear method with
41 limited 1 corrections (to handle mesh non-orthogonality and
42 interpolationSchemes
43 { non-uniformity).
44 default linear;
45 } • The method we are using is second order accurate but
46
47 snGradSchemes oscillatory. We are going to talk about the properties of the
48
49
{
//default orthogonal;
numerical schemes later.
50 default limited 1;
51 } • Remember, at the end of the day we want a solution that is
second order accurate.
106
A deeper view to my first OpenFOAM® case setup
The fvSolution dictionary
• The fvSolution dictionary contains the instructions of how
to solve each discretized linear equation system. The equation
17 solvers solvers, tolerances, and algorithms are controlled from the sub-
18 {
19 p dictionary solvers.
20 {
21 solver PCG; • In the dictionary file fvSolution (and depending on the solver
22 preconditioner DIC;
23 tolerance 1e-06; you are using), you will find the additional sub-dictionaries
24 relTol 0;
PISO, PIMPLE, SIMPLE, and relaxationFactors. These
39 } entries will be described later.
40
41
42
pFinal
{
• As for the controlDict and fvSchemes dictionaries, the
43 $p; parameters can be changed on-the-fly.
44 relTol 0;
45
46
}
• Also, if you want to know what options are available just use
47 U the banana method.
48 {
49
50
solver
smoother
smoothSolver;
symGaussSeidel;
• In this case, to solve the pressure (p) we are using the PCG
51 tolerance 1e-08; method, with the preconditioner DIC, an absolute tolerance
52 relTol 0;
53 } equal to 1e-06 and a relative tolerance relTol equal to 0.
54 }
55 • The entry pFinal refers to the final pressure correction (notice
56 PISO
57 { that we are using macro syntax), and we are using a relative
58
59
nCorrectors 1;
nNonOrthogonalCorrectors 0;
tolerance relTol equal to 0. We are putting more computational
60 pRefCell 0; effort in the last iteration.
61 pRefValue 0;
62 }
• In this case, we are using the same tolerances for p and
pFinal. However, you can use difference tolerances, where
usually you use a tighter tolerance in pFinal. 107
A deeper view to my first OpenFOAM® case setup
The fvSolution dictionary

17 solvers
• To solve U we are using the smoothSolver method, with the
18 { smoother symGaussSeidel, an absolute tolerance equal to
19 p
20 { 1e-08 and a relative tolerance relTol equal to 0.
21 solver PCG;
22 preconditioner DIC; • The solvers will iterative until reaching any of the tolerance
23 tolerance 1e-06;
24 relTol 0; values set by the user or reaching a maximum value of
39 }
iterations (optional entry).
40
41 pFinal • FYI, solving for the velocity is relative inexpensive, whereas
42
43
{
$p;
solving for the pressure is expensive.
44 relTol 0;
45 } • The PISO sub-dictionary contains entries related to the
46
47 U
pressure-velocity coupling method (the PISO method).
48 {
49 solver smoothSolver; • In this case we are doing only one PISO correction and no
50 smoother symGaussSeidel;
51 tolerance 1e-08;
orthogonal corrections.
52 relTol 0;
53 } • You need to do at least one PISO loop (nCorrectors).
54 }
55
56 PISO
57 {
58 nCorrectors 1;
59 nNonOrthogonalCorrectors 0;
60 pRefCell 0;
61 pRefValue 0;
62 }

108
A deeper view to my first OpenFOAM® case setup
The system directory
(optional dictionary files)

• In the system directory you will also find these two additional files:
• decomposeParDict
• sampleDict

• decomposeParDict is read by the utility decomposePar. This dictionary


file contains information related to the mesh partitioning. This is used when
running in parallel. We will address running in parallel later.
• sampleDict is read by the utility postProcess. This utility sample field
data (points, lines or surfaces). In this dictionary file we specify the sample
location and the fields to sample. The sampled data can be plotted using
gnuplot or Python.

109
A deeper view to my first OpenFOAM® case setup
The sampleDict dictionary
Type of sampling, sets will sample along a line.
Format of the output file, raw format is a generic format
17 type sets; that can be read by many applications. The output file is
18
19 setFormat raw;
human readable (ascii format).
20
23 interpolationScheme cellPointFace; Interpolation method at the solution level (location of the
24
26 fields interpolation points).
27 (
28 U Fields to sample.
29 );
30
31 sets
32 (
33 Sample method. How to interpolate the solution to the
34
35
l1
{
sample entity (line in this case)
38 type lineFace;
43 axis x;
44 start ( -1 0.5 0); Location of the sample line. We define start and end
45
46 }
end ( 2 0.5 0); point, and the axis of the sampling.
47
48 l2
49 {
52
57
type
axis
lineFace;
y;
Sample method from the solution to the line.
58 start (0.5 -1 0);
59 end (0.5 2 0);
60 }
61
62 );
Location of the sample line. We define start and end
point, and the axis of the sampling.

110
A deeper view to my first OpenFOAM® case setup
The sampleDict dictionary

The sampled information is always saved in the


directory,
17 type sets;
18 postProcessing/name_of_input_dictionary
19 setFormat raw;
20
23 interpolationScheme cellPointFace;
24
26
27
fields
(
As we are sampling the latest time solution (50) and
28 U using the dictionary sampleDict, the sampled data
29 );
30 will be located in the directory:
31 sets
32
33
(
postProcessing/sampleDict/50
34 l1
35 {
38 type lineFace;
43 axis x;
44 start ( -1 0.5 0); The files l1_U.xy and l2_U.xy located in the
45
46 }
end ( 2 0.5 0);
directory postProcessing/sampleDict/50
47
48 l2 contain the sampled data. Feel free to open them using
49
52
{
type lineFace;
your favorite text editor.
57 axis y;
58 start (0.5 -1 0);
59 end (0.5 2 0);
60 }
61 Name of the output file
62 );

Name of the output file


111
A deeper view to my first OpenFOAM® case setup
The 0 directory
(and by the way, open each file and go thru its content)

• The 0 directory contains the initial and boundary conditions for all primitive variables,
in this case p and U. The U file contains the following information (velocity vector):

17 dimensions [0 1 -1 0 0 0 0]; Dimensions of the field


18
19 internalField uniform (0 0 0);
20
21 boundaryField
22 {
23 movingWall
24 { Uniform initial conditions.
25 type fixedValue;
26 value uniform (1 0 0); The velocity field is initialize to (0 0 0) in all
27 }
28
the domain
29 fixedWalls
Remember velocity is a vector with three
30 {
31 type fixedValue; components, therefore the notation (0 0 0).
32 value uniform (0 0 0);
33 }
34
35 frontAndBack Note:
If you take some time and compare the files 0/U and
36 {
constant/polyMesh/boundary, you will see that the name and type of each
37 type empty;
numerical type patch (the patch defined in 0/U), is consistent with the base
38 } type patch (the patch defined in the file constant/polyMesh/boundary).
39 }

112
A deeper view to my first OpenFOAM® case setup
The 0 directory
(and by the way, open each file and go thru its content)

• The 0 directory contains the initial and boundary conditions for all primitive variables,
in this case p and U. The U file contains the following information (velocity):

17 dimensions [0 1 -1 0 0 0 0]; Dimensions of the field


18
19 internalField uniform (0 0 0);
20
21 boundaryField
22 {
23 movingWall
24 {
25 type fixedValue; Numerical boundary condition for the patch
26 value uniform (1 0 0); movingWall
27 }
28
29 fixedWalls
30 {
31 type fixedValue; Numerical boundary condition for the patch
32 value uniform (0 0 0); fixedWalls
33 }
34
35 frontAndBack
36 {
37 type empty;
Numerical boundary condition for the patch
38 } frontAndBack (this is a constrained boundary
39 } condition).
113
A deeper view to my first OpenFOAM® case setup
The 0 directory
(and by the way, open each file and go thru its content)

• The 0 directory contains the initial and boundary conditions for all primitive variables,
in this case p and U. The p file contains the following information (modified pressure):

17 dimensions [0 2 -2 0 0 0 0]; Dimensions of the field


18
19 internalField uniform 0;
20
21 boundaryField
22 {
23 movingWall
24 { Uniform initial conditions.
25 type zeroGradient;
26 } The modified pressure field is initialize to 0
27
28 fixedWalls
in all the domain. This is relative
29 { pressure.
30 type zeroGradient;
31 }
32
33 frontAndBack
34 {
35 type empty; Note:
If you take some time and compare the files 0/p and
36 }
constant/polyMesh/boundary, you will see that the name and type of each
37 }
numerical type patch (the patch defined in 0/p), is consistent with the base
38 type patch (the patch defined in the file constant/polyMesh/boundary).

114
A deeper view to my first OpenFOAM® case setup
The 0 directory
(and by the way, open each file and go thru its content)

• The 0 directory contains the initial and boundary conditions for all primitive variables,
in this case p and U. The p file contains the following information (modified pressure):

17 dimensions [0 2 -2 0 0 0 0]; Dimensions of the field


18
19 internalField uniform 0;
20
21 boundaryField
22 {
23 movingWall
24 {
25 type zeroGradient;
Numerical boundary condition for the patch
26 } movingWall
27
28 fixedWalls
29 {
30 type zeroGradient;
Numerical boundary condition for the patch
31 } fixedWalls
32
33 frontAndBack
34 {
35 type empty;
Numerical boundary condition for the patch
36 } frontAndBack (this is a constrained boundary
37 } condition).
38

115
A deeper view to my first OpenFOAM® case setup

A very important remark on the pressure field

• We just used icoFoam which is an incompressible solver.


• Let us be really loud on this. All the incompressible solvers implemented in OpenFOAM®
(icoFoam, simpleFoam, pisoFoam, and pimpleFoam), use the modified pressure, that is,

with units

• Or in OpenFOAM® jargon: dimensions [0 2 -2 0 0 0 0]


• So when visualizing or post processing the results do not forget to multiply the pressure by
the density in order to get the right units of the physical pressure, that is,

• Or in OpenFOAM® jargon: dimensions [1 -1 -2 0 0 0 0]

116
A deeper view to my first OpenFOAM® case setup
• Coming back to the headers, and specifically the headers related to the field variable
dictionaries (e.g. U, p, gradU, and so on).
• In the header of the field variables, the class type should be consistent with the type
of field variable you are using.
• Be careful with this, specially if you are copying and pasting files.
• If the field variable is a scalar, the class should be volScalarField.

/*--------------------------------*- C++ -*----------------------------------*\


| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 8 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

117
A deeper view to my first OpenFOAM® case setup
• If the field variable is a vector, the class should be volVectorField.
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 8 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
object U;
}

• If the field variable is a tensor (e.g. the velocity gradient tensor), the class should be
volTensorField.
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 8 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volTensorField;
object gradU;
} 118
A deeper view to my first OpenFOAM® case setup
The output screen
• Finally, let us talk about the output screen, which shows a lot of information.

Velocity residuals
Simulation time
Courant number
Pressure residuals
No orthogonal corrections
Only one PISO correction
Execution time (wall time)

Continuity errors

Additional information
End of the simulation Minimum and maximum values of each field

119
A deeper view to my first OpenFOAM® case setup
The output screen
• By default, OpenFOAM® does not show the minimum and maximum information. To print out this information,
we use functionObjects. We are going to address functionObjects in detail when we deal with post-
processing and sampling.
• But for the moment, what we need to know is that we add functionObjects at the end of the controlDict
dictionary. In this case, we are using a functionObject that prints the minimum and maximum information of
the selected fields.
• This information complements the residuals information and it is saved in the postProcessing directory. It
gives a better indication of stability, boundedness and consistency of the solution.

49 functions
50 {
51 Name of the folder where the output of
52 /////////////////////////////////////////////////////////////////////////// the functionObject will be saved
53
54 minmaxdomain
55 {
56 type fieldMinMax; functionObject to use
57
58 functionObjectLibs ("libfieldFunctionObjects.so");
59
60 enabled true; //true or false Turn on/off functionObject
61
62 mode component;
63
64 writeControl timeStep;
65 writeInterval 1; Output interval of functionObject
66
67 log true; Save output of the functionObject in a ascii file
68
69 fields (p U); Field variables to sample
70 }
91
92 };
120
A deeper view to my first OpenFOAM® case setup
The output screen
• Another very important output information is the CFL or Courant number.
• The Courant number imposes the CFL number condition, which is the maximum allowable
CFL number a numerical scheme can use. For the n - dimensional case, the CFL number
condition becomes,

• In OpenFOAM®, most of the solvers are implicit, which means they are unconditionally
stable. In other words, they are not constrained to the CFL number condition.
• However, the fact that you are using a numerical method that is unconditionally stable, does
not mean that you can choose a time step of any size.
• The time-step must be chosen in such a way that it resolves the time-dependent features, and it
maintains the solver stability.
• For the moment and for the sake of simplicity, let us try to keep the CFL number below 5.0 and
preferably close to 1.0 (for good accuracy).
• Other properties of the numerical method that you should observe are: conservationess,
boundedness, transportiveness, and accuracy. We are going to address these properties and
the CFL number when we deal with the FVM theory. 121
A deeper view to my first OpenFOAM® case setup
The output screen
• To control the CFL number you can change the time step or you can change the mesh.
• The easiest way is by changing the time step.
• For a time step of 0.01 seconds, this is the output you should get for this case,

Time = 49.99
CFL number at
Courant Number mean: 0.044365026 max: 0.16800273
time step n - 1
smoothSolver: Solving for Ux, Initial residual = 1.1174405e-09, Final residual = 1.1174405e-09, No Iterations 0
smoothSolver: Solving for Uy, Initial residual = 1.4904251e-09, Final residual = 1.4904251e-09, No Iterations 0
DICPCG: Solving for p, Initial residual = 6.7291723e-07, Final residual = 6.7291723e-07, No Iterations 0
time step continuity errors : sum local = 2.5096865e-10, global = -1.7872395e-19, cumulative = 2.6884327e-18
ExecutionTime = 4.47 s ClockTime = 5 s

fieldMinMax minmaxdomain output:


min(p) = -0.37208362 at location (0.025 0.975 0.5)
max(p) = 0.77640927 at location (0.975 0.975 0.5)
min(U) = (0.00028445255 -0.00028138799 0) at location (0.025 0.025 0.5)
max(U) = (0.00028445255 -0.00028138799 0) at location (0.025 0.025 0.5)

Time = 50
CFL number at
Courant Number mean: 0.044365026 max: 0.16800273
smoothSolver: Solving for Ux, Initial residual = 1.0907508e-09, Final residual = 1.0907508e-09, No Iterations 0 time step n
smoothSolver: Solving for Uy, Initial residual = 1.4677462e-09, Final residual = 1.4677462e-09, No Iterations 0
DICPCG: Solving for p, Initial residual = 1.0020944e-06, Final residual = 1.0746895e-07, No Iterations 1
time step continuity errors : sum local = 4.0107145e-11, global = -5.0601748e-20, cumulative = 2.637831e-18
ExecutionTime = 4.47 s ClockTime = 5 s

fieldMinMax minmaxdomain output:


min(p) = -0.37208345 at location (0.025 0.975 0.5)
max(p) = 0.77640927 at location (0.975 0.975 0.5)
min(U) = (0.00028445255 -0.00028138799 0) at location (0.025 0.025 0.5)
max(U) = (0.00028445255 -0.00028138799 0) at location (0.025 0.025 0.5)

122
A deeper view to my first OpenFOAM® case setup
The output screen
• To control the CFL number you can change the time step or you can change the mesh.
• The easiest way is by changing the time step.
• For a time step of 0.1 seconds, this is the output you should get for this case,

Time = 49.9
CFL number at
Courant Number mean: 0.4441161 max: 1.6798756
time step n - 1
smoothSolver: Solving for Ux, Initial residual = 0.00016535808, Final residual = 2.7960145e-09, No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.00015920267, Final residual = 2.7704949e-09, No Iterations 5
DICPCG: Solving for p, Initial residual = 0.0015842846, Final residual = 5.2788554e-07, No Iterations 26
time step continuity errors : sum local = 8.6128916e-09, global = 3.5439859e-19, cumulative = 2.4940081e-17
ExecutionTime = 0.81 s ClockTime = 1 s

fieldMinMax minmaxdomain output:


min(p) = -0.34322821 at location (0.025 0.975 0.5)
max(p) = 0.73453489 at location (0.975 0.975 0.5)
min(U) = (0.0002505779 -0.00025371425 0) at location (0.025 0.025 0.5)
max(U) = (0.0002505779 -0.00025371425 0) at location (0.025 0.025 0.5)

Time = 50
CFL number at
Courant Number mean: 0.44411473 max: 1.6798833
smoothSolver: Solving for Ux, Initial residual = 0.00016378098, Final residual = 2.7690608e-09, No Iterations 5 time step n
smoothSolver: Solving for Uy, Initial residual = 0.00015720331, Final residual = 2.7354499e-09, No Iterations 5
DICPCG: Solving for p, Initial residual = 0.0015662416, Final residual = 5.2290439e-07, No Iterations 26
time step continuity errors : sum local = 8.5379223e-09, global = -3.6676527e-19, cumulative = 2.4573316e-17
ExecutionTime = 0.81 s ClockTime = 1 s

fieldMinMax minmaxdomain output:


min(p) = -0.34244269 at location (0.025 0.975 0.5)
max(p) = 0.73656831 at location (0.975 0.975 0.5)
min(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5)
max(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5)

123
A deeper view to my first OpenFOAM® case setup
The output screen
• To control the CFL number you can change the time step or you can change the mesh.
• The easiest way is by changing the time step.
• For a time step of 0.5 seconds, this is the output you should get for this case,

Time = 2
CFL number at
Courant Number mean: 1.6828931 max: 5.6061178
time step n - 1
smoothSolver: Solving for Ux, Initial residual = 0.96587058, Final residual = 4.9900041e-09, No Iterations 27
smoothSolver: Solving for Uy, Initial residual = 0.88080685, Final residual = 9.7837781e-09, No Iterations 25
DICPCG: Solving for p, Initial residual = 0.95568243, Final residual = 7.9266324e-07, No Iterations 33
time step continuity errors : sum local = 6.3955627e-06, global = 1.3227253e-17, cumulative = 1.4125109e-17
ExecutionTime = 0.04 s ClockTime = 0 s

fieldMinMax minmaxdomain output:


min(p) = -83.486425 at location (0.975 0.875 0.5) Compare these values with the values
max(p) = 33.078468 at location (0.025 0.925 0.5)
of the previous cases. For the
min(U) = (0.1309243 -0.13648118 0) at location (0.025 0.025 0.5)
max(U) = (0.1309243 -0.13648118 0) at location (0.025 0.025 0.5) physics involve these values are
unphysical.
Time = 2.5

Courant Number mean: 8.838997 max: 43.078153


CFL number at
#0 Foam::error::printStack(Foam::Ostream&) at ??:? time step n (way
#1 Foam::sigFpe::sigHandler(int) at ??:? too high)
#2 ? in "/lib64/libc.so.6"
#3 Foam::symGaussSeidelSmoother::smooth(Foam::word const&, Foam::Field<double>&, Foam::lduMatrix const&, Foam::Field<double> const&,
Foam::FieldField<Foam::Field, double> const&, Foam::UPtrList<Foam::lduInterfaceField const> const&, unsigned char, int) at ??:?
#4 Foam::symGaussSeidelSmoother::smooth(Foam::Field<double>&, Foam::Field<double> const&, unsigned char, int) const at ??:?
#5 Foam::smoothSolver::solve(Foam::Field<double>&, Foam::Field<double> const&, unsigned char) const at ??:?
#6 ? at ??:?

The solver crashed.


The offender? Time step too large.

124
A deeper view to my first OpenFOAM® case setup
The output screen
• Another output you should monitor are the continuity errors.
• These numbers should be small (it does not matter if they are negative or positive).
• If these values increase in time (about the order of 1e-2), you better control the case setup because
something is wrong.
• The continuity errors are defined in the following file
$WM_PROJECT_DIR/src/finiteVolume/cfdTools/incompressible/continuityErrs.H

Time = 50

Courant Number mean: 0.44411473 max: 1.6798833


smoothSolver: Solving for Ux, Initial residual = 0.00016378098, Final residual = 2.7690608e-09, No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.00015720331, Final residual = 2.7354499e-09, No Iterations 5
DICPCG: Solving for p, Initial residual = 0.0015662416, Final residual = 5.2290439e-07, No Iterations 26
time step continuity errors : sum local = 8.5379223e-09, global = -3.6676527e-19, cumulative = 2.4573316e-17
ExecutionTime = 0.81 s ClockTime = 1 s

fieldMinMax minmaxdomain output:


min(p) = -0.34244269 at location (0.025 0.975 0.5)
max(p) = 0.73656831 at location (0.975 0.975 0.5)
min(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5)
max(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5) Continuity errors

125
A deeper view to my first OpenFOAM® case setup
Error output
• If you forget a keyword or a dictionary file, give a wrong option to a compulsory or optional entry,
misspelled something, add something out of place in a dictionary, use the wrong dimensions,
forget a semi-colon and so on, OpenFOAM® will give you the error FOAM FATAL IO ERROR.
• This error does not mean that the actual OpenFOAM® installation is corrupted. It is telling you
that you are missing something or something is wrong in a dictionary.
• Maybe the guys of OpenFOAM® went a little bit extreme here.

/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 8 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 5.x-5d8318b22cbe
Exec : icoFoam
Date : Nov 02 2014
Time : 00:33:41
Host : "linux-cfd"
PID : 3675
Case : /home/cfd/my_cases_course/cavity
nProcs : 1
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time

--> FOAM FATAL IO ERROR:

126
A deeper view to my first OpenFOAM® case setup
Error output
• Also, before entering into panic read carefully the output screen because OpenFOAM® is telling
you what is the error and how to correct it.

Build : 6.x-5d8318b22cbe
Exec : icoFoam
Date : Nov 02 2014
Time : 00:33:41
Host : "linux-cfd"
PID : 3675
Case : /home/cfd/my_cases_course/cavity
nProcs : 1
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time

--> FOAM FATAL IO ERROR:

banana_endTime is not in enumeration: The origin of the error


4
(
endTime
nextWrite Possible options to correct the error
noWriteNow
writeNow
)

file: /home/cfd/my_cases_course/cavity/system/controlDict.stopAt at line 24. Location of the error

From function NamedEnum<Enum, nEnum>::read(Istream&) const


in file lnInclude/NamedEnum.C at line 72.

FOAM exiting

127
A deeper view to my first OpenFOAM® case setup
Error output
• It is very important to read the screen and understand the output.

“E perience is simply the name we give our mistakes.”

• Train yourself to identify the errors. Hereafter we list a few possible errors.
• Missing compulsory file p

--> FOAM FATAL IO ERROR:


cannot find file

file: /home/joegi/my_cases_course/6/101OF/cavity/0/p at line 0.

From function regIOobject::readStream()


in file db/regIOobject/regIOobjectRead.C at line 73.

FOAM exiting

128
A deeper view to my first OpenFOAM® case setup
Error output
• Mismatching patch name in file p

--> FOAM FATAL IO ERROR:


Cannot find patchField entry for xmovingWall

file: /home/joegi/my_cases_course/6/101OF/cavity/0/p.boundaryField from line 25 to line 35.

From function GeometricField<Type, PatchField, GeoMesh>::GeometricBoundaryField::readField(const


DimensionedField<Type, GeoMesh>&, const dictionary&)
in file /home/joegi/OpenFOAM/OpenFOAM-6/src/OpenFOAM/lnInclude/GeometricBoundaryField.C at line 209.

FOAM exiting

• Missing compulsory keyword in fvSchemes

--> FOAM FATAL IO ERROR:


keyword div(phi,U) is undefined in dictionary
"/home/joegi/my_cases_course/6/101OF/cavity/system/fvSchemes.divSchemes"

file: /home/joegi/my_cases_course/6/101OF/cavity/system/fvSchemes.divSchemes from line 30 to line 30.

From function dictionary::lookupEntry(const word&, bool, bool) const


in file db/dictionary/dictionary.C at line 442.

FOAM exiting

129
A deeper view to my first OpenFOAM® case setup
Error output
• Missing entry in file fvSolution at keyword PISO
--> FOAM FATAL IO ERROR:
"ill defined primitiveEntry starting at keyword 'PISO' on line 68 and ending at line 68"

file: /home/joegi/my_cases_course/6/101OF/cavity/system/fvSolution at line 68.

From function primitiveEntry::readEntry(const dictionary&, Istream&)


in file lnInclude/IOerror.C at line 132.

FOAM exiting

• Incompatible dimensions. Likely the offender is the file U


--> FOAM FATAL ERROR:
incompatible dimensions for operation
[U[0 1 -2 1 0 0 0] ] + [U[0 1 -2 2 0 0 0] ]

From function checkMethod(const fvMatrix<Type>&, const fvMatrix<Type>&)


in file /home/joegi/OpenFOAM/OpenFOAM-6/src/finiteVolume/lnInclude/fvMatrix.C at line 1295.

FOAM aborting

#0 Foam::error::printStack(Foam::Ostream&) at ??:?
#1 Foam::error::abort() at ??:?
#2 void Foam::checkMethod<Foam::Vector<double> >(Foam::fvMatrix<Foam::Vector<double> > const&,
Foam::fvMatrix<Foam::Vector<double> > const&, char const*) at ??:?
#3 ? at ??:?
#4 ? at ??:?
#5 __libc_start_main in "/lib64/libc.so.6"
#6 ? at /home/abuild/rpmbuild/BUILD/glibc-2.19/csu/../sysdeps/x86_64/start.S:125
Aborted 130
A deeper view to my first OpenFOAM® case setup
Error output
• Missing keyword deltaT in file controlDict

--> FOAM FATAL IO ERROR:


keyword deltaT is undefined in dictionary "/home/joegi/my_cases_course/6/101OF/cavity/system/controlDict"

file: /home/joegi/my_cases_course/6/101OF/cavity/system/controlDict from line 17 to line 69.

From function dictionary::lookupEntry(const word&, bool, bool) const


in file db/dictionary/dictionary.C at line 442.

FOAM exiting

• Missing file points in directory polyMesh. Likely you are missing the mesh.

--> FOAM FATAL ERROR:


Cannot find file "points" in directory "polyMesh" in times 0 down to constant

From function Time::findInstance(const fileName&, const word&, const IOobject::readOption, const word&)
in file db/Time/findInstance.C at line 203.

FOAM exiting

131
A deeper view to my first OpenFOAM® case setup
Error output
• Unknown boundary condition type.

--> FOAM FATAL IO ERROR:


Unknown patchField type sfixedValue for patch type wall

Valid patchField types are :

74
(
SRFFreestreamVelocity
SRFVelocity
SRFWallVelocity
activeBaffleVelocity

...
...
...

variableHeightFlowRateInletVelocity
waveTransmissive
wedge
zeroGradient
)

file: /home/joegi/my_cases_course/6/101OF/cavity/0/U.boundaryField.movingWall from line 25 to line 26.

From function fvPatchField<Type>::New(const fvPatch&, const DimensionedField<Type, volMesh>&, const


dictionary&)
in file /home/joegi/OpenFOAM/OpenFOAM-6/src/finiteVolume/lnInclude/fvPatchFieldNew.C at line 143.

FOAM exiting

132
A deeper view to my first OpenFOAM® case setup
Error output
• This one is especially hard to spot

/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 8 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 6.x-5d8318b22cbe
Exec : icoFoam
Date : Nov 02 2014
Time : 00:33:41
Host : "linux-cfd"
PID : 3675
fileName::stripInvalid() called for invalid fileName /home/cfd/my_cases_course/cavity0
For debug level (= 2) > 1 this is considerd fatal
Aborted

• This error is related to the name of the working directory. In this case the name of the
working directory is cavity 0 (there is a blank space between the word cavity and
the number 0).
• Do not use blank spaces or funny symbols when naming directories and files.
• Instead of cavity 0 you could use cavity_0.
133
A deeper view to my first OpenFOAM® case setup
Error output
• You should worry about the SIGFPE error signal. This error signal indicates that something
went really wrong (erroneous arithmetic operation).
• This message (that seems a little bit difficult to understand), is giving you a lot information.
• For instance, this output is telling us that the error is due to SIGFPE and the class associated to
the error is lduMatrix. It is also telling you that the GAMGSolver solver is the affected one
(likely the offender is the pressure).

#0 Foam::error::printStack(Foam::Ostream&) at ??:?
#1 Foam::sigFpe::sigHandler(int) at ??:?
#2 in "/lib64/libc.so.6"
#3 Foam::DICPreconditioner::calcReciprocalD(Foam::Field<double>&, Foam::lduMatrix const&) at ??:?
#4 Foam::DICSmoother::DICSmoother(Foam::word const&, Foam::lduMatrix const&, Foam::FieldField<Foam::Field, double>
const&, Foam::FieldField<Foam::Field, double> const&, Foam::UPtrList<Foam::lduInterfaceField const> const&) at ??:?
#5 Foam::lduMatrix::smoother::addsymMatrixConstructorToTable<Foam::DICSmoother>::New(Foam::word const&,
Foam::lduMatrix const&, Foam::FieldField<Foam::Field, double> const&, Foam::FieldField<Foam::Field, double> const&,
Foam::UPtrList<Foam::lduInterfaceField const> const&) at ??:?
#6 Foam::lduMatrix::smoother::New(Foam::word const&, Foam::lduMatrix const&, Foam::FieldField<Foam::Field, double>
const&, Foam::FieldField<Foam::Field, double> const&, Foam::UPtrList<Foam::lduInterfaceField const> const&,
Foam::dictionary const&) at ??:?
#7 Foam::GAMGSolver::initVcycle(Foam::PtrList<Foam::Field<double> >&, Foam::PtrList<Foam::Field<double> >&,
Foam::PtrList<Foam::lduMatrix::smoother>&, Foam::Field<double>&, Foam::Field<double>&) const at ??:?
#8 Foam::GAMGSolver::solve(Foam::Field<double>&, Foam::Field<double> const&, unsigned char) const at ??:?
#9 Foam::fvMatrix<double>::solveSegregated(Foam::dictionary const&) at ??:?
#10 Foam::fvMatrix<double>::solve(Foam::dictionary const&) at ??:?
#11
at ??:?
#12 __libc_start_main in "/lib64/libc.so.6"
#13
at /home/abuild/rpmbuild/BUILD/glibc-2.17/csu/../sysdeps/x86_64/start.S:126
Floating point exception 134
A deeper view to my first OpenFOAM® case setup
Dictionary files general features

• OpenFOAM® follows same general syntax rules as in C++.


• Commenting in OpenFOAM® (same as in C++):

/*
// This is a line comment This is a block comment
*/

• As in C++, you can use the #include directive in your dictionaries (do not forget to create the respective include file):
#include “ n t C nd t n ”

• Scalars, vectors, lists and dictionaries.


• Scalars in OpenFOAM® are represented by a single value, e.g.,
3.14159
• Vectors in OpenFOAM® are represented as a list with three components, e.g.,
(1.0 0.0 0.0)
• A second order tensor in OpenFOAM® is represented as a list with nine components, e.g.,
(
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
)

135
A deeper view to my first OpenFOAM® case setup
Dictionary files general features

• Scalars, vectors, lists and dictionaries.


• List entries are contained within parentheses ( ). A list can contain scalars, vectors, tensors, words, and so on.
• A list of scalars is represented as follows:
name_of_the_list
(
0
1
2
);

• A list of vectors is represented as follows:


name_of_the_list
(
(0 0 0)
(1 0 0)
(2 0 0)
);

• A list of words is represented as follows


name_of_the_list
(
“ rd1”
“ rd2”
“ rd3”
);
136
A deeper view to my first OpenFOAM® case setup
Dictionary files general features
• OpenFOAM® uses dictionaries to specify data in an input file (dictionary file).
• A dictionary in OpenFOAM® can contain multiple data entries and at the same time dictionaries can contain
sub-dictionaries.
• To specify a dictionary entry, the name is followed by the keyword entries in curly braces:

solvers Dictionary solvers


{
p Sub-dictionary p
{
solver PCG;
preconditioner DIC;
tolerance 1e-06;
relTol 0;
}

U Sub-dictionary U
{
solver PBiCGStab;
preconditioner DILU;
tolerance 1e-06;
relTol 0;
}



} 137
A deeper view to my first OpenFOAM® case setup
Dictionary files general features

• Macro expansion.
• We first declare a variable (x = 10) and then we use it through the $ macro substitution ($x).

vectorField (20 0 0); //Declare variable

internalField uniform $vectorField; //Use declared variable

scalarField 101328; //Declare variable

type fixedValue;
value uniform $scalarField; //Use declared variable

• You can use macro expansion to duplicate and access variables in dictionaries

p // Declare/create the dictionary p


{
solver PCG;
preconditioner DIC;
tolerance 1e-06;
relTol 0;
}

$p; //To create a copy of the dictionary p


$p.solver; //To access the variable solver in the dictionary p
138
A deeper view to my first OpenFOAM® case setup
Dictionary files general features

• In tead of writing t e poor an’ way :

leftWall rightWall topWall


{ { {
type fixedValue; type fixedValue; type fixedValue;
value uniform (0 0 0); value uniform (0 0 0); value uniform (0 0 0);
} } }

• You can write (the lazy way):

“( eft|r ght|t )W ”
{
type fixedValue;
value uniform (0 0 0);
}

• You could also try (even lazier):

“.*W ”
{
type fixedValue;
value uniform (0 0 0);
}

• OpenFOAM® understands the syntax of regular expressions (regex or regeaxp).


139
A deeper view to my first OpenFOAM® case setup
Dictionary files general features

• Inline calculations.
• You can use the directive #calc to do inline calculations, the syntax is as follows:
X = 10.0; //Declare variable
Y = 3.0; //Declare variable

Z #c c “$ *$ – 12.0”; //Do inline calculation. The result is saved in the variable Z

• With inline calculations you can access all the mathematical functions available in C++.
• Macro expansions and inline calculations are very useful to parametrize dictionaries and avoid repetitive tasks.
• Switches: they are used to enable or disable a function or a feature in the dictionaries.
• Switches are logical values. You can use the following values:

Switches
false true
off on
no yes
n y
f t
none true

• You can find all the valid switches in the following file:
OpenFOAM-6/src/OpenFOAM/primitives/bools/Switch/Switch.C 140
A deeper view to my first OpenFOAM® case setup
Solvers and utilities help

• If you need help about a solver or utility, you can use the option –help. For
instance:

• $> icoFoam –help

will print some basic help and usage information about icoFoam

• Remember, you have the source code there so you can always
check the original source.

141
A deeper view to my first OpenFOAM® case setup
Solvers and utilities help
• To get more information about the boundary conditions, post-processing utilities, and the API read the
Doxygen documentation.
• If you did not compile the Doxygen documentation, you can access the information online,
http://cpp.openfoam.org/v6/

API documentation

Boundary conditions and post-processing


utilities documentation

142
A deeper view to my first OpenFOAM® case setup
Exercises
• Run the case with Re = 10 and Re = 1000. Feel free to change any variable to achieve the Re value (velocity,
viscosity or length). Do you see an unsteady behavior in any of the cases? What about the computing time,
what simulation is faster?
• Run the tutorial with Re = 100, a mesh with 120 x 120 x 1 cells, and using the default setup (original
controlDict, fvSchemes and fvSolution). Did the simulation converge? Did it crash? Any comments.
• If your simulation crashed, try to solve the problem.
(Hint: try to reduce the time-step to get a CFL less than 1)
• Besides reducing the time-step, can you find another solution?
(Hint: look at the PISO options)
• Change the base type of the boundary patch movingWall to patch. (the boundary file). Do you get the same
results? Can you comment on this?
• Try to extent the problem to 3D and use a uniform mesh (20 x 20 x 20). Compare the solution at the mid
section of the 3D simulation with the 2D solution. Are the solutions similar?
• How many time discretization schemes are there in OpenFOAM®? Try to use a different discretization
scheme.
• Run the simulation using Gauss upwind instead of Gauss linear for the term div(phi,U) (fvSchemes). Do
you get the same quantitative results?
• Sample the field variables U and P at a different location and plot the results using gnuplot.
• What density value do you think we were using? What about dynamic viscosity?
Hint: the physical pressure is equal to the modified pressure and 143
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

144
3D Dam break – Free surface flow

Dam break free surface flow

Physical and numerical side of the


Box with open top problem:
Gravity • In this case we are going to use the volume of
fluid (VOF) method.
• This method solves the incompressible Navier-
Stokes equations plus an additional equation to
track the phases (free surface location).
• As this is a multiphase case, we need to define
the physical properties for each phase involved
(viscosity, density and surface tension).
• The working fluids are water and air.
• Additionally, we need to define the gravity vector
Water column and initialize the two flows.
• This is a three-dimensional and unsteady case.

Obstacle • The details of the case setup can be found in


the following reference:
A Volume-of-Fluid Based Simulation Method for Wave
Impact Problems.
Journal of Computational Physics 206(1):363-393.
June, 2005.
145
3D Dam break – Free surface flow

Workflow of the case

blockMesh
+
snappyHexMesh

setFields

interFoam functionObjects

sampling paraview

146
3D Dam break – Free surface flow

At the end of the day, you should get something like this

Initial conditions – Coarse mesh Solution at Time = 1 second – Coarse mesh

147
3D Dam break – Free surface flow

VOF Fraction (Free surface tracking) – Very fine mesh


http://www.wolfdynamics.com/validations/3d_db/dbreak.gif

148
3D Dam break – Free surface flow

• Let us run this case. Go to the directory:

$PTOFC/101OF/3d_damBreak

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.

149
3D Dam break – Free surface flow

What are we going to do?

• We will use this case to introduce the multiphase solver interFoam.


• interFoam is a solver for 2 incompressible, isothermal immiscible fluids using a VOF
(volume of fluid) phase-fraction based interface capturing approach
• We will define the physical properties of two phases, and we are going to initialize
these phases.
• We will define the gravity vector in the dictionary g.
• After finding the solution, we will visualize the results. This is an unsteady case so
now we are going to see things moving.
• We are going to briefly address how to post-process multiphase flows.
• We are going to generate the mesh using snappyHexMesh, but for the purpose of this
tutorial we are not going to discuss the dictionaries.
• Remember, different solvers have different input dictionaries.

150
3D Dam break – Free surface flow
The constant directory

• In this directory, we will find the following compulsory dictionary files:

• g
• transportProperties
• momentumTransport

• g contains the definition of the gravity vector.


• transportProperties contains the definition of the physical properties of
each phase.
• momentumTransport contains the definition of the turbulence model to use.

151
3D Dam break – Free surface flow
The g dictionary file

• This dictionary file is located in the directory


8
9
FoamFile
{
constant.
10 version 2.0;
11
12
format
class
ascii;
uniformDimensionedVectorField; • For multiphase flows, this dictionary is
13
14
location
object
"constant";
g;
compulsory.
15 }
17
18 dimensions [0 1 -2 0 0 0 0];
• In this dictionary we define the gravity vector (line
19 value (0 0 -9.81);
19).
• Pay attention to the class type (line 12).

152
3D Dam break – Free surface flow
The transportProperties dictionary file
Primary phase

• This dictionary file is located in the directory


17
18
phases (water air);
constant.
19 water
20
21
{
transportModel Newtonian; • We first define the name of the phases (line 17).
22
23
nu
rho
[0 2 -1 0 0 0 0] 1e-06;
[1 -3 0 0 0 0 0] 1000;
In this case we are defining the names water and
24
25
}
air. The first entry in this list is the primary phase
26
27
air
{
(water).
28 transportModel Newtonian;
29
30
nu
rho
[0 2 -1 0 0 0 0] 1.48e-05;
[1 -3 0 0 0 0 0] 1;
• The name of the primary phase is the one you will
31 } use to initialize the solution.
32
33 sigma [1 0 -2 0 0 0 0] 0.07;
• The name of the phases is given by the user.
• In this file we set the kinematic viscosity (nu),
density (rho) and transport model
(transportModel) of the phases.
• We also define the surface tension (sigma).

153
3D Dam break – Free surface flow
The momentumTransport dictionary file
• In this dictionary file we select what model we would like to use (laminar or
turbulent).
• This dictionary is compulsory.
• In this case we use a RANS turbulence model (kEpsilon).

17 simulationType RAS;
18
19 RAS
20 {
21 RASModel kEpsilon;
22
23 turbulence on;
24
25 printCoeffs on;
26 }

154
3D Dam break – Free surface flow
The 0 directory

• In this directory, we will find the dictionary files that contain the boundary and
initial conditions for all the primitive variables.
• As we are solving the incompressible RANS Navier-Stokes equations using
the VOF method, we will find the following field files:

• alpha.water (volume fraction of water phase)


• p_rgh (pressure field minus hydrostatic component)
• U (velocity field)
• k (turbulent kinetic energy field)
• epsilon (rate of dissipation of turbulence energy field)
• nut (turbulence viscosity field)

155
3D Dam break – Free surface flow
The file 0/alpha.water

17 dimensions [0 0 0 0 0 0 0];
18 • This file contains the boundary and initial conditions
19
20
internalField uniform 0; for the non-dimensional scalar field alpha.water
21 boundaryField
22 { • This file is named alpha.water, because the
23
24
front
{
primary phase is water (we defined the primary
25 type zeroGradient; phase in the transportProperties dictionary).
26 }
27
28
back
{
• Initially, this field is initialized as 0 in the whole
29 type zeroGradient; domain (line 19). This means that there is no water in
30 }
31 left the domain at time 0. Later, we will initialize the
32
33
{
type zeroGradient;
water column and this file will be overwritten with a
34 } non-uniform field for the internalField.
35 right
36
37
{
type zeroGradient;
• For the front, back, left, right, bottom and
38 } stlSurface patches we are using a zeroGradient
39 bottom
40 { boundary condition (we are just extrapolating the
41 type zeroGradient; internal values to the boundary face).
42 }
43 top
44 { • For the top patch we are using an inletOutlet
45
46
type
inletValue
inletOutlet;
uniform 0;
boundary condition. This boundary condition avoids
47 value uniform 0; backflow into the domain. If the flow is going out it
48 }
49 stlSurface will use zeroGradient and if the flow is coming back
50 { it will assign the value set in the keyword inletValue
51 type zeroGradient;
52 } (line 46).
53
54 }

156
3D Dam break – Free surface flow
The file 0/p_rgh

17 dimensions [1 -1 -2 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0;
20 for the dimensional scalar field p_rgh. The
21
22
boundaryField
{
dimensions of this field are given in Pascal (line 17)
23 front
24 { • This scalar field contains the value of the static
25
26
type
value
fixedFluxPressure;
uniform 0;
pressure field minus the hydrostatic component.
27 }
28 back • This field is initialized as 0 in the whole domain (line
33 left
19).
38 right • For the front, back, left, right, bottom and
43 bottom
stlSurface patches we are using the
fixedFluxPressure boundary condition (refer to the
48 top
49 { source code or doxygen documentation to know
50
51
type
p0
totalPressure;
uniform 0;
more about this boundary condition).
52 U U;
53 phi phi; • For the top patch we are using the totalPressure
54
55
rho
psi
rho;
none;
boundary condition (refer to the source code or
56 gamma 1; doxygen documentation to know more about this
57 value uniform 0;
58 } boundary condition).
59 stlSurface
60 {
61 type fixedFluxPressure;
62 value uniform 0;
63 }
64
65 }

157
3D Dam break – Free surface flow
The file 0/U

17 dimensions [0 -1 -1 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform (0 0 0);
20 for the dimensional vector field U.
21 boundaryField
22 { • We are using uniform initial conditions and the
23 front
24 { numerical value is (0 0 0) (keyword internalField in
25
26
type
value
fixedValue;
uniform (0 0 0);
line 19).
27 }
28 back • The front, back, left, right, bottom and stlSurface
33 left
patches are no-slip walls, therefore we impose a
fixedValue boundary condition with a value of (0 0 0)
38 right
at the wall.
43 bottom
• For the top patch we are using the
48 top
49 { pressureInlterOutletVelocity boundary condition
50
51
type
value
pressureInletOutletVelocity;
uniform (0 0 0);
(refer to the source code or doxygen documentation
52 } to know more about this boundary condition).
53 stlSurface
54 {
55 type fixedValue;
56 value uniform (0 0 0);
57 }
58
59 }

158
3D Dam break – Free surface flow
The file 0/k

17 dimensions [0 2 -2 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0.1;
20 for the dimensional scalar field k.
21 boundaryField
22 { • This scalar (turbulent kinetic energy), is related to the
23 “(front|back|left|right|bottom|stlSurface)”
24 { turbulence model.
25 type kqRWallFunction;
26 value $internalField; • This field is initialized as 0.1 in the whole domain,
27 }
28 and all the boundary patches take the same value
29
30
top
{
($internalField).
31 type inletOutlet;
32 inletValue $internalField; • For the front, back, left, right, bottom and
33
34 }
value $internalField;
stlSurface patches we are using the
35 kqRWallFunction boundary condition, which applies
36 }
a wall function at the walls (refer to the source code
or doxygen documentation to know more about this
boundary condition).
• For the top patch we are using the inletOutlet
boundary condition, this boundary condition handles
backflow (refer to the source code or doxygen
documentation to know more about this boundary
condition).
• We will deal with turbulence modeling later.

159
3D Dam break – Free surface flow
The file 0/epsilon

17 dimensions [0 2 -3 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0.1;
20 for the dimensional scalar field epsilon.
21 boundaryField
22 { • This scalar (rate of dissipation of turbulence energy),
23 “(front|back|left|right|bottom|stlSurface)”
24 { is related to the turbulence model.
25 type epsilonWallFunction;
26 value $internalField; • This field is initialized as 0.1 in the whole domain,
27 }
28 and all the boundary patches take the same value
29
30
top
{
($internalField).
31 type inletOutlet;
32 inletValue $internalField; • For the front, back, left, right, bottom and
33
34 }
value $internalField;
stlSurface patches we are using the
35 epsilonWallFunction boundary condition, which
36 }
applies a wall function at the walls (refer to the
source code or doxygen documentation to know
more about this boundary condition).
• For the top patch we are using the inletOutlet
boundary condition, this boundary condition handles
backflow (refer to the source code or doxygen
documentation to know more about this boundary
condition).
• We will deal with turbulence modeling later.

160
3D Dam break – Free surface flow
The file 0/nut

17 dimensions [0 2 -1 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0;
20 for the dimensional scalar field nut.
21 boundaryField
22 { • This scalar (turbulent viscosity), is related to the
23 “(front|back|left|right|bottom|stlSurface)”
24 { turbulence model.
25 type nutkWallFunction;
26 value $internalField; • This field is initialized as 0 in the whole domain, and
27 }
28 all the boundary patches take the same value
29
30
top
{
($internalField).
31 type calculated;
32 value $internalField;; • For the front, back, left, right, bottom and
33
34
}
stlSurface patches we are using the
35 } nutkWallFunction boundary condition, which applies
a wall function at the walls (refer to the source code
or doxygen documentation to know more about this
boundary condition).
• For the top patch we are using the calculated
boundary condition, this boundary condition
computes the value of nut from k and epsilon (refer to
the source code or doxygen documentation to know
more about this boundary condition).
• We will deal with turbulence modeling later.

161
3D Dam break – Free surface flow
The system directory

• The system directory consists of the following compulsory dictionary files:


• controlDict
• fvSchemes
• fvSolution

• controlDict contains general instructions on how to run the case.


• fvSchemes contains instructions for the discretization schemes that will be
used for the different terms in the equations.
• fvSolution contains instructions on how to solve each discretized linear
equation system.

162
3D Dam break – Free surface flow
The controlDict dictionary
• This case starts from time 0 (startTime), and it will run up to 8
17 application interFoam; seconds (endTime).
18
19
20
startFrom startTime;
• The initial time step of the simulation is 0.0001 seconds
21 startTime 0; (deltaT).
22
23
24
stopAt endTime;
• It will write the solution every 0.02 seconds (writeInterval) of
25 endTime 8; simulation time (runTime). It will automatically adjust the time
26
27 deltaT 0.0001; step (adjustableRunTime), in order to save the solution at the
28
29 writeControl adjustableRunTime;
precise write interval.
30
31 writeInterval 0.02; • It will keep all the solution directories (purgeWrite).
32
33 purgeWrite 0; • It will save the solution in ascii format (writeFormat).
34
35 writeFormat ascii;
36 • The write precision is 8 digits (writePrecision). It will only save
37
38
writePrecision 8; eight digits in the output files.
39 writeCompression uncompressed;
40 • And as the option runTimeModifiable is on, we can modify all
41
42
timeFormat general; these entries while we are running the simulation.
43 timePrecision 8;
44 • In line 47 we turn on the option adjustTimeStep. This option
45
46
runTimeModifiable yes;
will automatically adjust the time step to achieve the maximum
47 adjustTimeStep yes; desired courant number (lines 49-50). We also set a maximum
48
49 maxCo 1.0; time step in line 51.
50 maxAlphaCo 0.5;
51 maxDeltaT 0.01; • Remember, the first time step of the simulation is done using
the value set in line 27 and then it is automatically scaled to
achieve the desired maximum values (lines 49-51).
163
3D Dam break – Free surface flow
The controlDict dictionary

55 functions • Let us take a look at the functionObjects definitions.


56 {
• In lines 60-76 we define the fieldMinMax functionObject
60 minmaxdomain
61 { which computes the minimum and maximum values of
62
63
type fieldMinMax;
the field variables (p p_rgh U alpha.water k epsilon).
64 functionObjectLibs ("libfieldFunctionObjects.so");
65
66 enabled true; //true or false
67
68 mode component;
69
70 writeControl timeStep;
71 writeInterval 1;
72
73 log true;
74
75 fields (p p_rgh U alpha.water k epsilon);
76 }

144 };

164
3D Dam break – Free surface flow
The controlDict dictionary

55 functions • Let us take a look at the functionObjects definitions.


56 {
• In lines 81-102 we define the volRegion functionObject
81 water_in_domain
82 { which computes the volume integral (volIntegrate) of the
83
84
type volRegion;
functionObjectLibs ("libfieldFunctionObjects.so");
field variable alpha.water in all the domain.
85 enabled true;
86 • Basically, we are monitoring the quantity of water in the
87
88
enabled true;
domain.
89 //writeControl outputTime;
90 writeControl timeStep;
91 writeInterval 1;
92
93 log true;
94
95 regionType all;
96
97 operation volIntegrate;
98 fields
99 (
100 alpha.water
101 );
102 }

144 };

165
3D Dam break – Free surface flow
The controlDict dictionary

55 functions • Let us take a look at the functionObjects definitions.


56 {
• In lines 107-131 we define the probes functionObject
107 probes1
108 { which sample the selected fields (lines 124-127) at the
109
110
type probes;
functionObjectLibs ("libsampling.so");
selected locations (lines 112-122).
111
112 pobeLocations • This sampling is done on-the-fly. All the information
113
114
(
(0.82450002 0 0.021)
sample by this functionObject is saved in the directory
115 (0.82450002 0 0.061) ./postProcessing/probes1
116 (0.82450002 0 0.101)
117
118
(0.82450002 0 0.141)
(0.8035 0 0.161)
• As we are sampling starting from time 0, the sampled
119 (0.7635 0 0.161) data will be located in the directory:
120 (0.7235 0 0.161)
121
122 );
(0.6835 0 0.161)
postProcessing/probes1/0
123
124 fields • Feel free to open the files located in the directory
125
126
(
p p_rgh
postProcessing/probes1/0 using your favorite text
127 ); editor.
128
129 writeControl timeStep;
130 writeInterval 1;
131 }

144 };

Sampling locations
(probeLocations)

166
3D Dam break – Free surface flow
The controlDict dictionary

55 functions • Let us take a look at the functionObjects definitions.


56 {
• In lines 135-141 we define the yplus functionObject
135 yplus
136 { which computes the yplus value.
137 type yPlus;
138 functionObjectLibs ("libutilityFunctionObjects.so "); • This quantity is related to the turbulence modeling.
139 enabled true;
140 writeControl outputTime;
141 } • This functionObject will save the yplus field in the
solution directories with the same saving frequency as the
144 };
solution (line 140).
• It will also save the minimum, maximum and mean values
of yplus in the directory:
postProcessing/yplus

167
3D Dam break – Free surface flow
The fvSchemes dictionary

17 ddtSchemes • In this case, for time discretization (ddtSchemes) we are using the
18 {
19 default Euler; Euler method.
21 }
22
• For gradient discretization (gradSchemes) we are using the Gauss
23 gradSchemes linear as the default method and slope limiters (cellLimited) for the
24 { velocity gradient or grad(U).
25 default Gauss linear;
26 grad(U) cellLimited Gauss linear 1; • For the discretization of the convective terms (divSchemes) we are
27 }
28
using linearUpwindV interpolation method for the term
29 divSchemes div(rhoPhi,U).
30 {
31 div(rhoPhi,U) Gauss linearUpwindV grad(U); • For the term div(phi,alpha) we are using interfaceCompression
vanLeer interpolation scheme.
33 div(phi,alpha) Gauss interfaceCompression vanLeer 1;
• This is an interface compression corrected scheme used to
39 div(phi,k) Gauss upwind; maintain sharp interfaces in VOF simulations.
40 div(phi,epsilon) Gauss upwind;
41 div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear; • The coefficient defines the degree of compression, where 1 is
42 }
43
suitable for most VOF applications.
44 laplacianSchemes • For the terms div(phi,k) and div(phi,epsilon) we are using upwind
45 {
46 default Gauss linear corrected; (these terms are related to the turbulence modeling).
47 }
48
• For the term div(((rho*nuEff)*dev2(T(grad(U))))) we are using
49 interpolationSchemes linear interpolation (this term is related to the turbulence modeling).
50 {
51 default linear; • For the discretization of the Laplacian (laplacianSchemes and
52 } snGradSchemes) we are using the Gauss linear corrected method
53
54 snGradSchemes • In overall, this method is second order accurate but a little bit
55 { diffusive. Remember, at the end of the day we want a solution that is
56 default corrected;
57 } second order accurate.

168
3D Dam break – Free surface flow
The fvSolution dictionary

17 solvers • To solve the volume fraction or alpha.water (lines 19-32) we


18
19
{
"alpha.water.*"
are using the smoothSolver method.
20 {
21 nAlphaCorr 3; • In line 25 we turn on the semi-implicit method MULES. The
22
23
nAlphaSubCycles 1;
cAlpha 1;
keyword nLimiterIter controls the number of MULES iterations
24 over the limiter.
25 MULESCorr yes;
26
27
nLimiterIter 10;
• To have more stability it is possible to increase the number of
28 solver smoothSolver; loops and corrections used to solve alpha.water (lines 21-22).
29 smoother symGaussSeidel;
30
31
tolerance
relTol
1e-8;
0;
• The keyword cAlpha (line 23) controls the sharpness of the
32 } interface (1 is usually fine for most cases).
33
34 “(pcorr|pcorrFinal)”
35 {
• In lines 34-40 we setup the solver for pcorr and pcorrFinal
36 solver PCG; (pressure correction).
37 preconditioner DIC;
38 tolerance 1e-8;
39 relTol 0; • In this case pcorr is solved only one time at the beginning of
40 } the computation.
41
42 p_rgh
43 { • In lines 42-49 we setup the solver for p_rgh.
44 solver PCG;
45 preconditioner DIC; • The keyword minIter (line 48), means that the linear solver will
46 tolerance 1e-06;
47 relTol 0.01; do at least one iteration.
48 minIter 1;
49 }

169
3D Dam break – Free surface flow
The fvSolution dictionary

51 p_rghFinal • In lines 51-56 we setup the solver for p_rghFinal. This


52
53
{
$p_rgh;
correspond to the last iteration in the loop (we can use a tighter
54 relTol 0; convergence criteria to get more accuracy without increasing
55 minIter 1;
56 } the computational cost)
57
58 "(U|UFinal)" • In lines 58-72 we setup the solvers for U and UFInal.
59 {
60
61
solver
Preconditioner
PBiCGStab;
DILU;
• In lines 74-80 we setup the solvers for the turbulent quantities,
62 tolerance 1e-08; namely, k and epsilon.
63 relTol 0;
72 }
73
74 "(k|epsilon).*"
75 {
76 solver PBiCGStab;
77 Preconditioner DILU;
78 tolerance 1e-08;
79 relTol 0;
80 }
81 }
82

170
3D Dam break – Free surface flow
The fvSolution dictionary

82 • In lines 83-89 we setup the entries related to the pressure-


83
84
PIMPLE
{
velocity coupling method used (PIMPLE in this case). Setting
85 momentumPredictor yes; the keyword nOuterCorrectors to 1 is equivalent to running
86 nOuterCorrectors 1;
87 nCorrectors 3; using the PISO method.
88 nNonOrthogonalCorrectors 1;
89 } • To gain more stability we can increase the number of correctors
90
91 relaxationFactors (lines 87-88), however this will increase the computational cost.
92 {
93 fields • In lines 91-101 we setup the under-relaxation factors related to
94 {
95 ".*" 0.9; the PIMPLE method outer iterations.
96 }
97 equations • The values defined correspond to the industry standard of
98 {
99 ".*" 0.9; the SIMPLEC method.
100 }
101 } • By using under-relaxation we ensure diagonal equality.
102

• Be careful not use too low values as you will loose time
accuracy.
• If you want to disable under-relaxation, comment out
these lines.
• The option momentumPredictor (line 85), is recommended for
highly convective flows.

171
3D Dam break – Free surface flow
The system directory

• In the system directory you will find the following optional dictionary files:
• decomposeParDict
• setFieldsDict

• decomposeParDict is read by the utility decomposePar. This dictionary


file contains information related to the mesh partitioning. This is used when
running in parallel.
• setFieldsDict is read by the utility setFields. This utility set values on
selected cells/faces.

172
3D Dam break – Free surface flow
The setFieldsDict dictionary
• This dictionary file is located in the directory system.
• In lines 17-20 we set the default value to be 0 in the whole
17 defaultFieldValues domain (no water).
18 (
19
20 );
volScalarFieldValue alpha.water 0
• In lines 22-32, we initialize a rectangular region (box)
21 containing water (alpha.water 1).
22 regions
23
24
(
boxToCell
• In this case, setFields will look for the dictionary file
25 { alpha.water and it will overwrite the original values
26 box (1.992 -10 0) (5 10 0.55);
27 fieldValues according to the regions defined in setFieldsDict.
28 (
29 volScalarFieldValue alpha.water 1 • We initialize the water phase because is the primary phase in
30 );
31 } the dictionary transportProperties.
32 );
• If you are interested in initializing the vector field U, you can
proceed as follows volVectorFieldValue U (0 0 0)

Air
alpha.water = 0

Water
alpha.water = 1

boxToCell region
173
3D Dam break – Free surface flow
The decomposeParDict dictionary
• This dictionary file is located in the directory system.
• This dictionary is used to decompose the domain in order to run in parallel.
• The keyword numberOfSubdomains (line 17) is used to set the number of cores we want to use in the
parallel simulation.
• In this dictionary we also set the decomposition method (line 19).
• Most of the times the scotch method is fine.
• In this case we set the numberOfSubdomains to 4, therefore we will run in parallel using 4 cores.

17 numberOfSubdomains 4;
18
19 method scotch;
20

• When you run in parallel, the solution is saved in the directories processorN, where N stands for processor
number. In this case you will find the following directories with the decomposed mesh and solution:
processor0, processor1, processor2, and processor3.
174
3D Dam break – Free surface flow

Running the case

• Let us first generate the mesh.


• To generate the mesh will use snappyHexMesh (sHM), do not worry we will talk about
sHM tomorrow.

1. $> foamCleanTutorials
2. $> rm –rf 0
3. $> blockMesh
4. $> surfaceFeatures
5. $> snappyHexMesh -overwrite
6. $> createPatch -dict system/createPatchDict.0 -overwrite
7. $> createPatch -dict system/createPatchDict.1 -overwrite
8. $> checkMesh
9. $> paraFoam

175
3D Dam break – Free surface flow

Running the case


• Let us run the simulation in parallel using the solver interFoam.
• We will talk more about running in parallel tomorrow
• To run the case, type in the terminal:

1. $> rm –rf 0
2. $> cp –r 0_org 0
3. $> setFields
4. $> paraFoam
5. $> decomposePar
6. $> mpirun –np 4 interFoam –parallel | tee log.interFoam
7. $> reconstructPar
8. $> paraFoam

176
3D Dam break – Free surface flow

Running the case


• In steps 1-2 we copy the information of the backup directory 0_org into the directory
0. We do this because in the next step the utility setFields will overwrite the file
0/alpha.water, so it is a good idea to keep a backup.
• In step 3 we initialize the solution using the utility setFields. This utility reads the
dictionary setFieldsDict located in the system directory.
• In step 4 we visualize the initialization using paraFoam.
• In step 5 we use the utility decomposePar to do the domain decomposition needed
to run in parallel.
• In step 6 we run the simulation in parallel. Notice that np means number of
processors and the value used should be the same number as the one you set in the
dictionary decomposeParDict.
• If you want to run in serial, type in the terminal: interFoam | tee log
• In step 7 we reconstruct the parallel solution. This step is only needed if you are
running in parallel.
• Finally, in step 8 we visualize the solution.

177
3D Dam break – Free surface flow
• To plot the sampled data using gnuplot you can proceed as follows. To enter to the
gnuplot prompt type in the terminal:

1. $> gnuplot

• Now that we are inside the gnuplot prompt, we can type,


1. set xlabel 'Time (seconds)'

2. set ylabel 'Water volume integral'

3. gnuplot> plot 'postProcessing/water_in_domain/0/volRegion.dat' u 1:2 w l title


'Water in domain'
4. set xlabel 'Time (seconds)'

5. set ylabel 'Pressure'

6. plot 'SPHERIC_Test2/case.txt' u 1:2 w l title 'Experiment',


'postProcessing/probes1/0/p' u 1:2 w l title 'Numerical simulation'
7. gnuplot> exit
To exit gnuplot
178
3D Dam break – Free surface flow
• The output of steps 3 and 6 is the following:

alpha.water vs. time p vs. time (at probe 0)

179
3D Dam break – Free surface flow

The output screen


Courant Number mean: 0.0099001831 max: 0.50908228 Flow courant number
Interface Courant Number mean: 0.0012838336 max: 0.05362054
deltaT = 0.00061195165
Time = 0.41265658 Interface courant number. When solving multiphase flows, is always
desirable to keep the interface courant number less than 1.
PIMPLE: iteration 1
alpha.water
smoothSolver: Solving for alpha.water, Initial residual = 0.00035163885, Final residual = 9.3476388e-11, No Iterations 2
Phase-1 volume fraction = 0.20706923 Min(alpha.water) = -9.1300674e-12 Max(alpha.water) = 1.0000113 residuals
MULES: Correcting alpha.water nAlphaSubCycles 1
MULES: Correcting alpha.water nAlphaCorr 3 Only one loop
MULES: Correcting alpha.water
Phase-1 volume fraction = 0.20706923 Min(alpha.water) = -1.2354076e-07 Max(alpha.water) = 1.0000113
DILUPBiCGStab: Solving for Ux, Initial residual = 0.00057936556, Final residual = 2.3207684e-09, No Iterations 1
DILUPBiCGStab: Solving for Uy, Initial residual = 0.0021990412, Final residual = 7.228845e-09, No Iterations 1
DILUPBiCGStab: Solving for Uz, Initial residual = 0.00041048425, Final residual = 3.946807e-10, No Iterations 1
DICPCG: Solving for p_rgh, Initial residual = 0.0013260985, Final residual = 1.2556023e-05, No Iterations 4
DICPCG: Solving for p_rgh, Initial residual = 1.4873252e-05, Final residual = 8.7706547e-07, No Iterations 13
time step continuity errors : sum local = 2.166836e-08, global = -4.8300033e-11, cumulative = -5.8278026e-05 3 pressure correctors
DICPCG: Solving for p_rgh, Initial residual = 1.6925332e-05, Final residual = 8.9811533e-07, No Iterations 9 and no non-orthogonal
DICPCG: Solving for p_rgh, Initial residual = 1.1731393e-06, Final residual = 4.991128e-07, No Iterations 1 corrections
time step continuity errors : sum local = 1.2328745e-08, global = -3.6165262e-09, cumulative = -5.8281643e-05
DICPCG: Solving for p_rgh, Initial residual = 8.2834963e-07, Final residual = 4.6047958e-07, No Iterations 1
DICPCG: Solving for p_rgh, Initial residual = 4.6053278e-07, Final residual = 4.65519e-07, No Iterations 1 Tighter tolerance
time step continuity errors : sum local = 1.1498949e-08, global = -3.1908629e-09, cumulative = -5.8284834e-05
DILUPBiCGStab: Solving for epsilon, Initial residual = 0.001169828, Final residual = 9.2601488e-11, No Iterations 2 (p_rghFinal) is only applied
DILUPBiCGStab: Solving for k, Initial residual = 0.0014561556, Final residual = 9.4651262e-11, No Iterations 2 to this iteration (the final
ExecutionTime = 23.21 s ClockTime = 24 s one)
Turbulence variables residuals
fieldMinMax minmaxdomain write:

Minimum and maximum


values of field variables
min(p) = -9.8942827 in cell 5509 at location (2.490155 0.025000016 1) on processor 2
max(p) = 4703.3656 in cell 1485 at location (3.1948336 -0.425 0) on processor 2
min(p_rgh) = -7.9025882 in cell 1241 at location (0.82088765 -0.20846334 0.043756428) on processor 1
max(p_rgh) = 4831.247 in cell 3285 at location (3.1948341 -0.475 0.42499986) on processor 2
min(U) = (-0.96505264 -0.019641482 -0.052664083) in cell 2 at location (2.1879167 -0.42500042 0.024999822) on processor 2
max(U) = (0.32541708 0.29383224 2.7117589) in cell 5246 at location (0.8884354 0.087713417 0.16296979) on processor 1
min(alpha.water) = -1.2354076e-07 in cell 2653 at location (0.84202094 -0.10628417 0.0062556498) on processor 1
max(alpha.water) = 1.0000113 in cell 224 at location (2.6411358 -0.42500003 0.074999874) on processor 2
min(k) = 0.0041733636 in cell 2510 at location (0.65789113 -0.0062500875 0.0062360099) on processor 1
max(k) = 0.83402261 in cell 6589 at location (1.2803306 -0.025028634 0.17499623) on processor 1
min(epsilon) = 0.018352121 in cell 2510 at location (0.65789113 -0.0062500875 0.0062360099) on processor 1
max(epsilon) = 11.712212 in cell 1933 at location (0.83147515 -0.19630576 0.068753535) on processor 1

volFieldValue water_in_domain write:


volIntegrate() of alpha.water = 0.66459985 Volume integral functionObject
180
3D Dam break – Free surface flow

Post-processing multiphase flows in paraFoam


• To visualize the volume fraction, proceed as follows,
4. To animate the solution, press Play in the
VCR Controls

2. Select alpha.water in
the Active Variable drop-
down menu

3. Select Surface in the


Representation drop-down
menu

Air Water
alpha.water = 0 alpha.water = 1

1. In the Properties tab select


alpha.water in Volume Fields

Interface
alpha.water = 0.5
181
3D Dam break – Free surface flow

Post-processing multiphase flows in paraFoam


• To visualize a surface representing the interface, proceed as follows,
5. To animate the solution, press Play in the
VCR Controls

1. Select the filter Contour

4. Press apply

2. Select alpha.water or the field you


want to use to plot the iso-surface (it
has to be a scalar)

3. Enter the value 0.5 which


corresponds to the interface Iso-surface representing the interface
between water and air between water and air

182
3D Dam break – Free surface flow

Post-processing multiphase flows in paraFoam


• To visualize all the cells representing the water fraction, proceed as follows,
5. To animate the solution, press Play in the
VCR Controls

1. Select the filter Threshold

4. Press apply

2. Select alpha.water or the field


you want to use to visualize the
cells (it has to be a scalar)

Cells representing the


3. Select the range you want to water location
visualize. To visualize the
water select Minimum 0.5 and
Maximum 1.

183
3D Dam break – Free surface flow

Exercises
• Instead of using the boundary condition totalPressure and pressureInletOutletVelocity for the patch top, try
to use zeroGradient. Do you get the same results? Any comments?
(Hint: this combination of boundary conditions might give you an error, if so, read carefully the screen
and try to find a fix, you can start by looking at the file fvSolution)
• Instead of using the boundary condition fixedFluxPressure for the walls, try to use zeroGradient. Do you get
the same results? Any comments?
• Run the simulation in a close domain. Does the volume integral of alpha.water remains the same? Why the
value is not constant when the domain is open?
• Use a functionObject to measure the average pressure on the obstacle.
• How many initialization methods are there available in the dictionary setFieldsDict?
(Hint: use the banana method)
• Run the simulation using Gauss upwind instead of Gauss vanLeer or Gauss interfaceCompression
vanLeer 1 for the term div(phi,alpha) (fvSchemes). Do you get the same quantitative results?

184
3D Dam break – Free surface flow

Exercises
• Run a numerical experiment for cAlpha equal to 0, 1, and 2. Do you see any difference in the solution? What
about computing time?
• Use the solver GAMG instead of using the solver PCG for the variable p_rgh. Do you see any difference on
the solution or computing time?
• Increase the number of nOuterCorrector to 2 and study the output screen. What difference do you see?
• Turn off the MULES corrector (MULESCorr). Do you see any difference on the solution or computing time?
• If you set the gravity vector to (0 0 0), what do you think will happen?
• Try to break the solver and identify the cause of the error. You are free to try any kind of setup.

185
Roadmap

1. OpenFOAM® brief overview


2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
7. A deeper view to my first OpenFOAM® case setup
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

186
Flow past a cylinder – From laminar to turbulent flow

• At this point we all have a rough idea of what is going


on with all these dictionary files.
• Unless it is strictly necessary, from now on we will not
go into details about the dictionaries and files we are
using.
• Remember, if you are using the lab computers, do not
forget to load the environment variables.

187
Flow past a cylinder – From laminar to turbulent flow
Flow around a cylinder – 10 < Re < 2 000 000
Incompressible and compressible flow

Physical and numerical side of the


problem:
• In this case we are going to solve the flow
around a cylinder. We are going to use
incompressible and compressible solvers, in
laminar and turbulent regime.
• Therefore, the governing equations of the
problem are the incompressible/compressible
laminar/turbulent Navier-Stokes equations.
• We are going to work in a 2D domain.
• Depending on the Reynolds number, the flow
can be steady or unsteady.
All the dimensions are in meters • This problem has a lot of validation data.

188
Flow past a cylinder – From laminar to turbulent flow
Workflow of the case
blockMesh
Or
fluentMeshToFoam

icoFoam
NOTE: pisoFoam
One single mesh can be used with all
solvers and utilities pimpleFoam
pimpleDyMFoam
simpleFoam
functionObjects
rhoPimpleFoam
interFoam
sonicFoam
potentialFoam
mapFields

postProcessing
utilities

sampling paraview

189
Flow past a cylinder – From laminar to turbulent flow

Vortex shedding behind a cylinder

Creeping flow (no s eparation)


S teady flow Re < 5

A pair of s table vortices


in the wake
S teady flow
5 < Re < 40 - 46

Laminar vortex s treet


(Von Karman s treet)
Uns teady flow
40 - 46 < Re < 150 Drag coefficient

Laminar boundary layer up to


the s eparation point, turbulent
150 < Re < 300
Trans ition to turbulence
wake
Uns teady flow 300 < Re < 3 x 10 5

Boundary layer trans ition to 5 6


turbulent 3 x 10 < Re < 3 x 10
Uns teady flow

Turbulent vortex s treet, but the


6
wake is narrower than in the
laminar cas e 3 x 10 > Re
Uns teady flow

Strouhal number

190
Flow past a cylinder – From laminar to turbulent flow
Some experimental (E) and numerical (N) results of the flow past a circular
cylinder at various Reynolds numbers

Reference cd – Re = 20 Lrb – Re = 20 cd – Re = 40 Lrb – Re = 40

[1] Tritton (E) 2.22 – 1.48 –

[2] Cuntanceau and Bouard (E) – 0.73 – 1.89

[3] Russel and Wang (N) 2.13 0.94 1.60 2.29

[4] Calhoun and Wang (N) 2.19 0.91 1.62 2.18

[5] Ye et al. (N) 2.03 0.92 1.52 2.27

[6] Fornbern (N) 2.00 0.92 1.50 2.24

[7] Guerrero (N) 2.20 0.92 1.62 2.21

Lrb = length of recirculation bubble, cd = drag coefficient, Re = Reynolds number,

[1] D. Tritton. Experiments on the flow past a circular cylinder at low Reynolds numbers. Journal of Fluid Mechanics, 6:547-567, 1959.
[2] M. Cuntanceau and R. Bouard. Experimental determination of the main features of the viscous flow in the wake of a circular cylinder in uniform translation. Part 1. Steady flow. Journal of Fluid
Mechanics, 79:257-272, 1973.
[3] D. Rusell and Z. Wang. A cartesian grid method for modeling multiple moving objects in 2D incompressible viscous flow. Journal of Computational Physics, 191:177-205, 2003.
[4] D. Calhoun and Z. Wang. A cartesian grid method for solving the two-dimensional streamfunction-vorticity equations in irregular regions. Journal of Computational Physics. 176:231-275, 2002.
[5] T. Ye, R. Mittal, H. Udaykumar, and W. Shyy. An accurate cartesian grid method for viscous incompressible flows with complex immersed boundaries. Journal of Computational Physics,
156:209-240, 1999.
[6] B. Fornberg. A numerical study of steady viscous flow past a circular cylinder. Journal of Fluid Mechanics, 98:819-855, 1980.
[7] J. Guerrero. Numerical simulation of the unsteady aerodynamics of flapping flight. PhD Thesis, University of Genoa, 2009.
191
Flow past a cylinder – From laminar to turbulent flow
Some experimental (E) and numerical (N) results of the flow past a circular
cylinder at various Reynolds numbers

Reference cd – Re = 100 cl – Re = 100 cd – Re = 200 cl – Re = 200

[1] Russel and Wang (N) 1.38 ± 0.007 ± 0.322 1.29 ± 0.022 ± 0.50

[2] Calhoun and Wang (N) 1.35 ± 0.014 ± 0.30 1.17 ± 0.058 ± 0.67

[3] Braza et al. (N) 1.386± 0.015 ± 0.25 1.40 ± 0.05 ± 0.75

[4] Choi et al. (N) 1.34 ± 0.011 ± 0.315 1.36 ± 0.048 ± 0.64

[5] Liu et al. (N) 1.35 ± 0.012 ± 0.339 1.31 ± 0.049 ± 0.69

[6] Guerrero (N) 1.38 ± 0.012 ± 0.333 1.408 ± 0.048 ± 0.725

cl = lift coefficient, cd = drag coefficient, Re = Reynolds number

[1] D. Rusell and Z. Wang. A cartesian grid method for modeling multiple moving objects in 2D incompressible viscous flow. Journal of Computational Physics, 191:177-205, 2003.
[2] D. Calhoun and Z. Wang. A cartesian grid method for solving the two-dimensional streamfunction-vorticity equations in irregular regions. Journal of Computational Physics. 176:231-275, 2002.
[3] M. Braza, P. Chassaing, and H. Hinh. Numerical study and physical analysis of the pressure and velocity fields in the near wake of a circular cylinder. Journal of Fluid Mechanics, 165:79-130,
1986.
[4] J. Choi, R. Oberoi, J. Edwards, an J. Rosati. An immersed boundary method for complex incompressible flows. Journal of Computational Physics, 224:757-784, 2007.
[5] C. Liu, X. Zheng, and C. Sung. Preconditioned multigrid methods for unsteady incompressible flows. Journal of Computational Physics, 139:33-57, 1998.
[6] J. Guerrero. Numerical Simulation of the unsteady aerodynamics of flapping flight. PhD Thesis, University of Genoa, 2009.

192
Flow past a cylinder – From laminar to turbulent flow
At the end of the day, you should get something like this

Instantaneous velocity magnitude field Instantaneous vorticity magnitude field


www.wolfdynamics.com/wiki/cylinder_vortex_shedding/movvmag.gif www.wolfdynamics.com/wiki/cylinder_vortex_shedding/movvort.gif

Incompressible flow – Reynolds 200

193
Flow past a cylinder – From laminar to turbulent flow
At the end of the day, you should get something like this

Incompressible flow – Reynolds 200 194


Flow past a cylinder – From laminar to turbulent flow

• Let us run this case. Go to the directory:

$PTOFC/101OF/vortex_shedding

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.

195
Flow past a cylinder – From laminar to turbulent flow
What are we going to do?
• We will use this case to learn how to use different solvers and utilities.
• Remember, different solvers have different input dictionaries.
• We will learn how to convert the mesh from a third-party software.
• We will learn how to use setFields to initialize the flow field and accelerate the
convergence.
• We will learn how to map a solution from a coarse mesh to a fine mesh.
• We will learn how to setup a compressible solver.
• We will learn how to setup a turbulence case.
• We will use gnuplot to plot and compute the mean values of the lift and drag
coefficients.
• We will visualize unsteady data.

196
Flow past a cylinder – From laminar to turbulent flow
Running the case
• Let us first convert the mesh from a third-party format (Fluent format).
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c2
• In the terminal window type:

1. $> foamCleanTutorials
2. $> fluent3DMeshToFoam ../../../meshes_and_geometries/vortex_shedding/ascii.msh

3. $> checkMesh
4. $> paraFoam

• In step 2, we convert the mesh from Fluent format to OpenFOAM® format. Have in
mind that the Fluent mesh must be in ascii format.
• If we try to open the mesh using paraFoam (step 4), it will crash. Can you tell what is
the problem by just reading the screen?

197
Flow past a cylinder – From laminar to turbulent flow
Running the case
• To avoid this problem, type in the terminal,

1. $> paraFoam -builtin

• Basically, the problem is related to the names and type of the patches in the file
boundary and the boundary conditions (U, p). Notice that OpenFOAM® is telling you
what and where is the error.

Created temporary 'c2.OpenFOAM'

--> FOAM FATAL IO ERROR:

patch type 'patch' not constraint type 'empty' What Where


for patch front of field p in file "/home/joegi/my_cases_course/8/101OF/vortex_shedding/c2/0/p"

file: /home/joegi/my_cases_course/8/101OF/vortex_shedding/c2/0/p.boundaryField.front from line 60 to line 60.

From function Foam::emptyFvPatchField<Type>::emptyFvPatchField(const Foam::fvPatch&, const


Foam::DimensionedField<Type, Foam::volMesh>&, const Foam::dictionary&) [with Type = double]
in file fields/fvPatchFields/constraint/empty/emptyFvPatchField.C at line 80.

FOAM exiting

198
Flow past a cylinder – From laminar to turbulent flow
• Remember, when converting meshes the name and type of the patches are not
always set as you would like, so it is always a good idea to take a look at the file
boundary and modify it according to your needs.
• Let us modify the boundary dictionary file.
• In this case, we would like to setup the following numerical type boundary
conditions.

199
Flow past a cylinder – From laminar to turbulent flow
The boundary dictionary file

• This dictionary is located in the


18
19
7
(
constant/polyMesh directory.
20 out
21 { • This file is automatically created when converting
22 type patch;
23 nFaces 80; or generating the mesh.
24 startFace 18180;
25
26
}
sym1 • To get a visual reference of the patches, you can
27
28
{
type symmetry;
visualize the mesh with paraFoam/paraview.
29 inGroups 1(symmetry);
30 nFaces 100; • The type of the out patch is OK.
31 startFace 18260;
32 }
33 sym2 • The type of the sym1 patch is OK.
34 {
35
36
type
inGroups
symmetry;
1(symmetry);
• The type of the sym2 patch is OK.
37 nFaces 100;
38 startFace 18360; • The type of the in patch is OK.
39 }
40 in
41 {
42 type patch;
43 nFaces 80;
44 startFace 18460;
45 }

200
Flow past a cylinder – From laminar to turbulent flow
The boundary dictionary file

• The type of the cylinder patch is OK.


46 cylinder
47
48
{
type wall;
• The type of the back patch is NOT OK.
49 inGroups 1(wall); Remember, this is a 2D simulation, therefore the
50 nFaces 80;
51 startFace 18540; type should be empty.
52 }
53
54
back
{ • The type of the front patch is NOT OK.
55
56
type
nFaces
patch;
9200;
Remember, this is a 2D simulation, therefore the
57
58 }
startFace 18620;
type should be empty.
59 front
60 { • Remember, we assign the numerical type
61 type patch;
62 nFaces 9200; boundary conditions (numerical values), in the
63
64 }
startFace 27820;
field files found in the directory 0
65 )

201
Flow past a cylinder – From laminar to turbulent flow
• At this point, check that the name and type of the base type boundary conditions
and numerical type boundary conditions are consistent. If everything is ok, we are
ready to go.
• Do not forget to explore the rest of the dictionary files, namely:
• 0/p (p is defined as relative pressure)
• 0/U
• constant/transportProperties
• system/controlDict
• system/fvSchemes
• system/fvSolution
• Reminder:
• The diameter of the cylinder is 2.0 m.
• And we are targeting for a Re = 200.

202
Flow past a cylinder – From laminar to turbulent flow
Running the case
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c2
• In the folder c1 you will find the same setup, but to generate the mesh we use
blockMesh (the mesh is identical).
• To run this case, in the terminal window type:

1. $> renumberMesh -overwrite


2. $> icoFoam | tee log.icofoam
$> pyFoamPlotWatcher.py log.icofoam
3.
You will need to launch this script in a different terminal

$> gnuplot scripts0/plot_coeffs


4.
You will need to launch this script in a different terminal

5. $> paraFoam

203
Flow past a cylinder – From laminar to turbulent flow
Running the case
• In step 1 we use the utility renumberMesh to make the linear system more diagonal
dominant, this will speed-up the linear solvers. This is inexpensive (even for large
meshes), therefore is highly recommended to always do it.
• In step 2 we run the simulation and save the log file. Notice that we are sending the
job to background.
• In step 3 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
job is running in background, we can launch this utility in the same terminal tab.
• In step 4 we use the gnuplot script scripts0/plot_coeffs to plot the force
coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
• The force coefficients are computed using functionObjects.
• After the simulation is over, we use paraFoam to visualize the results. Remember to
use the VCR Controls to animate the solution.
• In the folder c1 you will find the same setup, but to generate the mesh we use
blockMesh (the mesh is identical).

204
Flow past a cylinder – From laminar to turbulent flow
• At this point try to use the following utilities. In the terminal type:
• $> postProcess –func vorticity –noZero
This utility will compute and write the vorticity field. The –noZero option means do not compute the vorticity field for the
solution in the directory 0. If you do not add the –noZero option, it will compute and write the vorticity field for all the
saved solutions, including 0
• $> postprocess –func 'grad(U)' –latestTime
This utility will compute and write the velocity gradient or grad(U) in the whole domain (including at the walls). The
–latestTime option means compute the velocity gradient only for the last saved solution.
• $> postprocess –func 'grad(p)'
This utility will compute and write the pressure gradient or grad(U) in the whole domain (including at the walls).
• $> foamToVTK –time 50:300
This utility will convert the saved solution from OpenFOAM® format to VTK format. The –time 50:300 option means
convert the solution to VTK format only for the time directories 50 to 300

• $> postProcess -func 'div(U)'


and error message, try to fix it.
These last three will give you

This utility will compute and write the divergence of the velocity field or grad(U) in the whole domain (including at the
walls).
• $> pisoFoam -postProcess -func CourantNo
This utility will compute and write the Courant number. This utility needs to access the solver database for the physical
properties and additional quantities; therefore we need to tell what solver we are using. As the solver icoFoam does not
accept the option –postProcess, we can use the solver pisoFoam instead. Remember, icoFoam is a fully laminar
solver and pisoFoam is a laminar/turbulent solver.
• $> pisoFoam -postProcess -func wallShearStress
This utility will compute and write the wall shear stresses at the walls. As no arguments are given, it will save the wall
shear stresses for all time steps.
205
Flow past a cylinder – From laminar to turbulent flow
Non-uniform field initialization
• In the previous case, it took about 150 seconds of simulation time to onset the instability.
• If you are not interested in the initial transient or if you want to speed-up the computation, you
can add a perturbation in order to trigger the onset of the instability.
• Let us use the utility setFields to initialize a non-uniform flow.
• This case is already setup in the directory ,
$PTOFC/101OF/vortex_shedding/c3

• As you saw in the previous example, icoFoam is a very basic solver that does not have access
to all the advanced modeling or postprocessing capabilities that comes with OpenFOAM®.
• Therefore, instead of using icoFoam we will use pisoFoam (or pimpleFoam) from now on.
• To run the solver pisoFoam (or pimpleFoam) starting from the directory structure of an
icoFoam case, you will need to add the followings modifications:
• Add the file momentumTransport in the directory constant.
• Add the transportModel to be used in the file constant/transportProperties.
• Add the entry div((nuEff*dev2(T(grad(U))))) Gauss linear; to the dictionary
system/fvSchemes in the section divSchemes (this entry is related to the Reynodls
stresses).
206
Flow past a cylinder – From laminar to turbulent flow
• Let us run the same case but using a non-uniform field
The setFieldsDict dictionary
• This dictionary file is located in the directory system.
17 defaultFieldValues • In lines 17-20 we set the default value of the velocity vector
18 (
19 volVectorFieldValue U (1 0 0) to be (0 0 0) in the whole domain.
20 );
21 • In lines 24-31, we initialize a rectangular region (box) just
22 regions
23 ( behind the cylinder with a velocity vector equal to (0.98480
24 boxToCell 0.17364 0)
25 {
26 box (0 -100 -100) (100 100 100);
27 fieldValues • In this case, setFields will look for the dictionary file U
28
29
(
volVectorFieldValue U (0.98480 0.17364 0)
and it will overwrite the original values according to the
30 ); regions defined in setFieldsDict.
31 }
32 );

boxToCell region

U (0.98480 0.17364 0)
U (1 0 0)

207
Flow past a cylinder – From laminar to turbulent flow
• Let us run the same case but using a non-uniform field.
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c3
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. Hereafter, we will
use blockMesh.
• To run this case, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0 > /dev/null 2>&1
4. $> cp –r 0_org/ 0
5. $> setFields
6. $> renumberMesh -overwrite
7. $> pisoFoam | tee log.solver
$> pyFoamPlotWatcher.py log.pisofoam
8.
You will need to launch this script in a different terminal

$> gnuplot scripts0/plot_coeffs


9.
You will need to launch this script in a different terminal

10. $> paraFoam 208


Flow past a cylinder – From laminar to turbulent flow
Running the case – Non-uniform field initialization
• In step 2 we generate the mesh using blockMesh. The name and type of the
patches are already set in the dictionary blockMeshDict so there is no need to
modify the boundary file.
• In step 4 we copy the original files to the directory 0. We do this to keep a backup of
the original files as the file 0/U will be overwritten when using setFields.
• In step 5 we initialize the solution using setFields.
• In step 6 we use the utility renumberMesh to make the linear system more diagonal
dominant, this will speed-up the linear solvers.
• In step 7 we run the simulation and save the log file. Notice that we are sending the
job to background.
• In step 8 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
job is running in background, we can launch this utility in the same terminal tab.
• In step 9 we use the gnuplot script scripts0/plot_coeffs to plot the lift and drag
coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.

209
Flow past a cylinder – From laminar to turbulent flow
Does non-uniform field initialization make a difference?
• A picture is worth a thousand words. No need to tell you yes, even if the solutions are
slightly different.
• This bring us to the next subject, for how long should we run the simulation?

No field initialization With field initialization

210
Flow past a cylinder – From laminar to turbulent flow
For how long should run the simulation?

• This is the difficult part when dealing with


unsteady flows.
• Usually you run the simulation until the
behavior of a quantity of interest does not
oscillates or it becomes periodic.
• In this case we can say that after the 50
seconds mark the solution becomes
periodic, therefore there is no need to run up
to 350 seconds (unless you want to gather a
lot of statistics).
• We can stop the simulation at 150 seconds
(or maybe less), and do the average of the
quantities between 100 and 150 seconds.

211
Flow past a cylinder – From laminar to turbulent flow
What about the residuals?

• Residuals are telling you a lot, but they are


difficult to interpret.
• In this case the fact that the initial residuals
are increasing after about 10 seconds, does
not mean that the solution is diverging. This
is in indication that something is happening
(in this case the onset of the instability).
• Remember, the residuals should always
drop to the tolerance criteria set in the
fvSolution dictionary (final residuals). If
they do not drop to the desired tolerance, we
are talking about unconverged time-steps.
• Things that are not clear from the residuals:
• For how long should we run the
simulation?
• Is the solution converging to the right
value?

212
Flow past a cylinder – From laminar to turbulent flow
How to compute force coefficients

51 functions • To compute the force coefficients we use


52 { functionObjects.
178
179
forceCoeffs_object
{
• Remember, functionObjects are defined at the end of
188 type forceCoeffs; the controlDict dictionary file.
189 functionObjectLibs ("libforces.so");
191 patches (cylinder); • In line 178 we give a name to the functionObject.
193 pName p; • In line 191 we define the patch where we want to
194 Uname U;
195 rhoName rhoInf; compute the forces.
196 rhoInf 1.0;
• In lines 195-196 we define the reference density value.
198 //// Dump to file
199 log true; • In line 201 we define the center of rotation (for moments).
201 CofR (0.0 0 0); • In line 202 we define the lift force axis.
202 liftDir (0 1 0);
202 dragDir (1 0 0); • In line 203 we define the drag force axis.
204 pitchAxis (0 0 1);
205 magUInf 1.0; • In line 204 we define the axis of rotation for moment
206
207
lRef 1.0;
Aref 2.0;
computation.
209 outputControl timeStep;
• In line 206 we give the reference length (for computing
210 outputInterval 1; the moments)
211 }
• In line 207 we give the reference area (in this case the
237 };
frontal area).
• The output of this functionObject is saved in the file
forceCoeffs.dat located in the directory
forceCoeffs_object/0/

213
Flow past a cylinder – From laminar to turbulent flow
Can we compute basic statistics of the force coefficients using gnuplot?
• Yes we can. Enter the gnuplot prompt and type:

1. gnuplot> stats ‘postProcessing/forceCoeffs_object/0/forceCoeffs.dat’ u 3


This will compute the basic statistics of all the rows in the file forceCoeffs.dat (we are sampling column 3 in the input file)

2. gnuplot> stats ‘postProcessing/forceCoeffs_object/0/forceCoeffs.dat’ every ::3000::7000 u 3


This will compute the basic statistics of rows 3000 to 7000 in the file forceCoeffs.dat (we are sampling column 3 in the input file)

3. gnuplot> plot ‘postProcessing/forceCoeffs_object/0/forceCoeffs.dat’ u 3 w l


This will plot column 3 against the row number (iteration number)

4. gnuplot> exit
To exit gnuplot

• Remember the force coefficients information is saved in the file forceCoeffs.dat


located in the directory postProcessing/forceCoeffs_object/0

214
Flow past a cylinder – From laminar to turbulent flow
On the solution accuracy

17 ddtSchemes
• At the end of the day we want a solution that is second order
18 { accurate.
20 default backward;
22
23
}
• We define the discretization schemes (and therefore the
24 gradSchemes accuracy) in the dictionary fvSchemes.
25 {
29
35 }
default cellLimited leastSquares 1;
• In this case, for time discretization (ddtSchemes) we are
36 using the backward method.
37 divSchemes
38
39
{
default none;
• For gradient discretization (gradSchemes) we are using the
43 div(phi,U) Gauss linearUpwindV default; leastSquares method with slope limiters (cellLimited) for all
48 div((nuEff*dev2(T(grad(U))))) Gauss linear;
49 } terms (default option).
50
51 laplacianSchemes • Sometimes adding a gradient limiter to the pressure gradient
52 {
53 default Gauss linear limited 1; or grad(p) can be too diffusive, so it is better not to use
54
55
}
gradient limiters for grad(p), e.g., grad(p) leastSquares.
56 interpolationSchemes
57 { • For the discretization of the convective terms (divSchemes)
58
59 }
default linear;
we are using linearUpwindV interpolation method for the
60 term div(rho,U).
61 snGradSchemes
62
63
{
default limited 1;
• For the discretization of the Laplacian (laplacianSchemes
64 } and snGradSchemes) we are using the Gauss linear
limited 1 method
• In overall, this method is second order accurate (this is what
we want).
215
Flow past a cylinder – From laminar to turbulent flow
On the solution tolerance and linear solvers

17 solvers
• We define the solution tolerance and linear solvers in the
18 { dictionary fvSolution.
31 p
32
33
{
solver GAMG;
• To solve the pressure (p) we are using the GAMG method
34 tolerance 1e-6; with an absolute tolerance of 1e-6 and a relative tolerance
35 relTol 0;
36 smoother GaussSeidel; relTol of 0.01.
37 nPreSweeps 0;
38 nPostSweeps 2; • The entry pFinal refers to the final correction of the PISO
39 cacheAgglomeration on;
40 agglomerator faceAreaPair; loop. It is possible to use a tighter convergence criteria only
41
42
nCellsInCoarsestLevel 100;
mergeLevels 1;
in the last iteration.
43 }
44 • To solve U we are using the solver PBiCGStab and the DILU
45
46
pFinal
{
preconditioner, with an absolute tolerance of 1e-8 and a
47 $p; relative tolerance relTol of 0 (the solver will stop iterating
48 relTol 0;
49 } when it meets any of the conditions).
50
51 U • Solving for the velocity is relative inexpensive, whereas
52 {
53 solver PBiCGStab; solving for the pressure is expensive.
54 preconditioner DILU;
55 tolerance 1e-08; • The PISO sub-dictionary contains entries related to the
56 relTol 0;
57 } pressure-velocity coupling (in this case the PISO method).
69
70
}
Hereafter we are doing two PISO correctors (nCorrectors)
71 PISO and two non-orthogonal corrections
72 {
73 nCorrectors 2; (nNonOrthogonalCorrectors).
74 nNonOrthogonalCorrectors 2;
77 }

216
Flow past a cylinder – From laminar to turbulent flow
On the runtime parameters

17 application pisoFoam;
• This case starts from the latest saved solution (startFrom).
18
20 startFrom latestTime; • In this case as there are no saved solutions, it will start from
21
22 startTime 0;
0 (startTime).
23
24 stopAt endTime; • It will run up to 350 seconds (endTime).
26
27 endTime 350; • The time step of the simulation is 0.05 seconds (deltaT). The
28
29 deltaT 0.05; time step has been chosen in such a way that the Courant
30
31 writeControl runTime;
number is less than 1
32
33 writeInterval 1; • It will write the solution every 1 second (writeInterval) of
34
35 purgeWrite 0;
simulation time (runTime).
36
37 writeFormat ascii; • It will keep all the solution directories (purgeWrite).
38
39
40
writePrecision 8; • It will save the solution in ascii format (writeFormat).
41 writeCompression off;
42 • The write precision is 8 digits (writePrecision).
43 timeFormat general;
44 • And as the option runTimeModifiable is on, we can modify
45 timePrecision 6;
46 all these entries while we are running the simulation.
47 runTimeModifiable true;

217
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the pisoFoam solver.
nCorrector 1

Time = 350
Courant number
Courant Number mean: 0.11299953 max: 0.87674198
DILUPBiCG: Solving for Ux, Initial residual = 0.0037946307, Final residual = 4.8324843e-09, No Iterations 3
DILUPBiCG: Solving for Uy, Initial residual = 0.011990022, Final residual = 5.8815028e-09, No Iterations 3
GAMG: Solving for p, Initial residual = 0.022175872, Final residual = 6.2680545e-07, No Iterations 14
GAMG: Solving for p, Initial residual = 0.0033723932, Final residual = 5.8494331e-07, No Iterations 8
nNonOrthogonalCorrectors 2
GAMG: Solving for p, Initial residual = 0.0010074964, Final residual = 4.4726195e-07, No Iterations 7
time step continuity errors : sum local = 1.9569266e-11, global = -3.471923e-14, cumulative = -2.8708402e-10
GAMG: Solving for p, Initial residual = 0.0023505548, Final residual = 9.9222424e-07, No Iterations 8
GAMG: Solving for p, Initial residual = 0.00045248026, Final residual = 7.7250386e-07, No Iterations 6
GAMG: Solving for p, Initial residual = 0.00014664077, Final residual = 4.5825218e-07, No Iterations 5 pFinal
time step continuity errors : sum local = 2.0062733e-11, global = 1.2592813e-13, cumulative = -2.8695809e-10
ExecutionTime = 746.46 s ClockTime = 807 s

faceSource inMassFlow output:


sum(in) of phi = -40 Mass flow at in patch
nCorrector 2

faceSource outMassFlow output:


sum(out) of phi = 40 Mass flow at out patch

fieldAverage fieldAverage output:


Calculating averages Computing averages of fields
Writing average fields nCorrectors 2

forceCoeffs forceCoeffs_object output:


Cm = 0.0043956828
Cd = 1.4391786
Cl = 0.44532594 Force
Cl(f) = 0.22705865 coefficients
Cl(r) = 0.21826729

fieldMinMax minmaxdomain output:


min(p) = -0.82758125 at location (2.2845502 0.27072681 1.4608125e-17)
max(p) = 0.55952746 at location (-1.033408 -0.040619346 0)
min(U) = (-0.32263726 -0.054404584 -1.8727033e-19) at location (2.4478235 -0.69065656 -2.5551406e-17) Min and max values
max(U) = (1.4610304 0.10220218 2.199981e-19) at location (0.43121241 1.5285504 -1.4453535e-17)

218
Flow past a cylinder – From laminar to turbulent flow
Let us use a potential solver to find a quick solution
• In this case we are going to use the potential solver potentialFoam (remember potential
solvers are inviscid, irrotational and incompressible)
• This solver is super fast, and it can be used to find a solution to be used as initial conditions
(non-uniform field) for an incompressible solver.
• A good initial condition will accelerate and improve the convergence rate.
• This case is already setup in the directory

$PTOFC/101OF/vortex_shedding/c4

• Do not forget to explore the dictionary files.


• The following dictionaries are different
• system/fvSchemes
• system/fvSolution

Try to spot the differences.

219
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us use a potential solver to find a quick solution

• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c4


• Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this
case we will use blockMesh.
• To run this case, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> potentialFoam –noFunctionObjects –initialiseUBCs –writep -writePhi

6. $> paraFoam

220
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us use a potential solver to find a quick solution

• In step 2 we generate the mesh using blockMesh. The name and type of the
patches are already set in the dictionary blockMeshDict so there is no need to
modify the boundary file.
• In step 4 we copy the original files to the directory 0. We do this to keep a backup of
the original files as they will be overwritten by the solver potentialFoam.
• In step 5 we run the solver. We use the option –noFunctionObjects to avoid
conflicts with the functionobjects. The options –writep and –writePhi will write
the pressure field and fluxes respectively.
• At this point, if you want to use this solution as initial conditions for an incompressible
solver, just copy the files U and p into the start directory of the incompressible case
you are looking to run. Have in mind that the meshes need to be the same.
• Be careful with the name and type of the boundary conditions, they should be same
between the potential case and incompressible case.

221
Flow past a cylinder – From laminar to turbulent flow
Potential solution
• Using a potential solution as initial conditions is much better than using a uniform
flow. It will speed up the solution and it will give you more stability.
• Finding a solution using the potential solver is inexpensive.

Velocity field Pressure field

222
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the potentialFoam solver.
• The output of this solver is also a good indication of the sensitivity of the mesh quality
to gradients computation. If you see that the number of iterations are dropping
iteration after iteration, it means that the mesh is fine.
• If the number of iterations remain stalled, it means that the mesh is sensitive to
gradients, so you should use non-orthogonal correction.
• In this case we have a good mesh.

Calculating potential flow Velocity computation


DICPCG: Solving for Phi, Initial residual = 2.6622265e-05, Final residual = 8.4894837e-07, No Iterations 27 Initial approximation
DICPCG: Solving for Phi, Initial residual = 1.016986e-05, Final residual = 9.5168103e-07, No Iterations 9
DICPCG: Solving for Phi, Initial residual = 4.0789046e-06, Final residual = 7.7788216e-07, No Iterations 5
DICPCG: Solving for Phi, Initial residual = 1.8251249e-06, Final residual = 8.8483568e-07, No Iterations 1
DICPCG: Solving for Phi, Initial residual = 1.1220074e-06, Final residual = 5.6696809e-07, No Iterations 1
DICPCG: Solving for Phi, Initial residual = 7.1187246e-07, Final residual = 7.1187246e-07, No Iterations 0
Continuity error = 1.3827583e-06
Interpolated velocity error = 7.620206e-07
nNonOrthogonalCorrectors 5
Calculating approximate pressure field Pressure computation
DICPCG: Solving for p, Initial residual = 0.0036907012, Final residual = 9.7025397e-07, No Iterations 89
DICPCG: Solving for p, Initial residual = 0.0007470416, Final residual = 9.9942495e-07, No Iterations 85
DICPCG: Solving for p, Initial residual = 0.00022829496, Final residual = 8.6107759e-07, No Iterations 36
DICPCG: Solving for p, Initial residual = 7.9622793e-05, Final residual = 8.4360883e-07, No Iterations 31
DICPCG: Solving for p, Initial residual = 2.8883108e-05, Final residual = 8.7152873e-07, No Iterations 25
DICPCG: Solving for p, Initial residual = 1.151539e-05, Final residual = 9.7057871e-07, No Iterations 9
ExecutionTime = 0.17 s ClockTime = 0 s

End

223
Flow past a cylinder – From laminar to turbulent flow
Let us map a solution from a coarse mesh to a finer mesh
• It is also possible to map the solution from a coarse mesh to a finer mesh (and all the
way around).
• For instance, you can compute a full Navier-Stokes solution in a coarse mesh (fast
solution), and then map it to a finer mesh.
• Let us map the solution from the potential solver to a finer mesh (if you want you can
map the solution obtained using pisoFoam or icoFoam). To do this we will use the
utility mapFields.
• This case is already setup in the directory

$PTOFC/101OF/vortex_shedding/c6

224
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us map a solution from a coarse mesh to a finer mesh

• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c6


• To generate the mesh, use blockMesh (remember this mesh is finer).
• To run this case, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> mapfields ../c4 –consistent –noFunctionObjects –mapMethod cellPointInterpolate -sourceTime 0

6. $> paraFoam

• To run step 5 you need to have a solution in the directory ../c4

225
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us map a solution from a coarse mesh to a finer mesh

• In step 2 we generate a finer mesh using blockMesh. The name and type of the
patches are already set in the dictionary blockMeshDict so there is no need to
modify the boundary file.
• In step 4 we copy the original files to the directory 0. We do this to keep a backup of
the original files as they will be overwritten by the utility mapFields.
• In step 5 we use the utility mapFields with the following options:
• We copy the solution from the directory ../c4
• The options –consistent is used when the domains and BCs are the same.
• The option –noFunctionObjects is used to avoid conflicts with the
functionObjects.
• The option –mapMethod cellPointInterpolate defines the interpolation
method.
• The option -sourceTime 0 defines the time from which we want to interpolate
the solution.

226
Flow past a cylinder – From laminar to turbulent flow
The meshes and the mapped fields

Coarse mesh Fine mesh

mapFields

227
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the mapFields utility.
• The utility mapFields, will try to interpolate all fields in the source directory.
• You can control the target time via the startFrom and startTime keywords in the
controlDict dictionary file.
Source: "/home/joegi/my_cases_course/OF8/101OF/vortex_shedding" "c5" Source case
Target: "/home/joegi/my_cases_course/OF8/101OF/vortex_shedding" "c6" Target case
Mapping method: cellPointInterpolate Interpolation method

Create databases as time

Source time: 350 Source time


Target time: 0 Target time
Create meshes

Source mesh size: 9200 Target mesh size: 36800 Source and target mesh cell count

Consistently creating and mapping fields for time 0

interpolating Phi
interpolating p Interpolated fields
interpolating U

End

• Finally, after mapping the solution, you can run the solver in the usual way. The solver
will use the mapped solution as initial conditions. 228
Flow past a cylinder – From laminar to turbulent flow
Setting a turbulent case
• So far we have used laminar incompressible solvers.
• Let us do a turbulent simulation.
• When doing turbulent simulations, we need to choose the turbulence model, define
the boundary and initial conditions for the turbulent quantities, and modify the
fvSchemes and fvSolution dictionaries to take account for the new variables we
are solving (the transported turbulent quantities).
• This case is already setup in the directory

$PTOFC/101OF/vortex_shedding/c14

229
Flow past a cylinder – From laminar to turbulent flow
• The following dictionaries remain unchanged
• system/blockMeshDict
• constant/polyMesh/boundary
• 0/p
• 0/U

• The following dictionaries need to be adapted for the turbulence case


• constant/transportProperties
• system/controlDict
• system/fvSchemes
• system/fvSolution

• The following dictionaries need to be adapted for the turbulence case


• constant/momentumTransport
230
Flow past a cylinder – From laminar to turbulent flow
The transportProperties dictionary file
• This dictionary file is located in the directory constant.
• In this file we set the transport model and the kinematic viscosity (nu).

16 transportModel Newtonian;
17
19 nu nu [ 0 2 -1 0 0 0 0 ] 0.0002;

• Reminder:
• The diameter of the cylinder is 2.0 m.
• And we are targeting for a Re = 10000.

231
Flow past a cylinder – From laminar to turbulent flow
The momentumTransport dictionary file
• This dictionary file is located in the directory constant.

• In this dictionary file we select what model we would like to use (laminar or turbulent).
• In this case we are interested in modeling turbulence, therefore the dictionary is as follows

17 simulationType RAS; RANS type simulation


18
19 RAS RANS sub-dictionary
20 {
21 RASModel kOmegaSST; RANS model to use
22
23 turbulence on; Turn on/off turbulence. Runtime modifiable
24
25 printCoeffs on; Print coefficients at the beginning
26 }

• If you want to know the models available use the banana method.

232
Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary

17 application pimpleFoam;
• This case will start from the last saved solution (startFrom). If there is
18 no solution, the case will start from time 0 (startTime).
20 startFrom latestTime;
21 • It will run up to 500 seconds (endTime).
22 startTime 0;
23 • The initial time step of the simulation is 0.001 seconds (deltaT).
24 stopAt endTime;
25
26 endTime 500;
• It will write the solution every 1 second (writeInterval) of simulation time
27 (runTime).
28 deltaT 0.001;
29 • It will keep all the solution directories (purgeWrite).
30 writeControl runTime;
31 • It will save the solution in ascii format (writeFormat).
32 writeInterval 1;
33
34 purgeWrite 0;
• The write precision is 8 digits (writePrecision).
35
36 writeFormat ascii; • And as the option runTimeModifiable is on, we can modify all these
37 entries while we are running the simulation.
38 writePrecision 8;
39 • In line 48 we turn on the option adjustTimeStep. This option will
40 writeCompression off;
41 automatically adjust the time step to achieve the maximum desired
42 timeFormat general; courant number maxCo (line 50).
43
44 timePrecision 6; • We also set a maximum time step maxDeltaT in line 51.
45
46 runTimeModifiable yes; • Remember, the first time-step of the simulation is done using the value
47
48 adjustTimeStep yes; set in line 28 and then it is automatically scaled to achieve the desired
49 maximum values (lines 50-51).
50 maxCo 0.9;
51 maxDeltaT 0.1; • The feature adjustTimeStep is only present in the PIMPLE family
solvers, but it can be added to any solver by modifying the source code.

233
Flow past a cylinder – From laminar to turbulent flow
The fvSchemes dictionary

• In this case, for time discretization (ddtSchemes) we are using the


17 ddtSchemes blended CrankNicolson method. The blending coefficient goes from 0
18 {
21 default CrankNicolson 0.7; to 1, where 0 is equivalent to the Euler method and 1 is a pure Crank
22 } Nicolson.
24 gradSchemes
25 { • For gradient discretization (gradSchemes) we are using as default
29 default cellLimited leastSquares 1;
34 grad(U) cellLimited Gauss linear 1; option the leastSquares method. For grad(U) we are using Gauss
35 } linear with slope limiters (cellLimited). You can define different
37 divSchemes
38 {
methods for every term in the governing equations, for example, you
39 default none; can define a different method for grad(p).
45 div(phi,U) Gauss linearUpwindV grad(U);
47 div((nuEff*dev2(T(grad(U))))) Gauss linear; • For the discretization of the convective terms (divSchemes) we are
49 div(phi,k) Gauss linearUpwind default;
50 div(phi,omega) Gauss linearUpwind default;
using linearUpwindV interpolation method with slope limiters for the
57 } term div(phi,U).
59 laplacianSchemes
60 { • For the terms div(phi,k) and div(phi,omega) we are using
61 default Gauss linear limited 1;
62 }
linearUpwind interpolation method with no slope limiters. These terms
64 interpolationSchemes are related to the turbulence modeling.
65 {
66 default linear; • For the term div((nuEff*dev2(T(grad(U))))) we are using linear
67 }
69 snGradSchemes
interpolation (this term is related to turbulence modeling).
70 {
71 default limited 1; • For the discretization of the Laplacian (laplacianSchemes and
72 } snGradSchemes) we are using the Gauss linear limited 1 method.
74 wallDist
75 { • To compute the distance to the wall and normals to the wall, we use the
76 method meshWave;
77 } method meshWave. This only applies when using wall functions
(turbulence modeling).
• This method is second order accurate.

234
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary

17 solvers
• To solve the pressure (p) we are using the GAMG method, with an
18 { absolute tolerance of 1e-6 and a relative tolerance relTol of 0.001.
31 p Notice that we are fixing the number of minimum iterations (minIter).
32 {
33 solver GAMG;
34 tolerance 1e-6;
• To solve the final pressure correction (pFinal) we are using the PCG
35 relTol 0.001; method with the DIC preconditioner, with an absolute tolerance of 1e-6
36 smoother GaussSeidel; and a relative tolerance relTol of 0.
37 nPreSweeps 0;
38 nPostSweeps 2;
39 cacheAgglomeration on;
• Notice that we can use different methods between p and pFinal. In this
40 agglomerator faceAreaPair; case we are using a tighter tolerance for the last iteration.
41 nCellsInCoarsestLevel 100;
42 mergeLevels 1; • We are also fixing the number of minimum iterations (minIter). This
44 minIter 2;
45 }
entry is optional.
46
47 pFinal • To solve U we are using the solver PBiCGStab with the DILU
48 { preconditioner, an absolute tolerance of 1e-8 and a relative tolerance
49 solver PCG;
50 preconditioner DIC;
relTol of 0. Notice that we are fixing the number of minimum iterations
51 tolerance 1e-06; (minIter).
52 relTol 0;
53 minIter 3;
54 }
55
56 U
57 {
58 solver PBiCGStab;
59 preconditioner DILU;
60 tolerance 1e-08;
61 relTol 0;
62 minIter 3;
63 }

235
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary

17 solvers
• To solve UFinal we are using the solver PBiCGStab with an absolute
18 { tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
fixing the number of minimum iterations (minIter).
77 UFinal
78 {
79 solver PBiCGStab;
• To solve omega and omegaFinal we are using the solver PBiCGStab
80 preconditioner DILU; with an absolute tolerance of 1e-8 and a relative tolerance relTol of 0.
81 tolerance 1e-08; Notice that we are fixing the number of minimum iterations (minIter).
82 relTol 0;
83 minIter 3;
84 }
• To solve k we are using the solver PBiCGStab with an absolute
85 tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
86 omega fixing the number of minimum iterations (minIter).
87 {
88 solver PBiCGStab;
89 preconditioner DILU;
90 tolerance 1e-08;
91 relTol 0;
92 minIter 3;
93 }
94
95 omegaFinal
96 {
97 solver PBiCGStab;
98 preconditioner DILU;
99 tolerance 1e-08;
100 relTol 0;
101 minIter 3;
102 }
103
104 k
105 {
106 solver PBiCGStab;
107 preconditioner DILU;
108 tolerance 1e-08;
109 relTol 0;
110 minIter 3;
111 }
236
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary

113 kFinal
• To solve kFinal we are using the solver PBiCGStab with an absolute
114 { tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
115 solver PBiCGStab; fixing the number of minimum iterations (minIter).
116 preconditioner DILU;
117 tolerance 1e-08;
118 relTol 0;
• In lines 123-133 we setup the entries related to the pressure-velocity
119 minIter 3; coupling method used (PIMPLE in this case). Setting the keyword
120 } nOuterCorrectors to 1 is equivalent to running using the PISO method.
121 }
122
123 PIMPLE
• To gain more stability we are using 1 outer correctors
124 { (nOuterCorrectors), 3 inner correctors or PISO correctors
126 nOuterCorrectors 1; (nCorrectors), and 1 correction due to non-orthogonality
127 //nOuterCorrectors 2;
128 (nNonOrthogonalCorrectors).
129 nCorrectors 3;
130 nNonOrthogonalCorrectors 1; • Remember, adding corrections increase the computational cost.
133 }
134 • In lines 135-147 we setup the under-relaxation factors used during the
135 relaxationFactors
136 {
outer corrections of the PIMPLE method.
137 fields
138 { • The values defined correspond to the industry standard of the
139 p 0.3; SIMPLE method.
140 }
141 equations • By using under-relaxation we ensure diagonal equality.
142 {
143 U 0.7;
144 k 0.7;
• Be careful not use too low values as you will loose time accuracy.
145 omega 0.7;
146 } • If you want to disable under-relaxation, comment out these lines.
147 }

237
Flow past a cylinder – From laminar to turbulent flow
• The following dictionaries are new
• 0/k
• 0/omega
• 0/nut
These are the field variables related to the closure equations of the turbulent
model.

• As we are going to use the model we need to define the initial


conditions and boundaries conditions.
• To define the IC/BC we will use the free stream values of and
• In the following site, you can find a lot information about choosing initial and
boundary conditions for the different turbulence models:
• https://turbmodels.larc.nasa.gov/

238
Flow past a cylinder – From laminar to turbulent flow
Turbulence model free-stream boundary conditions
• The initial value for the turbulent kinetic energy can be found as follows

• The initial value for the specific kinetic energy can be found as follows

• Where is the viscosity ratio and is the turbulence intensity.

• If you are working with external aerodynamics or virtual wind tunnels, you can use the following
reference values for the turbulence intensity and the viscosity ratio. They work most of the
times, but it is a good idea to have some experimental data or a better initial estimate.

Low Medium High

1.0 % 5.0 % 10.0 %

1 10 100
239
Flow past a cylinder – From laminar to turbulent flow
The file 0/k
19 internalField uniform 0.00015;
20 • We are using uniform initial conditions (line 19).
21 boundaryField
22 { • For the in patch we are using a fixedValue boundary
23 out
24 { condition.
25 type inletOutlet;
26 inletValue uniform 0.00015; • For the out patch we are using an inletOutlet boundary
27 value uniform 0.00015;
28 } condition (this boundary condition avoids backflow).
29 sym1
30
31
{
type symmetryPlane;
• For the cylinder patch (which is base type wall), we
32 } are using the kqRWallFunction boundary condition.
33 sym2
34 {
This is a wall function, we are going to talk about this
35 type symmetryPlane; when we deal with turbulence modeling. Remember,
36 }
37 in we can use wall functions only if the patch is of base
38
39
{
type fixedValue;
type wall.
40 value uniform 0.00015;
41 } • The rest of the patches are constrained.
42 cylinder
43
44
{
type kqRWallFunction;
• FYI, the inlet velocity is 1 and the turbulence intensity is
45 value uniform 0.00015; equal to 1%.
46 }
47
48
back
{
• We will study with more details how to setup the
49 type empty; boundary conditions when we deal with turbulence
50 }
51 front modeling in the advanced modules.
52 {
53 type empty;
54 }
55 }

240
Flow past a cylinder – From laminar to turbulent flow
The file 0/omega
19 internalField uniform 0.075;
20
21 boundaryField • We are using uniform initial conditions (line 19).
22 {
23 out • For the in patch we are using a fixedValue boundary
24 {
25 type inletOutlet; condition.
26 inletValue uniform 0.075;
27
28 }
value uniform 0.075; • For the out patch we are using an inletOutlet boundary
29 sym1 condition (this boundary condition avoids backflow).
30 {
31
32 }
type symmetryPlane;
• For the cylinder patch (which is base type wall), we
33 sym2 are using the omegaWallFunction boundary condition.
34 {
35 type symmetryPlane; This is a wall function; we are going to talk about this
36
37
}
in
when we deal with turbulence modeling. Remember, we
38 { can use wall functions only if the patch is of base type
39
40
type
value
fixedValue;
uniform 0.075;
wall.
41 }
42 cylinder • The rest of the patches are constrained.
43 {
44
45
type
Cmu
omegaWallFunction;
0.09;
• FYI, the inlet velocity is 1 and the eddy viscosity ratio is
46 kappa 0.41; equal to 10.
47 E 9.8;
48
49
beta1
value
0.075;
uniform 0.075;
• We will study with more details how to setup the
50 } boundary conditions when we deal with turbulence
51 back
52 { modeling in the advanced modules.
53 type empty;
54 }
55 front
56 {
57 type empty;
58 }
59 }
241
Flow past a cylinder – From laminar to turbulent flow
The file 0/nut
19 internalField uniform 0;
20 • We are using uniform initial conditions (line 19).
21 boundaryField
22
23
{
out
• For the in patch we are using the calculated boundary
24 { condition (nut is computed from kappa and omega)
25 type calculated;
26
27 }
value uniform 0; • For the out patch we are using the calculated
28 sym1 boundary condition (nut is computed from kappa and
29 {
30 type symmetryPlane; omega)
31 }
32 sym2 • For the cylinder patch (which is base type wall), we
33 {
34 type symmetryPlane; are using the nutkWallFunction boundary condition.
35
36
}
in
This is a wall function, we are going to talk about this
37 { when we deal with turbulence modeling. Remember, we
38 type calculated;
39 value uniform 0;
can use wall functions only if the patch is of base type
40 } wall.
41 cylinder
42 {
43 type nutkWallFunction; • The rest of the patches are constrained.
44 Cmu 0.09;
45 kappa 0.41; • Remember, the turbulent viscosity (nut) is equal to
46 E 9.8;
47 value uniform 0;
48 }
49 back
50 {
51 type empty;
52 } • We will study with more details how to setup the
53 front
54 { boundary conditions when we deal with turbulence
55
56 }
type empty;
modeling in the advanced modules.
57 }

242
Flow past a cylinder – From laminar to turbulent flow
Running the case – Setting a turbulent case
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c14
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this case we will use
blockMesh.
• To run this case, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> renumberMesh -overwrite
$> pimpleFoam | tee log.solver
4.
You will need to launch this script in a different terminal

$> pyFoamPlotWatcher.py log.solver


5.
You will need to launch this script in a different terminal

$> gnuplot scripts0/plot_coeffs


6.
You will need to launch this script in a different terminal

7. $> pimpleFoam –postprocess –func yPlus –latestTime -noFunctionObjects

8. $> paraFoam
243
Flow past a cylinder – From laminar to turbulent flow
Running the case – Setting a turbulent case

• In step 3 we use the utility renumberMesh to make the linear system more diagonal
dominant, this will speed-up the linear solvers.
• In step 4 we run the simulation and save the log file. Notice that we are sending the
job to background.
• In step 5 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
job is running in background, we can launch this utility in the same terminal tab.
• In step 6 we use the gnuplot script scripts0/plot_coeffs to plot the force
coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
• In step 7 we use the utility postProcess to compute the value of each saved
solution (we are going to talk about when we deal with turbulence modeling).

244
Flow past a cylinder – From laminar to turbulent flow
pimpleFoam output screen
Courant Number mean: 0.088931706 max: 0.90251464 Courant number
deltaT = 0.040145538 Time step
Time = 499.97 Simulation time
PIMPLE: iteration 1 Outer iteration 1 (nOuterCorrectors)
DILUPBiCG: Solving for Ux, Initial residual = 0.0028528538, Final residual = 9.5497298e-11, No Iterations 3
DILUPBiCG: Solving for Uy, Initial residual = 0.0068876991, Final residual = 7.000938e-10, No Iterations 3
GAMG: Solving for p, Initial residual = 0.25644342, Final residual = 0.00022585963, No Iterations 7
GAMG: Solving for p, Initial residual = 0.0073871161, Final residual = 5.2798526e-06, No Iterations 8
time step continuity errors : sum local = 3.2664019e-10, global = -1.3568363e-12, cumulative = -9.8446438e-08
GAMG: Solving for p, Initial residual = 0.16889316, Final residual = 0.00014947209, No Iterations 7
GAMG: Solving for p, Initial residual = 0.0051876466, Final residual = 3.7123156e-06, No Iterations 8
time step continuity errors : sum local = 2.2950163e-10, global = -8.0710768e-13, cumulative = -9.8447245e-08
PIMPLE: iteration 2 Outer iteration 2 (nOuterCorrectors)
DILUPBiCG: Solving for Ux, Initial residual = 0.0013482181, Final residual = 4.1395468e-10, No Iterations 3
DILUPBiCG: Solving for Uy, Initial residual = 0.0032433196, Final residual = 3.3969121e-09, No Iterations 3
GAMG: Solving for p, Initial residual = 0.10067317, Final residual = 8.9325549e-05, No Iterations 7
GAMG: Solving for p, Initial residual = 0.0042844521, Final residual = 3.0190597e-06, No Iterations 8
time step continuity errors : sum local = 1.735023e-10, global = -2.0653335e-13, cumulative = -9.8447452e-08
GAMG: Solving for p, Initial residual = 0.0050231165, Final residual = 3.2656397e-06, No Iterations 8
DICPCG: Solving for p, Initial residual = 0.00031459519, Final residual = 9.4260163e-07, No Iterations 36 pFinal
time step continuity errors : sum local = 5.4344408e-11, global = 4.0060595e-12, cumulative = -9.8443445e-08
DILUPBiCG: Solving for omega, Initial residual = 0.00060510266, Final residual = 1.5946601e-10, No Iterations 3
DILUPBiCG: Solving for k, Initial residual = 0.0032163247, Final residual = 6.9350899e-10, No Iterations 3
bounding k, min: -3.6865398e-05 max: 0.055400108 average: 0.0015914926
ExecutionTime = 1689.51 s ClockTime = 1704 s

fieldAverage fieldAverage output:


Calculating averages Message letting you know that kappa and omega residuals
the variable is becoming
forceCoeffs forceCoeffs_object output:
Cm = 0.0023218797
unbounded
Cd = 1.1832452
Cl = -1.3927646 Force coefficients
Cl(f) = -0.69406044
Cl(r) = -0.6987042

fieldMinMax minmaxdomain output:


min(p) = -1.5466372 at location (-0.040619337 -1.033408 0)
max(p) = 0.54524589 at location (-1.033408 0.040619337 1.4015759e-17)
min(U) = (0.94205232 -1.0407426 -5.0319219e-19) at location (-0.70200781 -0.75945224 -1.3630525e-17)
max(U) = (1.8458167 0.0047368607 4.473279e-19) at location (-0.12989625 -1.0971865 2.4694467e-17) Minimum and
min(k) = 1e-15 at location (1.0972618 1.3921931 -2.2329889e-17) maximum values
max(k) = 0.055400108 at location (2.1464795 0.42727634 0)
min(omega) = 0.2355751 at location (29.403674 19.3304 0)
max(omega) = 21.477072 at location (1.033408 0.040619337 1.3245285e-17) 245
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the yPlus utility.

Time = 500.01
Reading field U

Reading/calculating face flux field phi


Transport model
Selecting incompressible transport model Newtonian
Selecting RAS turbulence model kOmegaSST Turbulence model
kOmegaSSTCoeffs Model coefficients
{
alphaK1 0.85;
alphaK2 1;
alphaOmega1 0.5;
alphaOmega2 0.856;
gamma1 0.55555556; Patch where we are computing y+
gamma2 0.44;
beta1 0.075;
beta2 0.0828;
betaStar 0.09;
a1 0.31;
b1 1;
c1 10;
F3 false; Minimum, maximum and average values
}

Patch 4 named cylinder y+ : min: 0.94230389 max: 12.696632 average: 7.3497345

Writing yPlus to field yPlus Writing the field to the solution directory

246
Flow past a cylinder – From laminar to turbulent flow
Using a compressible solver
• So far, we have only used incompressible solvers.
• Let us use the compressible solver rhoPimpleFoam, which is a,
Transient solver for laminar or turbulent flow of compressible fluids for HVAC and
similar applications. Uses the flexible PIMPLE (PISO-SIMPLE) solution for time-
resolved and pseudo-transient simulations.

• When working with compressible solver we need to define the thermodynamical


properties of the working fluid and the temperature field (we are also solving the
energy equation).
• Also remember, compressible solvers use absolute pressure. Conversely,
incompressible solvers use relative pressure.
• This case is already setup in the directory

$PTOFC/101OF/vortex_shedding/c24

247
Flow past a cylinder – From laminar to turbulent flow
• The following dictionaries remain unchanged

• system/blockMeshDict
• constant/polyMesh/boundary

• Reminder:
• The diameter of the cylinder is 0.002 m.
• The working fluid is air at 20° Celsius and at a sea level.
• Isothermal flow.
• And we are targeting for a Re = 200.

248
Flow past a cylinder – From laminar to turbulent flow
The constant directory

• In this directory, we will find the following compulsory dictionary files:

• thermophysicalProperties
• momentumTransport

• thermophysicalProperties contains the definition of the physical


properties of the working fluid.
• momentumTransport contains the definition of the turbulence model to use.

249
Flow past a cylinder – From laminar to turbulent flow
The thermophysicalProperties dictionary file

• This dictionary file is located in the directory constant.


18 thermoType Thermophysical models are concerned with energy, heat
19 {
20 type hePsiThermo; and physical properties.
21 mixture pureMixture;
22 transport const; • In the sub-dictionary thermoType (lines 18-27), we
23 thermo hConst;
24 equationOfState perfectGas; define the thermophysical models.
25 specie specie;
26 energy sensibleEnthalpy; • The transport modeling concerns evaluating dynamic
27 }
28 viscosity (line 22). In this case the viscosity is constant.
29 mixture
30
31
{
specie
• The thermodynamic models (thermo) are concerned with
32 { evaluating the specific heat Cp (line 23). In this case Cp
33 nMoles 1;
34 molWeight 28.9; is constant
35 }
36 thermodynamics • The equationOfState keyword (line 24) concerns to the
37 {
38 Cp 1005; equation of state of the working fluid. In this case
39 Hf 0;
40 }
41 transport
42 {
43 mu 1.84e-05;
44 Pr 0.713;
45 } • The form of the energy equation to be used in the
46 }
solution is specified in line 26 (energy). In this case we
are using enthalpy (sensibleEnthalpy).

250
Flow past a cylinder – From laminar to turbulent flow
The thermophysicalProperties dictionary file

• In the sub-dictionary mixture (lines 29-46), we define the


18 thermoType thermophysical properties of the working fluid.
19 {
20 type hePsiThermo;
21 mixture pureMixture;
• In this case, we are defining the properties for air at 20°
22 transport const; Celsius and at a sea level.
23 thermo hConst;
24 equationOfState perfectGas;
25 specie specie;
26 energy sensibleEnthalpy;
27 }
28
29 mixture
30 {
31 specie
32 {
33 nMoles 1;
34 molWeight 28.9;
35 }
36 thermodynamics
37 {
38 Cp 1005;
39 Hf 0;
40 }
41 transport
42 {
43 mu 1.84e-05;
44 Pr 0.713;
45 }
46 }

251
Flow past a cylinder – From laminar to turbulent flow
The turbulenceProperties dictionary file
• In this dictionary file we select what model we would like to use (laminar or
turbulent).
• This dictionary is compulsory.
• As we do not want to model turbulence, the dictionary is defined as follows,

17 simulationType laminar;

252
Flow past a cylinder – From laminar to turbulent flow
The 0 directory

• In this directory, we will find the dictionary files that contain the boundary and
initial conditions for all the primitive variables.
• As we are solving the compressible laminar Navier-Stokes equations, we will
find the following field files:

• p (pressure)
• T (temperature)
• U (velocity field)

253
Flow past a cylinder – From laminar to turbulent flow
The file 0/p
• This file contains the boundary and initial conditions
17
18
dimensions [1 -1 -2 0 0 0 0];
for the scalar field pressure (p). We are working
19 internalField uniform 101325; with absolute pressure.
20
21
22
boundaryField
{
• Contrary to incompressible flows where we defined
23 in relative pressure, this is the absolute pressure.
24 {
25
26 }
type zeroGradient;
• Also, pay attention to the units (line 17). The
28 out pressure is defined in Pascal.
29 {
30
31
type
value
fixedValue;
uniform 101325;
• We are using uniform initial conditions (line 19).
32 }
34 cylinder • For the in patch we are using a zeroGradient
35 {
36 type zeroGradient; boundary condition.
37 }
39 sym1 • For the outlet patch we are using a fixedValue
40 {
41 type symmetryPlane; boundary condition.
42 }
44 sym2 • For the cylinder patch we are using a zeroGradient
45 {
46 type symmetryPlane; boundary condition.
47 }
49 back • The rest of the patches are constrained.
50 {
51 type empty;
52 }
54 front
55 {
56 type empty;
57 }
58 }

254
Flow past a cylinder – From laminar to turbulent flow
The file 0/T
17 dimensions [0 0 0 -1 0 0 0];
• This file contains the boundary and initial conditions
18 for the scalar field temperature (T).
19 internalField uniform 293.15;
20
21 boundaryField • Also, pay attention to the units (line 17). The
22 { temperature is defined in Kelvin.
23 in
24 {
25 type fixedValue; • We are using uniform initial conditions (line 19).
26 value $internalField;
27 } • For the in patch we are using a fixedValue boundary
29 out
30 { condition.
31 type inletOutlet;
32 value $internalField; • For the out patch we are using a inletOutlet
33 inletValue $internalField;
34 } boundary condition (in case of backflow).
36 cylinder
37 { • For the cylinder patch we are using a zeroGradient
38 type zeroGradient;
39 } boundary condition.
41 sym1
42 { • The rest of the patches are constrained.
43 type symmetryPlane;
44 }
46 sym2
47 {
48 type symmetryPlane;
49 }
51 back
52 {
53 type empty;
54 }
56 front
57 {
58 type empty;
59 }
60 }

255
Flow past a cylinder – From laminar to turbulent flow
The file 0/U
17 dimensions [0 1 -1 0 0 0 0];
18 • This file contains the boundary and initial conditions
19
20
internalField uniform (1.5 0 0); for the dimensional vector field U.
21 boundaryField
22 { • We are using uniform initial conditions and the
23
24
in
{
numerical value is (1.5 0 0) (keyword internalField in
25 type fixedValue; line 19).
26 value uniform (1.5 0 0);
27
29
}
out
• For the in patch we are using a fixedValue boundary
30 { condition.
31 type inletOutlet;
32
33
phi
inletValue
phi;
uniform (0 0 0);
• For the out patch we are using a inletOutlet
34 value uniform (0 0 0); boundary condition (in case of backflow).
35 }
37 cylinder
38 {
• For the cylinder patch we are using a zeroGradient
39 type fixedValue; boundary condition.
40 value uniform (0 0 0);
41 }
43 sym1 • The rest of the patches are constrained.
44 {
45 type symmetryPlane;
46 }
48 sym2
49 {
50 type symmetryPlane;
51 }
53 back
54 {
55 type empty;
56 }
58 front
59 {
60 type empty;
61 }
62 }

256
Flow past a cylinder – From laminar to turbulent flow
The system directory

• The system directory consists of the following compulsory dictionary files:


• controlDict
• fvSchemes
• fvSolution

• controlDict contains general instructions on how to run the case.


• fvSchemes contains instructions for the discretization schemes that will be
used for the different terms in the equations.
• fvSolution contains instructions on how to solve each discretized linear
equation system.

257
Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary

17 application rhoPimpleFoam;
• This case will start from the last saved solution (startFrom). If there is
18 no solution, the case will start from time 0 (startTime).
19 startFrom startTime;
20 //startFrom latestTime; • It will run up to 0.3 seconds (endTime).
21
22 startTime 0; • The initial time step of the simulation is 0.00001 seconds (deltaT).
23
24 stopAt endTime;
25 //stopAt writeNow;
• It will write the solution every 0.0025 seconds (writeInterval) of
26 simulation time (adjustableRunTime). The option adjustableRunTime
27 endTime 0.3; will adjust the time-step to save the solution at the precise intervals. This
28
29 deltaT 0.00001; may add some oscillations in the solution as the CFL is changing.
30
31 writeControl adjustableRunTime; • It will keep all the solution directories (purgeWrite).
32
33 writeInterval 0.0025; • It will save the solution in ascii format (writeFormat).
34
35 purgeWrite 0; • And as the option runTimeModifiable is on, we can modify all these
36
37 writeFormat ascii; entries while we are running the simulation.
38
39 writePrecision 10; • In line 49 we turn on the option adjustTimeStep. This option will
40 automatically adjust the time step to achieve the maximum desired
41 writeCompression off;
42 courant number (line 50).
43 timeFormat general;
44 • We also set a maximum time step in line 51.
45 timePrecision 6;
46 • Remember, the first time step of the simulation is done using the value
47 runTimeModifiable true;
set in line 28 and then it is automatically scaled to achieve the desired
48
49 adjustTimeStep yes; maximum values (lines 66-67).
50 maxCo 1;
51 maxDeltaT 1; • The feature adjustTimeStep is only present in the PIMPLE family
solvers, but it can be added to any solver by modifying the source code.

258
Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary

55 functions • As usual, at the bottom of the controlDict dictionary file


56 { we define the functionObjects (lines 55-236).
178 forceCoeffs_object
179 { • Of special interest is the functionObject
188
189
type forceCoeffs;
functionObjectLibs ("libforces.so");
forceCoeffs_object.
190 patches (cylinder);
191 • As we changed the domain dimensions and the inlet
192
193
pName p;
Uname U;
velocity, we need to update the reference values (lines 204-
194 //rhoName rhoInf; 206).
195 rhoInf 1.205;
196
197 //// Dump to file
• It is also important to update the reference density (line
198 log true; 195).
199
200 CofR (0.0 0 0);
201 liftDir (0 1 0);
202 dragDir (1 0 0);
203 pitchAxis (0 0 1);
204 magUInf 1.5;
205 lRef 0.001;
206 Aref 0.000002;
207
208 outputControl timeStep;
209 outputInterval 1;
210 }

235
236 };

259
Flow past a cylinder – From laminar to turbulent flow
The fvSchemes dictionary

17 ddtSchemes • In this case, for time discretization (ddtSchemes) we are


18
19
{
default Euler;
using the Euler method.
20 }
21 • For gradient discretization (gradSchemes) we are using the
22
23
gradSchemes
{
leastSquares method.
29 default cellLimited leastSquares 1;
34 } • For the discretization of the convective terms (divSchemes)
35
36 divSchemes
we are using linearUpwind interpolation with no slope limiters
37 { for the term div(phi,U).
38 default none;
39
40
div(phi,U) Gauss linearUpwindV default;
• For the terms div(phi,K) (kinetic energy) and div(phi,h)
41 div(phi,K) Gauss linear; (enthalpy) we are using linear interpolation method with no
42 div(phi,h) Gauss linear;
43 slope limiters.
44 div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear;
45 } • For the term div(((rho*nuEff)*dev2(T(grad(U))))) we are
46
47 laplacianSchemes using linear interpolation (this term is related to the turbulence
48
49
{
default Gauss linear limited 1;
modeling).
50 }
51 • For the discretization of the Laplacian (laplacianSchemes
52
53
interpolationSchemes
{
and snGradSchemes) we are using the Gauss linear limited
54 default linear; 1 method.
55 }
56
57 snGradSchemes
• This method is second order accurate.
58 {
59 default limited 1;
60 }

260
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary

17 solvers • To solve the pressure (p) we are using the PCG method with
18
20
{
p
an absolute tolerance of 1e-6 and a relative tolerance relTol
21 { of 0.01.
22 solver PCG;
23
24
preconditioner
tolerance
DIC;
1e-06;
• The entry pFinal refers to the final correction of the PISO
25 relTol 0.01; loop. Notice that we are using macro expansion ($p) to copy
26 minIter 2;
27 } the entries from the sub-dictionary p.
46 pFinal
47 { • To solve U and UFinal (U.*) we are using the solver
48 $p;
49 relTol 0; PBiCGStab with an absolute tolerance of 1e-8 and a relative
50
51 }
minIter 2;
tolerance relTol of 0.
53 "U.*"
54 { • To solve hFinal (enthalpy) we are using the solver
55
56
solver PBiCGStab;
preconditioner DILU;
PBiCGStab with an absolute tolerance of 1e-8 and a relative
57 tolerance 1e-08; tolerance relTol of 0.
58 relTol 0;
59
60 }
minIter 2;
• To solve rho and rhoFinal (rho.*) we are using the diagonal
74 hFinal solver (remember rho is found from the equation of state, so
75 {
76 solver PBiCGStab; this is a back-substitution).
77 preconditioner DILU;
78 tolerance 1e-08; • FYI, solving for the velocity is relative inexpensive, whereas
79 relTol 0;
80 minIter 2; solving for the pressure is expensive.
81 }
83 "rho.*" • Be careful with the enthalpy, it might cause oscillations.
84 {
85 solver diagonal;
86 }
87 }

261
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary

88 • The PIMPLE sub-dictionary contains entries related to the


89
90
PIMPLE
{
pressure-velocity coupling (in this case the PIMPLE method).
91 momentumPredictor yes;
92 nOuterCorrectors 1; • Setting the keyword nOuterCorrectors to 1 is equivalent to
93
94
nCorrectors 2;
nNonOrthogonalCorrectors 1;
running using the PISO method.
103 pMinFactor 0.5;
104 pMaxFactor 2.0; • Hereafter we are doing 2 PISO correctors (nCorrectors) and
105 }
1 non-orthogonal corrections (nNonOrthogonalCorrectors).
• In lines 95-96 we set the minimum and maximum physical
values of rho (density).
• If we increase the number of nCorrectors and
nNonOrthogonalCorrectors we gain more stability but at a
higher computational cost.
• The choice of the number of corrections is driven by the
quality of the mesh and the physics involve.
• You need to do at least one PISO loop (nCorrectors).

262
Flow past a cylinder – From laminar to turbulent flow
Running the case – Using a compressible solver
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c24
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this case we will use
blockMesh.
• To run this case, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> transformPoints –scale ‘(0.001 0.001 0.001)’
4. $> renumberMesh -overwrite
5. $> rhoPimpleFoam | tee log
$> pyFoamPlotWatcher.py log
6.
You will need to launch this script in a different terminal

$> gnuplot scripts0/plot_coeffs


7.
You will need to launch this script in a different terminal

8. $> rhoPimpleFoam –postProcess –func MachNo


9. $> paraFoam
263
Flow past a cylinder – From laminar to turbulent flow
Running the case – Using a compressible solver

• In step 3 we scale the mesh.


• In step 4 we use the utility renumberMesh to make the linear system more diagonal
dominant, this will speed-up the linear solvers.
• In step 5 we run the simulation and save the log file. Notice that we are sending the
job to background.
• In step 6 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
job is running in background, we can launch this utility in the same terminal tab.
• In step 7 we use the gnuplot script scripts0/plot_coeffs to plot the force
coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
• In step 8 we use the utility MachNo to compute the Mach number.

264
Flow past a cylinder – From laminar to turbulent flow
rhoPimpleFoam output screen
Courant Number mean: 0.1280224248 max: 0.9885863338 Courant number
deltaT = 3.816512052e-05 Time step
Time = 0.3

diagonal: Solving for rho, Initial residual = 0, Final residual = 0, No Iterations 0 Solving for density (rho)
PIMPLE: iteration 1
DILUPBiCG: Solving for Ux, Initial residual = 0.003594731129, Final residual = 3.026673755e-11, No Iterations 5
DILUPBiCG: Solving for Uy, Initial residual = 0.01296036298, Final residual = 1.223236662e-10, No Iterations 5
DILUPBiCG: Solving for h, Initial residual = 0.01228951539, Final residual = 2.583236461e-09, No Iterations 4 h residuals
DICPCG: Solving for p, Initial residual = 0.01967621449, Final residual = 8.797612158e-07, No Iterations 77
DICPCG: Solving for p, Initial residual = 0.003109422612, Final residual = 9.943030465e-07, No Iterations 69
diagonal: Solving for rho, Initial residual = 0, Final residual = 0, No Iterations 0
time step continuity errors : sum local = 6.835363016e-11, global = 4.328592697e-12, cumulative = 2.366774797e-09
rho max/min : 1.201420286 1.201382023 pFinal
DICPCG: Solving for p, Initial residual = 0.003160602108, Final residual = 9.794177338e-07, No Iterations 69
DICPCG: Solving for p, Initial residual = 0.0004558492254, Final residual = 9.278622052e-07, No Iterations 58
diagonal: Solving for rho, Initial residual = 0, Final residual = 0, No Iterations 0 Solving for density (rhoFinal)
time step continuity errors : sum local = 6.38639685e-11, global = 1.446434866e-12, cumulative = 2.368221232e-09
rho max/min : 1.201420288 1.201381976 Max/min density values
ExecutionTime = 480.88 s ClockTime = 490 s

faceSource inMassFlow output:


sum(in) of phi = -7.208447027e-05

faceSource outMassFlow output:


sum(out) of phi = 7.208444452e-05

fieldAverage fieldAverage output:


Calculating averages

Writing average fields

forceCoeffs forceCoeffs_object output:


Cm = -0.001269886395
Cd = 1.419350733
Cl = 0.6247248606 Force coefficients
Cl(f) = 0.3110925439 Minimum and
Cl(r) = 0.3136323167 maximum values
fieldMinMax minmaxdomain output:
min(p) = 101322.7878 at location (-0.0001215826043 0.001027092827 0)
max(p) = 101326.4972 at location (-0.001033408037 -4.061934599e-05 0)
min(U) = (-0.526856427 -0.09305459972 -8.110485132e-25) at location (0.002039092041 -0.0004058872656 -3.893823418e-20)
max(U) = (2.184751599 0.2867627526 4.83091257e-25) at location (0.0001663574444 0.001404596295 0)
min(T) = 293.1487423 at location (-5.556854517e-05 0.001412635233 0)
max(T) = 293.1509903 at location (-0.00117685237 -4.627394552e-05 3.016083257e-20) 265
Flow past a cylinder – From laminar to turbulent flow
• In the directory $PTOFC/101OF/vortex_shedding, you will find 29 variations of the cylinder case involving
different solvers and models. Feel free to explore all them.
• This is what you will find in each directory,
• c1 = blockMesh – icoFoam – Unsteady solver – Re = 200.
• c2 = fluentMeshToFoam – icoFoam – Unsteady solver – Re = 200.
• c3 = blockMesh – pisoFoam – Unsteady solver – Field initialization – Re = 200.
• c4 = blockMesh – potentialFoam – Re = 200.
• c5 = blockMesh – mapFields – pisoFoam – Unsteady solver – original mesh – Re = 200.
• c6 = blockMesh – mapFields – pisoFoam – Unsteady solver – Finer mesh – Re = 200.
• c7 = blockMesh – pimpleFoam – Unsteady solver – Re = 200 – No turbulent model.
• c8 = blockMesh – pisoFoam – Unsteady solver – Re = 200 – No turbulent model.
• c9 = blockMesh – pisoFoam – Unsteady solver – Re = 200 – K-Omega SST turbulent model.
• c10 = blockMesh – simpleFoam – Steady solver – Re = 200 – No turbulent model.
• c11 = blockMesh – simpleFoam – Steady solver – Re = 40 – No turbulent model.
• c12 = blockMesh – pisoFoam – Unsteady solver – Re = 40 – No turbulent model.
• c14 = blockMesh – pimpleFoam – Unsteady solver – Re = 10000 – K-Omega SST turbulence model with wall functions.
• c15 = blockMesh – pimpleFoam – Unsteady solver – Re = 100000 – K-Omega SST turbulence model with wall functions
• c16 = blockMesh – simpleFoam – Steady solver – Re = 100000 – K-Omega SST turbulence model no wall functions.
• c17 = blockMesh – simpleFoam – Steady solver – Re = 100000 – K-Omega SST turbulent model with wall functions.
• c18 = blockMesh – pisoFoam – Unsteady solver – Re = 100000, LES Smagorinsky turbulent model.

266
Flow past a cylinder – From laminar to turbulent flow
• This is what you will find in each directory,
• c19 = blockMesh – pimpleFoam – Unsteady solver – Re = 1000000 – Spalart Allmaras turbulent model no wall functions.
• c20 = blockMesh – rhoPimpleFoam – Unsteady solver – Mach = 2.0 – Compressible – Laminar.
• c21 = blockMesh – rhoPimpleFoam –Unsteady solver – Mach = 2.0 – Unsteady solver – Compressible – K-Omega SST
turbulent model with wall functions.
• c22 = blockMesh – rhoSimpleFoam – Mach = 2.0 – Steady solver – Compressible – K-Omega SST turbulent model with
wall functions.
• c23 = blockMesh – rhoPimpleFoam – Mach = 2.0 – LTS Pseudo-transient solver – Compressible – K-Omega SST
turbulent model with wall functions.
• c24 = blockMesh – pimpleFoam – Unsteady solver – Re = 200 – No turbulent model – Source terms (momentum)
• c25 = blockMesh – pimpleFoam – Unsteady solver – Re = 200 – No turbulent model – Source terms (scalar transport)
• c26 = blockMesh – rhoPimpleFoam – Unsteady solver – Re = 200 – Laminar, isothermal
• c27 = blockMesh – rhoPimpleFoam – Unsteady solver – Re = 20000 – Turbulent, compressible
• c28 = blockMesh – pimpleDyMFoam – Unsteady solver – Re = 200 – Laminar, moving cylinder (oscillating).
• c29 = blockMesh – pimpleDyMFoam/pimpleFoam – Unsteady solver – Re = 200 – Laminar, rotating cylinder using AMI
patches.
• c30 = blockMesh – interFoam – Unsteady solver – Laminar, multiphase, free surface.
• c31 = blockMesh – pimpleFoam – Unsteady solver – Laminar with source terms and AMR.

267
Module 2
Solid modeling

268
Roadmap

1. Solid modeling preliminaries and


introduction to Onshape

269
Solid modeling – Preliminaries
• There is no wrong or right way when doing solid modeling for CFD. The
only rule you should keep in mind is that by the end of the day you should
get a smooth, clean, and watertight geometry.
• A watertight geometry means a close body with no holes or overlapping
surfaces.
• Have in mind that the quality of the mesh and hence of the solution, greatly
depends on the geometry. So always do your best when creating the
geometry.
• During this solid modeling session we are going to show you how to get
started with the geometry generation tools. The rest is on you.
• The best way to learn how to use these tools is by doing.
• The tool of our choice is Onshape (www.onshape.com). However, have in
mind that all CAD and solid modeling applications have similar capabilities.

270
Solid modeling – Preliminaries
• There are always many ways to accomplish a task when creating a
geometry, this give you the freedom to work in a way that is comfortable to
you. Hereafter we are going to show you our way.
• Before starting to create your geometry, think about a strategy to employ to
create your design, this is what we call design intent.
• Choose one feature over other.
• Dimensioning strategy.
• Order of the operations.
• Parametrization.
• Single or multiple parts.
• Do I need to parametrize my design, or should I use direct
modeling?

• We are going to work with design intent during the hands-on sessions.
271
Solid modeling – Preliminaries
Geometry defeaturing
• Many times, it is not necessary to model all the details of the geometry. In these cases you
should consider simplifying the geometry (geometry defeaturing).
• Geometry defeaturing can save you a lot of time when generating the mesh. So be smart,
and use it whenever is possible.

Are the nuts and bolts necessary


in my simulation?

Do we really need to
capture the fillet details?

Do we need to
model the flange?
272
Solid modeling – Preliminaries
Geometry defeaturing
• Would you use all these geometry details for a CFD simulations?

273
Solid modeling using Onshape
• Onshape is a professional CAD/solid modeling application.
• It provides powerful parametric and direct modeling capabilities.
• It is cloud based therefore you do not need to install any software.
• Documents are shareable.
• Multiple users can work in the same document at the same time
(simultaneous editing).
• It runs in any device with a working web browser.
• Users can implement their own features using Onshape scripting language
(featureScript).
• Users can access and modify documents in a programmatic way using
python or nodejs.
• It is freely available for educational use and personal use.
• To start using Onshape register at: https://cad.onshape.com/

274
Solid modeling using Onshape
• Even if you have not used a CAD software before, you will find the GUI easy to use.
• You will notice that there is no save button because everything you do is
automatically saved.
Help
Versioning, branching, and history menu Toolbar

Undo/Redo View cube

Enter to sketch mode

Feature list

Parts list

3D area
Document tabs 275
Solid modeling using Onshape
• Mouse interaction in the 3D area (it can be configured in the preference area).

Mouse interaction in the


3D viewer

Selection

Rotate

Pan

Zoom

• To deselect click in an empty region in the 3D area


276
Solid modeling using Onshape
• Parametric modeling and feature based modeling are crucial components in the
design experience.
• In Onshape you will find the following features:

Feature toolbar:

Sketch toolbar:

• Remember, sketches are the core of good 3D designs and parametrization.


• This is all we need to know about Onshape.
• Let us work with a simple geometry to understand how Onshape works.
• We also will show you a few clicks and picks you should be aware of.

277
Solid modeling using Onshape
• Let us create this solid using the dimensions illustrated.

Note: all the dimensions are in meters


278
Solid modeling using Onshape
• Enter the document page and create a new design

Create new document

279
Solid modeling using Onshape
• In the part studio page, select the top plane and start a new sketch.

2. Start a new sketch

1. Select this plane

Part studio page

280
Solid modeling using Onshape
• In the part studio page, select the top plane and start a new sketch.

Right click on the 3D


area and select view
normal to sketch plane

281
Solid modeling using Onshape
• Using the sketching features, draw the following line.
When you are done sketching
press the checkmark

In sketch mode: Use the dimensions illustrated to


• Blue geometry is free to move. draw this polyline
• Black geometry is fully defined.
• Red geometry is over-constrained.
282
Solid modeling using Onshape
• Select the right plane and start a new sketch.
• Draw a circle with the center in the origin (the white point).
When you are done sketching
press the checkmark

Select this plane and


start a new sketch

Origin

Use the dimensions illustrated to


draw the circle

283
Solid modeling using Onshape
• Use the sweep feature to create a new solid.

Select the circle as the Select new solid Select the lines as the
face to sweep sweep patch

Sweep feature

284
Solid modeling using Onshape
• At this point, you should have this solid.

Solid name.
Right click to rename
or view the properties

285
Solid modeling using Onshape
• Let us add the new inlet to the pipe.
• Create a new sketch in the top plane or edit the initial sketch.
• Hereafter we will edit the initial sketch.

Right click and choose


the option edit

Sketch these new lines using the dimensions illustrated.


Pay attention to the angle and the offset distance.

286
Solid modeling using Onshape
• Create a plane normal to a line and passing through a point

1. Create new plane

2. Select point normal,


and select the line and
point as illustrated

To get better visibility, you


can hide the solid or adjust Use this line to create
the transparency the new plane

Use this point to create


the new plane

287
Solid modeling using Onshape
• Sketch a circle in the newly created plane.

New plane

To get better visibility, you


can hide the solid or adjust
the transparency

Sketch this circle in the newly created plane

288
Solid modeling using Onshape
• Using the feature extrude to create a new solid using the previous sketch.
• Extrude the circle until in intercept the solid.
Add the new solid to the previous part (boolean operation)
Feature extrusion

Use this sketch as the


base for the extrusion
Extrusion.
You can manually move
the extrusion using the
triad manipulator, or
input a value

Instead of the extrusion feature, you could use


the sweep feature. You will need to create a
longer sweep path.
289
Solid modeling using Onshape
• At this point you should have the following solid.

290
Solid modeling using Onshape
• If you want to know the mass properties of the solid, select it, and then click on the
mass properties icon.
• To get the inertia, you will need to assign a material.

Select the part.


Right click and select
assign material.

Mass properties icon

291
Solid modeling using Onshape
• To export the solid model, right click on the part name and select the option export.
• Choose the desired format. In this case choose STL.

Right click and select the


option export.

292
Solid modeling using Onshape
• Parametric modeling and feature-based modeling are two of the most powerful tools
available in any CAD/solid modeling applications.
• They are crucial components in the design experience, especially when dealing with
design intent.
• Experimenting with dimension schemes is one of the best ways to improve your
understanding of design intent.

• To learn more about Onshape, you can visit their learning center:
https://learn.onshape.com/

• Finally, feel free to visit our youtube channel where you will find a few solid modeling
videos in the context of CFD and OpenFOAM® :
https://www.youtube.com/channel/UCNNBm3KxVS1rGeCVUU1p61g

293
Solid modeling using Onshape
• At the following links, you can find a few geometries that you can use to setup cases
from scratch:

• Sailing boat:
https://cad.onshape.com/documents/ad885ed6298e6d95e372f573/w/1cfda457fe3ad410332aad9c/e/8dac4fcaf6e34a43e9676fbc

• Mixing elbow:
https://cad.onshape.com/documents/1cc919d8e75c2e47e8c1d50e/w/0efa002648eb2fb80ec4bec4/e/a742bf4113c626735e1d8f1a

• Static mixer:
https://cad.onshape.com/documents/58f7930861743e1074559ea6/w/96672317c9167265f9d10181/e/e4b6b1baffa90ca207afe974

• Ahmed body:
https://cad.onshape.com/documents/e1ecbacd95be9ed0962aa410/w/f0295899197e2f3d851000fd/e/aa40f8f5d26b7117dd0a5111

• Mixing tank:
https://cad.onshape.com/documents/e00307c191ce168d1d8c2e05/w/fc5d69b18559ec3893a1a80a/e/ba4b5ca5b34ad7335a2915a3

• Onera M6 wing:
https://cad.onshape.com/documents/e176caaa70bfd4719cafe3d7/w/9d8b5771d7382000b0762e65/e/ec4669f8c28761e60e35b32f

• Three element airfoil:


https://cad.onshape.com/documents/590a4195a6145a1089cfb96f/w/838a3095da90d5dd66a3150e/e/5d65878bed975a1a94102846

294
Module 3
Meshing preliminaries – Mesh quality
assessment – Meshing in OpenFOAM®

295
Before we begin
• OpenFOAM® comes with the following meshing applications:
• blockMesh
• snappyHexMesh
• foamyHexMesh
• foamyQuadMesh
• We are going to work with blockMesh and snappyHexMesh.
• blockMesh is a multi-block mesh generator.
• snappyHexMesh is an automatic split hex mesher, refines and snaps to surface.
• If you are not comfortable using OpenFOAM® meshing applications, you can use an
external mesher.
• OpenFOAM® comes with many mesh conversion utilities. Many popular meshing
formats are supported. To name a few: gambit, cfx, fluent, gmsh, ideas, netgen,
plot3d, starccm, VTK.
• In this module, we are going to address how to mesh using OpenFOAM®
technology, how to convert meshes to OpenFOAM® format, and how to assess
mesh quality in OpenFOAM®.

296
Before we begin
By the end of this module, you will realize that
You will use snappyHexMesh to mesh the sphinx

You will use blockMesh to mesh the pyramids

297
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

298
Meshing preliminaries
• Mesh generation or domain discretization consist in dividing the physical
domain into a finite number of discrete regions, called control volumes or
cells in which the solution is sought

www.wolfdynamics.com/wiki/moving/ani1.gif www.wolfdynamics.com/wiki/moving/ani2.gif
299
Meshing preliminaries
Mesh generation process
• Generally speaking, when generating the mesh we follow these three
simple steps:
• Geometry generation: we first generate the geometry that we are going
to feed into the meshing tool.
• Mesh generation: the mesh can be internal or external. We also define
surface and volume refinement regions. We can also add inflation layers
to better resolve the boundary layer. During the mesh generation
process we also check the mesh quality.
• Definition of boundary surfaces: in this step we define physical
surfaces where we are going to apply the boundary conditions. If you do
not define these individual surfaces, you will have one single surface
and it will not be possible to apply different boundary conditions.

300
Meshing preliminaries
Geometry generation - Input geometry
• The geometry must be watertight.
• Remember, the quality of the mesh and hence the quality of the solution greatly depends on the geometry. So
always do your best when creating the geometry.

301
Meshing preliminaries
Mesh generation
• If we are interested in external aerodynamics, we define a physical domain and we mesh the region around
the body.
• If we are interested in internal aerodynamics, we simply mesh the internal volume of the geometry.
• To resolve better the flow features, we can add surface and volume refinement.
• Remember to always check the mesh quality.

302
Meshing preliminaries
Definition of boundary surfaces (patches)
• In order to assign boundary conditions, we need to create boundary surfaces (patches) where we are going to
apply the boundary values.
• The boundary surfaces (patches) are created at meshing time.
• In OpenFOAM®, you will find this information in the boundary dictionary file which is located in the directory
constant/polyMesh. This dictionary is created automatically at meshing time.

inlet outlet

top

left right

airplane

bottom 303
Meshing preliminaries
What cell type should I use?

http://www.wolfdynamics.com/wiki/cells/ani_tetra.gif http://www.wolfdynamics.com/wiki/cells/ani_hexa.gif http://www.wolfdynamics.com/wiki/cells/ani_poly.gif

• In the meshing world, there are many cell types. Just to name a few: tetrahedrons,
pyramids, hexahedrons, prisms, polyhedral.
• Each cell type has its very own properties when it comes to approximate the gradients
and fluxes, we are going to talk about this later on when we deal with the FVM.
• Generally speaking, hexahedral cells will give more accurate solutions under certain
conditions.
• However, this does not mean that tetra/poly cells are not good.
• What cell type do I use? It is up to you; at the end of the day the overall quality of the
final mesh should be acceptable, and your mesh should resolve the physics
304
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

305
What is a good mesh?
• There is no written theory when it comes to mesh generation.
• Basically, the whole process depends on user experience and good standard
practices.
• A standard rule of thumb is that the elements shape and distribution should be
pleasing to the eye.

22rd IMR Meshing Maestro Contest Winner


Travis Carrigan, John Chawner and Carolyn Woeber. Pointwise.
http://imr.sandia.gov/22imr/MeshingContest.html

306
What is a good mesh?
• In a more sounded way, the user can rely in mesh metrics.
• However, no single standard benchmark or metric exists that can effectively
assess the quality of a mesh, but the user can rely on suggested best
practices.
• Hereafter, we will present the most common mesh quality metrics:
• Orthogonality.
• Skewness.
• Aspect Ratio.
• Smoothness.
• After generating the mesh, we measure these quality metrics to assess the
mesh quality.
• Have in mind that there are many more mesh quality metrics out there, and
some of them are not very easy to interpret (e.g., jacobian matrix,
determinant, flatness, equivalence, condition number, and so on).
• It seems that it is much easier diagnosing bad meshes than good meshes.
307
What is a good mesh?
Mesh quality metrics. Mesh orthogonality
• Mesh orthogonality is the angular deviation of the vector S (located at the face center
f ) from the vector d connecting the two cell centers P and N. In this case is .
• It mainly affects the Laplacian and gradient terms at the face center f.
• It adds numerical diffusion to the solution.

308
What is a good mesh?
Mesh quality metrics. Mesh skewness
• Skewness (also known as non-conjunctionality) is the deviation of the vector d that
connects the two cells P and N, from the face center f.
• The deviation vector is represented with and is the point where the vector d
intersects the face f .
• It affects the interpolation of the cell centered quantities at the face center f.
• It affects the computation of the convective, diffusive, and gradient terms.
• It adds numerical diffusion and wiggles to the solution.

309
What is a good mesh?
Mesh quality metrics. Mesh aspect ratio AR
• Mesh aspect ratio AR is the ratio between the longest side and the shortest
side .
• Large AR are ok if gradients in the largest direction are small.
• High AR smear gradients.
• Large AR can add numerical diffusion to the solution.

310
What is a good mesh?
Mesh quality metrics. Smoothness
• Smoothness, also known as expansion rate, growth factor or uniformity, defines the
transition in size between contiguous cells.
• Large transition ratios between cells add diffusion to the solution.
• Ideally, the maximum change in mesh spacing should be less than 20%:

Steep transition Smooth transition 311


What is a good mesh?
Mesh quality metrics. Element type close to the walls - Cell/Flow alignment

• Hexes, prisms, and quadrilaterals can be stretched easily to resolve boundary layers
without losing quality.
• Triangular and tetrahedral meshes have inherently larger truncation error.
• Less truncation error when faces aligned with flow direction and gradients.

Flow direction

312
What is a good mesh?
Striving for quality
• For the same cell count, hexahedral meshes will give more accurate solutions,
especially if the grid lines are aligned with the flow.
• But this does not mean that tetrahedral meshes are not good, by carefully choosing
the numerical scheme you can get the same level of accuracy as in hexahedral
meshes.
• The problem with tetrahedral meshes is mainly related to the way gradients are
computed.

• In the early years of CFD, there was a huge


Tetra gap between the outcome of tetra and hex
meshes.
• But with time and thanks to developments in
numerical methods and computer science
QOI

(software and hardware), today all cell types


give the same results.

Hexa

Year 313
What is a good mesh?
Striving for quality
• The mesh density should be high enough to capture all relevant flow features.
• In areas where the solution change slowly, you can use larger elements.
• A good mesh does not rely in the fact that the more cells we use the better the
solution.

23rd IMR Meshing Maestro Contest Winner


Zhoufang Xiao , Jianjing Zheng, Dawei Zhao, Lijuan Zeng, Jianjun Chen, Yao Zheng
Center for Engineering & Scientific Computation, Zhejiang University, China.
http://www.sandia.gov/imr/MeshingContest.html 314
What is a good mesh?
Striving for quality
• Hexes, prisms, and quadrilaterals can be easily aligned with the flow.
• They can also be stretched to resolve boundary layers without losing much quality.
• Triangular and tetrahedral meshes can easily be adapted to any kind of geometry. The mesh
generation process is almost automatic.
• Tetrahedral meshes normally need more computing resources during the solution stage. But
this can be easily offset by the time saved during the mesh generation stage.
• Increasing the cells count will likely improve the solution accuracy, but at the cost of a higher
computational cost. However, a finer mesh does not mean a better mesh.
• To keep cell count low, use non-uniform meshes to cluster cells only where they are needed.
Use local refinements and solution adaption to further refine only on selected areas.
• In boundary layers, quads, hexes, and prisms/wedges cells are preferred over triangles,
tetrahedrons, or pyramids.
• If you are not using wall functions (turbulence modeling), the mesh next to the walls should be
fine enough to resolve the boundary layer flow. Have in mind that this will rocket the cell count
and increase the computing time.

315
What is a good mesh?
Striving for quality
• Use hexahedral meshes whenever is possible, specially if high accuracy in predicting forces is
your goal (drag prediction) or for turbo machinery applications.
• For complex flows without dominant flow direction, quad and hex meshes loose their
advantages.
• Keep orthogonality, skewness, and aspect ratio to a minimum.
• Change in cell size should be smooth.
• Always check the mesh quality. Remember, one single cell can cause divergence or give you
inaccurate results.
• When you strive for quality, you avoid the GIGO syndrome (garbage in, garbage out).
• Just to end for good the mesh quality talk:
• A good mesh is a mesh that serves your project objectives.
• So, as long as your results are physically realistic, reliable and accurate; your mesh is
good.
• Know your physics and generate a mesh able to resolve the physics involve, without
over-doing.
316
What is a good mesh?

A good mesh might not lead to the ideal solution, but a bad
mesh will always lead to a bad solution.
P. Baker – Pointwise

Who owns the mesh, owns the solution.


H. Jasak – Wikki Ltd.

Avoid the GIGO syndrome (Garbage In – Garbage Out).


As I am a really positive guy I prefer to say,
good mesh – good results.
J. G. – WD

317
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

318
Mesh quality assessment in OpenFOAM®
Mesh quality metrics in OpenFOAM®
• In the file primitiveMeshCheck.C located in the directory
$WM_PROJECT_DIR/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/ you will find the
quality metrics hardwired in OpenFOAM®. Their maximum (or minimum) values are defined as follows:

36 Foam::scalar Foam::primitiveMesh::closedThreshold_ = 1.0e-6;


37 Foam::scalar Foam::primitiveMesh::aspectThreshold_ = 1000;
38 Foam::scalar Foam::primitiveMesh::nonOrthThreshold_ = 70; // deg
39 Foam::scalar Foam::primitiveMesh::skewThreshold_ = 4;
40 Foam::scalar Foam::primitiveMesh::planarCosAngle_ = 1.0e-6;

• You will be able to run simulations with mesh quality errors such as high skewness, high aspect ratio, and high
non-orthogonality. But remember, they will affect the solution accuracy, might give you strange results, and
eventually can made the solver blow-up.
• Have in mind that if you have bad quality meshes, you will need to adapt the numerics to deal with this kind of
meshes. We will give you our recipe later when we deal with the numerics.
• You should avoid as much as possible non-orthogonality values close to 90. This is an indication that you have
zero-volume cells.
• In overall, large aspect ratios do not represent a problem. It is just an indication that you have very fine
meshes (which is the case when you are resolving the boundary layer).
• The default quality metrics in OpenFOAM® seems to be a little bit conservative. In our experience, we have
found that you can run simulations with no numerical tricks with a non-orthogonality values up to 80 and
skewness values up to 8. 319
Mesh quality assessment in OpenFOAM®
Checking the mesh quality in OpenFOAM®
• To check the mesh quality and validity, OpenFOAM® comes with the utility checkMesh.
• To use this utility, just type in the terminal checkMesh, and read the screen output.
• checkMesh will look for/check for:
• Mesh stats and overall number of cells of each type.
• Check topology (boundary conditions definitions).
• Check geometry and mesh quality (bounding box, cell volumes, skewness, orthogonality, aspect
ratio, and so on).

• If for any reason checkMesh finds errors, it will give you a message and it will tell you what check failed.
• It will also write a set with the faulty cells, faces, and/or points.
• These sets are saved in the directory constant/polyMesh/sets/
• Mesh topology and patch topology errors must be repaired.
• You will be able to run with mesh quality errors such as skewness, aspect ratio, minimum face area, and non-
orthogonality.
• But remember, they will severely tamper the solution accuracy, might give you strange results, and eventually
can made the solver blow-up.
• Unfortunately, checkMesh does not repair these errors.
• You will need to check the geometry for possible errors and generate a new mesh.
• You can visualize the failed sets directly in paraFoam .
• You can also convert the failed sets into VTK format by using the utility foamToVTK.
320
Mesh quality assessment in OpenFOAM®
Visualizing the failed sets in OpenFOAM®
Check this box to include sets
• You can load the failed sets directly within
paraFoam.
• Remember, you will need to create the sets. To
do so, just run the checkMesh utility.
• If there are problems in the mesh, checkMesh
will automatically save the sets in the directory
constant/polyMesh/sets
• In paraFoam, simply select the option Include
Sets and then select the sets you want to
visualize.
• This method only works when using the wrapper
paraFoam.
• If you are using paraview or a different scientific
visualization application, you will need to convert
the failed sets to VTK format or an alternative
format.
• Also, when working with large meshes we prefer
to convert the faulty sets to VTK format.
• To convert the faulty sets to VTK format you can Failed sets
use the utility foamToVTK.
321
Mesh quality assessment in OpenFOAM®
Visualizing the failed sets in OpenFOAM®
• To convert the failed faces/cells/points to VTK format, you can proceed as follows:

• $> foamToVTK -set_type name_of_sets

where set_type is the type of sets (faceSet, cellSet, pointSet, surfaceFields) and
name_of_sets is the name of the set located in the directory
constant/polyMesh/sets (highAspectRatioCells, nonOrthoFaces,
wrongOrientedFaces, skewFaces, unusedPoints, and so on).
• At the end, foamToVTK will create a directory named VTK, where you will find the
failed faces/cells/points in VTK format.
• At this point you can use paraview/paraFoam or any scientific visualization
application to open the VTK files and visualize the failed sets.

322
Mesh quality assessment in OpenFOAM®
Checking mesh quality in OpenFOAM®
• Sample checkMesh output,

Mesh stats
points: 81812
faces: 902132
internal faces: 871012
cells: 443286
faces per cell: 4 Mesh stats
boundary patches: 9
point zones: 0
face zones: 1
cell zones: 1

Overall number of cells of each type:


hexahedra: 0
prisms: 0
wedges: 0
pyramids: 0 Number of each type of cells
tet wedges: 0
tetrahedra: 443286
polyhedra: 0

Checking topology...
Boundary definition OK. Checking mesh topology
Cell to face addressing OK.
***Unused points found in the mesh, number unused by faces: 16 number unused by cells: 16
<<Writing 16 unused points to set unusedPoints
Upper triangular ordering OK.
Face vertices OK.
Number of regions: 1 (OK). Unused points found in the mesh
In this case they do not harm the solution
They can be removed using topoSet and subsetMesh
323
Mesh quality assessment in OpenFOAM®
Checking mesh quality in OpenFOAM®
• Sample checkMesh output,
Checking patch topology for multiply connected surfaces...
Patch Faces Points Surface topology
FAIRING 1267 727 ok (non-closed singly connected)
FUSELAGE 3243 1774 ok (non-closed singly connected)
WING 15313 7706 ok (non-closed singly connected)
INLET 272 160 ok (non-closed singly connected)
OUTLET 272 160 ok (non-closed singly connected) Boundary patches
SYMM 6280 3324 ok (non-closed singly connected)
FARFIELD 3136 1645 ok (non-closed singly connected)
NOSE 76 49 ok (non-closed singly connected)
COCKPIT 1261 670 ok (non-closed singly connected)

Checking geometry...
Overall domain bounding box (-15000 -7621.0713 -7396.4536) (30048.969 0 7446.8442)
Mesh has 3 geometric (non-empty/wedge) directions (1 1 1)
Mesh has 3 solution (non-empty) directions (1 1 1)
Mesh bounding box
Boundary openness (-4.2298633e-18 8.0240802e-16 4.013988e-16) OK.
Max cell openness = 4.8098963e-16 OK.
Max aspect ratio = 29.575835 OK. Aspect ratio
Minimum face area = 0.0066721253. Maximum face area = 1037224.8. Face area magnitudes OK.
Min volume = 0.00050536842. Max volume = 3.2500889e+08. Total volume = 5.0960139e+12. Cell volumes OK.
Mesh non-orthogonality Max: 86.939754 average: 17.939523 High non-orthogonality
*Number of severely non-orthogonal (> 70 degrees) faces: 3168. But we still can run the simulation
Non-orthogonality check OK.
<<Writing 3168 non-orthogonal faces to set nonOrthoFaces
Face pyramids OK.
Max skewness = 2.5719979 OK. Skewness
Coupled point location match (average 0) OK.

Failed 1 mesh checks. The fact that one check failed does not mean that you can not run the simulation

End 324
Mesh quality assessment in OpenFOAM®
Visualization of faulty sets in paraFoam
• You will find this case ready to use in the directory,
$PTOFC/mesh_quality_manipulation/M1_wingbody
• To run the case, just follow the instructions in the README.FIRST files.

Non orthogonal faces (green spheres) and unused points (yellow spheres) 325
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

326
Mesh generation using blockMesh
blockMesh
• “blockMesh is a multi-block mesh generator.”
• For simple geometries, the mesh generation utility blockMesh can be used.
• The mesh is generated from a dictionary file named blockMeshDict
located in the system directory.
• This meshing tool generates high quality meshes.
• It is the tool to use for very simple geometries. As the complexity of the
geometry increases, the effort and time required to setup the dictionary
increases a lot.
• Usually, the background mesh used with snappyHexMesh consist of a
single rectangular block; therefore, blockMesh can be used with no
problem.
• It is highly recommended to create a template of the dictionary
blockMeshDict that you can change according to the dimensions of your
domain.
• You can also use m4 or Python scripting to automate the whole process. 327
Mesh generation using blockMesh
blockMesh
• These are a few meshes that you can generate using blockMesh.
• As you can see, they are not very complex.
• However, generating the blocking topology requires some effort.

328
Mesh generation using blockMesh
blockMesh workflow

• To generate a mesh with blockMesh, you will need to define the vertices, block
connectivity and number of cells in each direction.
• To assign boundary patches, you will need to define the faces connectivity
329
blockMesh guided tutorials

• Meshing with blockMesh – Case 1.


• We will use the square cavity case.
• You will find this case in the directory:

$PTOFC/101BLOCKMESH/C1

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
330
blockMesh guided tutorials
What are we going to do?
• We will use this simple case to take a close look at a blockMeshDict dictionary.
• We will study all sections in the blockMeshDict dictionary.
• We will introduce two features useful for parameterization, namely, macro syntax and
inline calculations.
• You can use this dictionary as a blockMeshDict template that you can change
automatically according to the dimensions of your domain and the desired cell
spacing.

331
blockMesh guided tutorials
The blockMeshDict dictionary.
• The keyword convertToMeters (line 17), is a scaling
17 convertToMeters 1; factor. In this case we do not scale the dimensions.
18
19 xmin 0;
20 xmax 1; • In lines 19-24 we declare some variables using macro
21
22
ymin
ymax
0;
1;
syntax notation. With macro syntax, we first declare the
23 zmin 0; variables and their values (lines 19-24), and then we can
24 zmax 1;
25
use the variables by adding the symbol $ to the variable
30 deltax 0.05; name (lines 47-54).
31 deltay 0.05;
32 deltaz 0.05;
33 • In lines 30-32 we use macro syntax to declare another
34 lx #calc "$xmax - $xmin"; set of variables that will be used later.
35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin";
37 • Macro syntax is a very convenient way to parameterize
38
39
xcells #calc "round(($lx)/($deltax))";
ycells #calc "round(($ly)/($deltay))";
dictionaries.
40 zcells #calc "round(($lz)/($deltaz))";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );

332
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 34-40 we are doing inline calculations using the
17 convertToMeters 1; directive #calc.
18
19 xmin 0;
20 xmax 1; • Basically we are programming directly in the dictionary.
21
22
ymin
ymax
0;
1;
OpenFOAM® will compile this function as it reads it.
23 zmin 0;
24 zmax 1; • With inline calculations and codeStream you can access
25
30 deltax 0.05;
many OpenFOAM® functions from the dictionaries.
31 deltay 0.05;
32 deltaz 0.05; • Inline calculations and codeStream are very convenient
33
34 lx #calc "$xmax - $xmin";
ways to parameterize dictionaries and program directly
35 ly #calc "$ymax - $ymin"; on the dictionaries.
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round(($lx)/($deltax))";
39 ycells #calc "round(($ly)/($deltay))";
40 zcells #calc "round(($lz)/($deltaz))";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );

333
blockMesh guided tutorials
The blockMeshDict dictionary.
• To do inline calculations using the directive #calc, we
17 convertToMeters 1; proceed as follows (we will use line 35 as example):
18
19 xmin 0;
20 xmax 1;
21 ymin 0;
22 ymax 1; ly #calc "$ymax - $ymin";
23 zmin 0;
24 zmax 1;
25
30 deltax 0.05;
31 deltay 0.05; • We first give a name to the new variable (ly), we then tell
32 deltaz 0.05;
33
OpenFOAM® that we want to do an inline calculation
34 lx #calc "$xmax - $xmin"; (#calc), and then we do the inline calculation ("$ymax-
35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin"; $ymin";). Notice that the operation must be between
37
38 xcells #calc "round(($lx)/($deltax))";
double quotation marks.
39 ycells #calc "round(($ly)/($deltay))";
40 zcells #calc "round(($lz)/($deltaz))";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );

334
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines lines 34-36, we use inline calculations to
17 convertToMeters 1; compute the length in each direction.
18
19 xmin 0;
20 xmax 1; • Then we compute the number of cells to be used in each
21
22
ymin
ymax
0;
1;
direction (lines 38-40).
23 zmin 0;
24 zmax 1; • To compute the number of cells we use as cell spacing
25
30 deltax 0.05;
the values declared in lines 30-32.
31 deltay 0.05;
32 deltaz 0.05; • By proceeding in this way, we can compute automatically
33
34 lx #calc "$xmax - $xmin";
the number of cells needed in each direction according to
35 ly #calc "$ymax - $ymin"; the desired cell spacing.
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round(($lx)/($deltax))";
39 ycells #calc "round(($ly)/($deltay))";
40 zcells #calc "round(($lz)/($deltaz))";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );

335
blockMesh guided tutorials
The blockMeshDict dictionary.
• In the vertices section (lines 44-66), we define the vertex
17 convertToMeters 1; coordinates of the geometry.
18
19 xmin 0;
20 xmax 1; • In this case, there are eight vertices defining a 3D block.
21 ymin 0;
22 ymax 1; • Remember, OpenFOAM® always uses 3D meshes, even
23 zmin 0;
24 zmax 1; if the simulation is 2D. For 2D meshes, you only add one
25
30 deltax 0.05;
cell in the third dimension.
31 deltay 0.05;
32 deltaz 0.05; • Notice that the vertex numbering starts from 0 (as the
33
34 lx #calc "$xmax - $xmin";
counters in c++). This numbering applies for blocks as
35 ly #calc "$ymax - $ymin"; well.
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round(($lx)/($deltax))";
39 ycells #calc "round(($ly)/($deltay))";
40 zcells #calc "round(($lz)/($deltaz))";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );

336
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 68-71, we define the block topology, hex means that it is a structured hexahedral block. In this case,
we are generating a rectangular mesh.
• In line 70, (0 1 2 3 4 5 6 7) are the vertices used to define the block (and yes, the order is important). Each
hex block is defined by eight vertices, in sequential order. Where the first vertex in the list represents the
origin of the coordinate system (vertex 0 in this case).
• ($xcells $ycells $zcells) is the number of mesh cells in each direction (X Y Z). Notice that we are using
macro syntax, and we compute the values using inline calculations.
• simpleGrading (1 1 1) is the grading or mesh stretching in each direction (X Y Z), in this case the mesh is
uniform. We will deal with mesh grading/stretching in the next case.

68 blocks
69 (
70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
71 );
72
73 edges
74 (
75
76 );

337
blockMesh guided tutorials
The blockMeshDict dictionary.
• Let us talk about the block ordering hex (0 1 2 3 4 5 6 7), which is extremely important.
• hex blocks are defined by eight vertices in sequential order. Where the first vertex in the list represents the
origin of the coordinate system (vertex 0 in this case).
• Starting from this vertex, we construct the block topology. So in this case, the first part of the block is made up
by vertices 0 1 2 3 and the second part of the block is made up by vertices 4 5 6 7 (notice that we start from
vertex 4 which is the projection in the Z-direction of vertex 0).
• In this case, the vertices are ordered in such a way that if we look at the screen/paper (-z direction), the
vertices rotate counter-clockwise.
• If you add a second block, you must identify the first vertex and starting from it, you should construct the block
topology. In this case, you will need to merges faces, you will find more information about merging face in the
supplement lectures.

68 blocks
69 (
70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
71 );
72
73 edges
74 (
75
76 );

338
blockMesh guided tutorials
The blockMeshDict dictionary.
• Edges, are constructed from the vertices definition.
• Each edge joining two vertices is assumed to be straight by default.
• The user can specify any edge to be curved by entries in the section edges.
• Possible options are Bspline, arc, line, polyline, project, projectCurve, spline.
• For example, to define an arc we first define the vertices to be connected to form an edge and then we give an
interpolation point.
• To define a polyline we first define the vertices to be connected to form an edge and then we give a list of the
coordinates of the interpolation points.
• In this case and as we do not specify anything, all edges are assumed to be straight lines.

68 blocks
69 (
70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
71 );
72
73 edges
74 (
75
76 );

339
blockMesh guided tutorials
The blockMeshDict dictionary.
• In the section boundary, we define all the patches where
78 boundary we want to apply boundary conditions.
79 (
80 top
81 { • This step is of paramount importance, because if we do
82
83
type wall;
faces
not define the surface patches, we will not be able to
84 ( apply the boundary conditions to individual surface
85 (3 7 6 2)
86 );
patches.
87 }
88 left
89 {
90 type wall;
91 faces
92 (
93 (0 4 7 3)
94 );
95 }
96 right
97 {
98 type wall;
99 faces
100 (
101 (2 6 5 1)
102 );
103 }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }

340
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 80-87 we define a boundary patch.
78 boundary
79 ( • In line 80 we define the patch name top (the name is
80 top
81 { given by the user).
82 type wall;
83 faces • In line 82 we give a base type to the surface patch. In
84 (
85 (3 7 6 2) this case wall (do not worry we are going to talk about
86
87 }
); this later).
88 left
89 { • In line 85 we give the connectivity list of the vertices that
90
91
type wall;
faces
made up the surface patch or face, that is, (3 7 6 2).
92 (
93 (0 4 7 3) • Have in mind that the vertices need to be neighbors and
94
95 }
);
it does not matter if the ordering is clockwise or
96 right counterclockwise.
97 {
98 type wall;
99 faces
100 (
101 (2 6 5 1)
102 );
103 }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }

341
blockMesh guided tutorials
The blockMeshDict dictionary.
• Have in mind that the vertices need to be neighbors and
78 boundary it does not matter if the ordering is clockwise or
79 (
80 top counterclockwise.
81 {
82
83
type wall;
faces
• Remember, faces are defined by a list of 4 vertex
84 ( numbers, e.g., (3 7 6 2).
85 (3 7 6 2)
86
87 }
); • In lines 88-95 we define the patch left.
88 left
89 { • In lines 96-103 we define the patch right.
90 type wall;
91 faces • In lines 104-11 we define the patch bottom.
92 (
93 (0 4 7 3)
94 );
95 }
96 right
97 {
98 type wall;
99 faces
100 (
101 (2 6 5 1)
102 );
103 }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }

342
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 112-119 we define the patch front.
112 front
113 { • In lines 120-127 we define the patch back.
114 type wall;
115
116
faces
(
• You can also group many faces into one patch, for
117 (4 5 6 7) example, instead of creating the patches front and back,
118 );
119 } you can group them into a single patch named
120
121
back
{
backAndFront, as follows,
122 type wall;
123 faces
124 (
125 (0 3 2 1) backAndFront
126 ); {
127 }
128 ); type wall;
129 faces
130 mergePatchPairs
131 ( (
132 (4 5 6 7)
133 );
(0 3 2 1)
);
}

343
blockMesh guided tutorials
The blockMeshDict dictionary.
• We can merge blocks in the section mergePatchPairs
112 front (lines 130-133).
113 {
114 type wall;
115 faces • The block patches to be merged must be first defined in
116 ( the boundary list, blockMesh then connect the two
117 (4 5 6 7)
118 ); blocks.
119 }
120
121
back
{
• In this case, as we have one single block there is no
122 type wall; need to merge patches.
123 faces
124 (
125 (0 3 2 1)
126 );
127 }
128 );
129
130 mergePatchPairs
131 (
132
133 );

344
blockMesh guided tutorials
The blockMeshDict dictionary.

• To sum up, the blockMeshDict dictionary


generates a single block with:

• X/Y/Z dimensions: 1.0/1.0/1.0

• As the cell spacing in all directions is


defined as 0.05, it will use the following
number of cells in the X, Y and Z directions:
20 x 20 x 20 cells.

• One single hex block with straight lines.

• Six patches of base type wall, namely, left,


right, top, bottom, front and back.

• The information regarding the patch base type


and patch name is saved in the file boundary.
Feel free to modify this file to fit your needs.
• Remember to use the utility checkMesh to check
the quality of the mesh and look for topological
errors.

• Topological errors must be repaired.

345
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18
19
6
(
• First of all, this file is automatically generated after you
20 top create the mesh or you convert it from a third-party format.
21 {
22 type wall;
23 inGroups 1(wall); • In this file, the geometrical information related to the base
24 nFaces 400;
25 startFace 22800; type patch of each boundary of the domain is specified.
26 }
27 left
28 { • The base type boundary condition is the actual surface
29 type wall;
30 inGroups 1(wall); patch where we are going to apply a primitive type
31
32
nFaces
startFace
400;
23200;
boundary condition (or numerical boundary condition).
33 }
34
35
right
{
• The primitive type boundary condition assign a field value
36 type empty; to the surface patch.
37 inGroups 1(wall);
38 nFaces 400;
39 startFace 23600; • You define the numerical type patch (or the value of the
40 }
41 bottom boundary condition), in the directory 0 or time directories.
42 {
43 type wall;
44 inGroups 1(wall); • The name and base type of the patches was defined in the
45
46
nFaces
startFace
400;
24000;
dictionary blockMeshDict in the section boundary.
47 }
48 front
49 { • You can change the name if you do not like it. Do not use
50
51
type
inGroups
wall;
1(wall);
strange symbols or white spaces.
52 nFaces 400;
53
54 }
startFace 24400; • You can also change the base type. For instance, you can
55 back change the type of the patch top from wall to patch.
56 {
57 type empty;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 346
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18
19
6
(
• If you do not define the boundary patches in the dictionary
20 top blockMeshDict, they are grouped automatically in a default
21 {
22 type wall; group named defaultFaces of type empty.
23 inGroups 1(wall);
24
25
nFaces
startFace
400;
22800;
• For instance, if you do not assign a base type to the patch
26 } front, it will be grouped as follows:
27 left
28 {
29 type wall;
30 inGroups 1(wall);
31 nFaces 400;
defaultFaces
32 startFace 23200; {
33 } type empty;
34 right inGroups 1(empty);
35 {
36 type empty;
nFaces 400;
37 inGroups 1(wall); startFace 24800;
38 nFaces 400; }
39 startFace 23600;
40 }
41 bottom
42 {
43 type wall; • Remember, you can manually change the name and type.
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 24400;
54 }
55 back
56 {
57 type empty;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 347
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18
19
6
(
Number of surface patches
20 top
21 {
22 type wall; In the list bellow there must be 6 patches
23 inGroups 1(wall);
24 nFaces 400; definition.
25 startFace 22800;
26 }
27 left
28 {
29 type wall;
30 inGroups 1(wall); top
31 nFaces 400;
32 startFace 23200;
33 }
34 right
35 {
36 type empty;
37 inGroups 1(wall); back
38 nFaces 400;
39 startFace 23600;
40 }
41 bottom
42 {
43 type wall;
44 inGroups 1(wall);
45 nFaces 400; left right
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400; front
53 startFace 24400;
54 }
55 back
56 {
57 type empty;
58 inGroups 1(wall);
59 nFaces 400; bottom
60 startFace 24800;
61 }
62 ) 348
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
20 top
21 {
22 type wall; Name and type of the surface patches
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 22800;
26 } • The name and base type of the patch is given
27 left
28 { by the user.
29 type wall;
30
31
inGroups
nFaces
1(wall);
400;
• In this case the name and base type was
32 startFace 23200; assigned in the dictionary blockMeshDict.
33 }
34 right
35 { • You can change the name if you do not like it.
36
37
type
inGroups
wall;
1(wall);
Do not use strange symbols or white spaces.
38 nFaces 400;
39 startFace 23600; • You can also change the base type. For
40 }
41 bottom instance, you can change the type of the
42
43
{
type wall;
patch top from wall to patch.
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 24400;
54 }
55 back
56 {
57 type wall;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 349
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
20 top
21 {
22 type wall; inGroups keyword
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 22800;
26 } • This is optional.
27 left
28
29
{
type wall; • You can erase this information safely.
30 inGroups 1(wall);
31 nFaces 400; • It is used to group patches during visualization
32 startFace 23200;
33 } in ParaView/paraFoam. If you open this mesh
34 right
35 { in paraFoam you will see that there are two
36
37
type
inGroups
wall;
1(wall);
groups, namely: wall and empty.
38 nFaces 400;
39 startFace 23600; • As usual, you can change the name.
40 }
41
42
bottom
{ • If you want to put a surface patch in two
43
44
type
inGroups
wall;
1(wall);
groups, you can proceed as follows:
45 nFaces 400;
46 startFace 24000; 2(wall wall1)
47 }
48
49
front
{
In this case the surface patch belongs to the
50
51
type
inGroups
wall;
1(wall);
group wall (which can have another patch)
52 nFaces 400; and the group wall1
53 startFace 24400;
54 }
55 back
56 {
57 type wall;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 350
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
20 top
21 {
22 type wall; nFaces and startFace keywords
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 22800;
26 } • Unless you know what are you doing, you do
27 left
28 { not need to change this information.
29 type wall;
30
31
inGroups
nFaces
1(wall);
400;
• Basically, this is telling you the starting face
32 startFace 23200; and ending face of the patch.
33 }
34 right
35 { • This information is created automatically when
36
37
type
inGroups
wall;
1(wall);
generating the mesh or converting the mesh.
38 nFaces 400;
39 startFace 23600;
40 }
41 bottom
42 {
43 type wall;
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 24400;
54 }
55 back
56 {
57 type wall;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 351
blockMesh guided tutorials
Running the case

• To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> checkMesh
4. $> paraFoam

• If you want to visualize the blocking topology, type in the terminal

1. $> paraFoam -block

• You can run the rest of the cases following the same steps.

352
blockMesh guided tutorials
Final remarks on blockMesh
• For the moment, we will limit the use of blockMesh to single-block mesh topologies, which are
used to run some simple cases and are the starting point for snappyHexMesh.
• But have in mind that you can do more elaborated meshes, however, it requires careful setup of
the input dictionary.
• Have in mind that it can be really tricky to generate multi-block meshes with curve edges.
• With the training material, you will find a set of supplement slides where we explain how to
create multi-block meshes, add stretching, and how to define curve edges.

Single-block mesh with multi-stretching Multi-block mesh with curved edges and Multi-block mesh with face merging
multi-stretching

353
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

354
Mesh generation using snappyHexMesh

snappyHexMesh
• “Automatic split hex mesher. Refines and snaps to surface.”
• For complex geometries, the mesh generation utility snappyHexMesh can be used.
• The snappyHexMesh utility generates 3D meshes containing hexahedra and split-
hexahedra from a triangulated surface geometry in Stereolithography (STL) format.
• The mesh is generated from a dictionary file named snappyHexMeshDict located in
the system directory and a triangulated surface geometry file located in the directory
constant/triSurface.

355
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• To generate a mesh with snappyHexMesh we proceed as follows:
• Generation of a background or base mesh.
• Geometry definition.
• Generation of a castellated mesh or cartesian mesh.
• Generation of a snapped mesh or body fitted mesh.
• Addition of layers close to the surfaces or boundary layer meshing.
• Check/enforce mesh quality.

blockMesh or external mesher

Background mesh Geometry (STL file)

snappyHexMesh

OpenFOAM mesh

356
Mesh generation using snappyHexMesh
snappyHexMesh workflow – Background mesh
• The background or base mesh can be generated using blockMesh or an
external mesher.
• The following criteria must be observed when creating the background
mesh:
• The mesh must consist purely of hexes.
• The cell aspect ratio should be approximately 1, at least near the
STL surface.
• There must be at least one intersection of a cell edge with the
STL surface.
blockMesh or external mesher

Background mesh Geometry (STL file)

snappyHexMesh

OpenFOAM mesh

357
Mesh generation using snappyHexMesh
snappyHexMesh workflow – Geometry (STL file)
• The STL geometry can be obtained from any geometry modeling tool.
• The STL file can be made up of a single surface describing the geometry, or
multiple surfaces that describe the geometry.
• In the case of a STL file with multiple surfaces, we can use local refinement
in each individual surface. This gives us more control when generating the
mesh.
• The STL geometry is always located in the directory
constant/triSurface

blockMesh or external mesher

Background mesh Geometry (STL file)

snappyHexMesh

OpenFOAM mesh

358
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• The meshing utility snappyHexMesh reads the dictionary
snappyHexMeshDict located in the directory system.
• The castellation, snapping, and boundary layer meshing steps are controlled
by the dictionary snappyHexMeshDict.
• The final mesh is always located in the directory
constant/polyMesh

blockMesh or external mesher

Background mesh Geometry (STL file)

snappyHexMesh

OpenFOAM mesh

359
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• All the volume and surface refinement is done in reference to the
background or base mesh.

and so on …

Base cell – RL 0 RL 1 RL 2

* RL = refinement level

Note:
• In 2D each quad is subdivided in 4
quads.
• In 3D each hex is subdivided in 8
hexes.
360
Mesh generation using snappyHexMesh
snappyHexMesh workflow

• The process of generating a mesh using snappyHexMesh will be described using this figure.
• The objective is to mesh a rectangular shaped region (shaded grey in the figure) surrounding an object
described by a STL surface (shaded green in the figure).
• This is an external mesh (e.g. for external aerodynamics).
• You can also generate an internal mesh (e.g. flow inside a pipe). 361
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Step 1. Creating the background hexahedral mesh


• Before snappyHexMesh is executed the user must create a background mesh of hexahedral cells that fills the entire region as
shown in the figure. This can be done by using blockMesh or any other mesher.
• The following criteria must be observed when creating the background mesh:
• The mesh must consist purely of hexes.
• The cell aspect ratio should be approximately 1, at least near the STL surface.
• There must be at least one intersection of a cell edge with the STL surface.
362
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Step 2. Cell splitting at feature edges


• Cell splitting is performed according to the specification supplied by the user in the castellatedMeshControls sub-dictionary in
the snappyHexMeshDict dictionary.
• The splitting process begins with cells being selected according to specified edge features as illustrated in the figure.
• The feature edges can be extracted from the STL geometry file using the utility surfaceFeatures.

363
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Additional internal cells


splitting

Step 3. Cell splitting at surfaces


• Following feature edges refinement, cells are selected for splitting in the locality of specified surfaces as illustrated in the figure.
• The surface refinement (splitting) is performed according to the specification supplied by the user in the
refinementMeshControls in the castellatedMeshControls sub-dictionary in the snappyHexMeshDict dictionary.
• Notice that we added additional internal cells splitting. This new cell region can be used to define a source term, or it can be put
into motion.

364
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Additional internal cells


splitting

Step 4. Cell removal


• Once the feature edges and surface splitting is complete, a process of cell removal begins.
• The region in which cells are retained are simply identified by a location point within the region, specified by the locationInMesh
keyword in the castellatedMeshControls sub-dictionary in the snappyHexMeshDict dictionary.
• Cells are retained if, approximately speaking, 50% or more of their volume lies within the region.

365
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Additional internal cells


splitting

Step 5. Cell splitting in specified regions


• Those cells that lie within one or more specified volume regions can be further split by a region (in the figure, the rectangular
region within the red rectangle).
• The information related to the refinement of the volume regions is supplied by the user in the refinementRegions block in the
castellatedMeshControls sub-dictionary in the snappyHexMeshDict dictionary.
• This is a valid castellated or cartesian mesh that can be used for a simulation.

366
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Additional internal cells


splitting

Step 6. Snapping to surfaces


• After deleting the cells in the region specified and refining the volume mesh, the points are snapped on the surface to create a
conforming mesh.
• The snapping is controlled by the user supplied information in the snapControls sub-dictionary in snappyHexMeshDict.
• Sometimes, the default snapControls options are not enough, so you will need to adjust the values to get a better mesh (not
guarantee). It is advisable to save the intermediate steps with a high writing precision (controlDict).
• This is a valid snapped or body fitted mesh that can be used for a simulation.
367
Mesh generation using snappyHexMesh
snappyHexMesh workflow

Additional internal cells


splitting

Step 7. Mesh layers


• The mesh output from the snapping stage it is suitable for simulation, although it can produce some irregular cells along
boundary surfaces.
• There is an optional stage of the meshing process which introduces boundary layer meshing in selected parts of the mesh.
• This information is supplied by the user in the addLayersControls sub-dictionary in the snappyHexMeshDict dictionary.
• This is the final step of the mesh generation process using snappyHexMesh.
• This is a valid body fitted mesh with boundary layer meshing, that can be used for a simulation.
368
Mesh generation using snappyHexMesh
snappyHexMesh in action
www.wolfdynamics.com/wiki/shm/ani.gif

369
Mesh generation using snappyHexMesh

• Let us study the snappyHexMesh dictionary in


details.
• We are going to work with the case we just saw in
action.
• You will find this case in the directory:

$PTOFC/101SHM/M101_WD

370
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.

castellatedMesh true; //or false


snap true; //or false
addLayers true; //or false

Definition of geometry entities


geometry
to be used for meshing
{
...
...
}
Definition of feature, surface
castellatedMeshControls
and volume mesh refinement
{
...
...
}
Definition of surface mesh
snapControls snapping and advanced
{ parameters
... • Open the dictionary snappyHexMeshDict with your favorite text
... editor (we will use gedit).
}
Definition of boundary layer • The snappyHexMesh dictionary is made up of five sections, namely:
addLayersControls meshing and advanced geometry, castellatedMeshControls, snapControls,
{ parameters addLayersControls and meshQualityControls. Each section
... controls a step of the meshing process.
...
} • In the first three lines we can turn off and turn on the different
Definition of mesh quality meshing steps. For example, if we want to generate a body fitted
meshQualityControls mesh with no boundary layer we should proceed as follows:
{ metrics
... castellatedMesh true;
... snap true;
} addLayers false; 371
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.

castellatedMesh true; //or false • Have in mind that there are more than 70
snap true; //or false
addLayers true; //or false parameters to control in
snappyHexMeshDict dictionary.
geometry
{
... • Adding the fact that there is no native GUI, it
... can be quite tricky to control the mesh
}
generation process.
castellatedMeshControls
{
... • Nevertheless, snappyHexMesh generates
...
} very good hexa dominant meshes.
snapControls
{ • Hereafter, we will only comment on the most
...
...
important parameters.
}

addLayersControls • The parameters that you will find in the


{ snappyHexMeshDict dictionaries distributed
...
... with the tutorials, in our opinion are robust and
}
will work most of the times.
meshQualityControls
{
...
... It can be located In a separated file
} 372
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Geometry controls section
geometry
{

wolfExtruded.stl STL file to read


{
type triSurfaceMesh;
name wolf; Name of the surface inside snappyHexMesh

regions Use this option if you have a STL with multiple patches defined
{
wolflocal This is the name of the region or surface patch in the STL
{
name wolf_wall; User-defined patch name. This is the final name of the patch
}
}
}
• In this section we read in the STL geometry. Remember, the input
box Name of geometrical entity
geometry is always located in the directory constant/triSurface
{
type searchableBox; • We can also define geometrical entities that can be used to refine the
min (-100.0 -120.0 -50.0 ); mesh, create regions, or generate baffles.
max (100.0 120.0 150.0 );
} • You can add multiple STL files.

sphere Name of geometrical entity • If you do not give a name to the surface, it will take the name of the
{ STL file.
type searchableSphere; Note 1
centre (120.0 -100.0 50.0 ); • The geometrical entities are created inside snappyHexMesh.
radius 40.0;
} Note 1:
If you want to know what geometrical entities are available, just
} misspelled something in the type keyword.

373
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{
//Refinement parameters
maxLocalCells 100000;
maxGlobalCells 2000000; Note 1
nCellsBetweenLevels 3;
...
...

//Explicit feature edge refinement


features Dictionary block
(
...
...
);

//Surface based refinement


refinementSurfaces Dictionary block
{
...
• In the castellatedMeshControls section, we define the global
...
refinement parameters, explicit feature edge refinement,
}
surface-based refinement, region-wise refinement and the
material point.
//Region-wise refinement
refinementRegions Dictionary block • In this step, we are generating the castellated mesh.
{
...
Note 1:
...
Maximum number of cells in the domain. If the mesher reach this
}
number, it will not add more cells.
//Mesh selection
locationInMesh (-100.0 0.0 50.0 ); Note 2 Note 2:
}
The material point indicates where we want to create the mesh,
that is, inside or outside the body to be meshed. 374
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{

// Refinement parameters
maxLocalCells 100000;
maxGlobalCells 2000000;
minRefinementCells 0;
maxLoadUnbalance 0.10;
nCellsBetweenLevels 3; Note 1

//Local curvature and


//feature angle refinement
resolveFeatureAngle 30; Note 2

planarAngle 30;

allowFreeStandingZoneFaces true;

//Explicit feature edge refinement


Note 1:
features Dictionary block
This parameter controls the transition between cell
(
refinement levels.
{
file "wolfExtruded.eMesh"; Note 3
Note 2:
level 2;
This parameter controls the local curvature refinement. The
}
higher the value, the less features it captures. For example,
);
if you use a value of 100 it will not add refinement in high
curvature areas. It also controls edge feature snapping; high
...
values will not resolve sharp angles in surface intersections.
...
...
Note 3:
This file is automatically created when you use the utility
}
surfaceFeatures. The file is located in the directory
constant/triSurface 375
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{

...
...
...

//Surface based refinement


refinementSurfaces Dictionary block
{

//wolf was defined in the geometry section


wolf Note 1
{

level (1 1); //Global refinement

regions Note 2
{

wolflocal Note 3
Note 1:
{
The surface wolf was defined in the geometry section.
level (2 4); Local refinement
Note 2:
patchInfo
The region wolflocal was defined in the geometry section.
{
type wall; Note 4
Note 3:
}
Named region in the STL file. This refinement is local.
}
To use the surface refinement in the regions, the local
}
regions must exist in STL file. We created a pointer to this
}
region in the geometry section.
...
...
Note 4:
} 376
You can only define patches of type wall or patch.
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{

//Surface based refinement


refinementSurfaces Dictionary block
{

...
...
...
//This surface or geometrical entity
//was defined in geometry section
sphere Note 1
{
level (1 1);
Name of faceZone
faceZone face_inner;
cellZone cell_inner; Name of cellZone

cellZoneInside inside; Create inner cellZone

//faceType internal; Create internal faces from faceZone


Uncomment to create the internal faceZone
}
Note 1:
} Optional specification of what to do with faceZone faces:

... internal: keep them as internal faces (default)


... baffle: create baffles from them. This gives more freedom in mesh
} motion
boundary: create free-standing boundary faces (baffles but
without the shared points)

e.g., faceType internal; 377


Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{

...
...
...

//Region-wise refinement
refinementRegions Dictionary block
{

//This region or geometrical entity


//was defined in the geometry section

box Note 1
{
mode inside;
levels (( 1 1 ));
}

//Mesh selection Note 1:


locationInMesh (-100.0 0.0 50.0 ); This region or geometrical entity was created in the geometry section.
}

378
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{

...
...
...

//Region-wise refinement
refinementRegions Dictionary block
{

//This region or geometrical entity


//was defined in the geometry section

box
{
mode inside;
levels (( 1 1 ));
}

}
This point defines where do you want the mesh.
Can be internal mesh or external mesh.
//Mesh selection
locationInMesh (-100.0 0.0 50.0 ); • If the point is inside the STL it is an internal mesh.
• If the point is inside the background mesh and outside the
} STL it is an external mesh.

At this point we have a valid mesh (cartesian)


379
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Snap mesh controls section
snapControls
{

//Number of patch smoothing iterations


//before finding correspondence to surface
nSmoothPatch 3;

tolerance 2.0;

//- Number of mesh displacement relaxation


//iterations.
nSolveIter 100; Note 1

//- Maximum number of snapping relaxation


//iterations. Should stop before upon
//reaching a correct mesh.
nRelaxIter 10; Note 2

// Feature snapping

//Number of feature edge snapping iterations.


nFeatureSnapIter 10; Note 3 Note 1:
The higher the value the better the body fitted mesh. The default value
//Detect (geometric only) features by is 30. If you are having problems with the mesh quality (related to the
//sampling the surface (default=false). snapping step), try to increase this value to 300. Have in mind that this
implicitFeatureSnap false; will increase the meshing time.

// Use castellatedMeshControls::features Note 2:


// (default = true) Increase this value to improve the quality of the body fitted mesh.
explicitFeatureSnap true;
Note 3:
multiRegionFeatureSnap false; Increase this value to improve the quality of the edge features.

} • In this step, we are generating the body fitted mesh.


380
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Boundary layer mesh controls section
addLayersControls
{
//Global parameters
relativeSizes true;
expansionRatio 1.2;
finalLayerThickness 0.5;
minThickness 0.01;

layers Note 1
{
wolf_wall Note 2
{
nSurfaceLayers 3;
//Local parameters
//expansionRatio 1.3;
//finalLayerThickness 0.3;
//minThickness 0.1;
}
}
// Advanced settings
nGrow 0;
featureAngle 130; Note 3 Note 1:
maxFaceThicknessRatio 0.5; In this section we select the patches where we want to add the
nSmoothSurfaceNormals 1; layers. We can add multiple patches (if they exist).
nSmoothThickness 10;
minMedianAxisAngle 90; Note 2:
maxThicknessToMedialRatio 0.3; This patch was created in the geometry section.
nSmoothNormals 3;
slipFeatureAngle 30; Note 3:
nRelaxIter 5; Specification of feature angle above which layers are collapsed
nBufferCellsNoExtrude 0; automatically.
nLayerIter 50;
nRelaxedIter 20; • In this step, we are generating the boundary layer mesh.
} 381
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Mesh quality controls section
meshQualityControls
{
maxNonOrtho 75; Note 1

maxBoundarySkewness 20;

maxInternalSkewness 4; Note 2

maxConcave 80;

minVol 1E-13;

//minTetQuality 1e-15;
minTetQuality -1e+30;

minArea -1;

minTwist 0.02;

minDeterminant 0.001;
Note 1:
Maximum non-orthogonality angle.
minFaceWeight 0.05;
Note 2:
minVolRatio 0.01;
Maximum skewness angle.
minTriangleTwist -1;
• During the mesh generation process, the mesh quality is continuously
monitored.
minFlatness 0.5; • The mesher snappyHexMesh will try to generate a mesh using the
mesh quality parameters defined by the user.
nSmoothScale 4;
• If a mesh motion or topology change introduces a poor quality cell or
face the motion or topology change is undone to revert the mesh back
errorReduction 0.75;
to a previously valid error free state.
}
382
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Mesh debug and write controls sections
debugFlags
(
// write intermediate meshes
mesh

// write current mesh intersections as .obj files


intersections

// write information about explicit feature edge


// refinement
featureSeeds

// write attraction as .obj files


attraction

// write information about layers


layerInfo
);

writeFlags
(
// write volScalarField with cellLevel for • At the end of the dictionary you will find the sections: debugFlags
// postprocessing and writeFlags
scalarLevels
• By default they are commented. If you uncomment them you will
// write cellSets, faceSets of faces in layer enable debug information.
layerSets
• debugFlags and writeFlags will produce a lot of outputs that you
// write volScalarField for layer coverage can use to post process and troubleshoot the different steps of
layerFields the meshing process.
);

383
Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo.
• This tutorial is located in the directory:
• $PTOFC/101SHM/M101_WD

• In this case we are going to generate a body fitted mesh with boundary layer. This is an
external mesh.
• Before generating the mesh take a look at the dictionaries and files that will be used.
• These are the dictionaries and files that will be used.
• system/snappyHexMeshDict
• system/surfaceFeaturesDict
• system/meshQualityDict
• system/blockMeshDict
• constant/triSurface/wolfExtruded.stl
• constant/triSurface/wolfExtruded.eMesh

• The file wolfExtruded.eMesh is generated after using the utility surfaceFeatures, which
reads the dictionary surfaceFeaturesDict.
384
Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo.

• To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> surfaceFeatures
4. $> snappyHexMesh
5. $> checkMesh –latestTime

• To visualize the mesh, in the terminal window type:


• $> paraFoam

• Remember to use the VCR controls in paraView/paraFoam to visualize the


mesh intermediate steps.
385
Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo.

• In the case directory you will find the time folders 1, 2, and 3, which contain
the castellated mesh, snapped mesh and boundary layer mesh respectively.
In this case, snappyHexMesh automatically saved the intermediate steps.
• Before running the simulation, remember to transfer the solution from the
latest mesh to the directory constant/polyMesh, in the terminal type:

1. $> cp 3/polyMesh/* constant/polyMesh


2. $> rm –rf 1
3. $> rm –rf 2
4. $> rm –rf 3
5. $> checkMesh –latestTime

386
Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo.

• If you want to avoid the additional steps of transferring the final mesh to the
directory constant/polyMesh by not saving the intermediate steps, you
can proceed as follows:

• $> snappyHexMesh –overwrite

• When you proceed in this way, snappyHexMesh automatically saves the


final mesh in the directory constant/polyMesh.
• Have in mind that you will not be able to visualize the intermediate steps.
• Also, you will not be able to restart the meshing process from a saved state
(castellated or snapped mesh).
• Unless it is strictly necessary, from this point on we will not save the
intermediate steps.
387
Mesh generation using snappyHexMesh
The constant/polyMesh/boundary file
• At this point, we have a valid mesh to run a simulation.
• Have in mind that before running the simulation you will need to set the boundary and initial
conditions in the directory 0.
• Let us talk about the constant/polyMesh/boundary file,
• First of all, this file is automatically generated after you create the mesh or you convert it
from a third-party format.
• In this file, the geometrical information related to the base type patch of each boundary of
the domain is specified.
• The base type boundary condition is the actual surface patch where we are going to apply
a numerical type boundary condition.
• The numerical type boundary condition assign a field value to the surface patch (base
type).
• You define the numerical type patch (or the value of the boundary condition), in the
directory 0 or time directories.
• The name and base type of the patches was defined in the dictionaries blockMeshDict
and snappyHexMeshDict.
• You can change the name if you do not like it. Do not use strange symbols or white
spaces.
• You can also change the base type. For instance, you can change the type of the patch
maxY from wall to patch. 388
Mesh generation using snappyHexMesh
The constant/polyMesh/boundary file
Number of surface patches
18 9 In the list bellow there must be 9 patches
19 (
20 minX definition.
21 {
22 type wall;
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 466399; wolf_wall
26 } maxY
27 maxX
28 {
29 type wall;
30 inGroups 1(wall);
31 nFaces 400;
32 startFace 466799;
33 } minZ
34 minY
35 {
36 type empty;
37 inGroups 1(wall);
38 nFaces 400;
39 startFace 467199;
40 }
41 maxY
minX maxX
42 {
43 type wall;
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 467599;
47 }
48 minZ maxZ
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 467999;
54 }
sphere
minY
sphere_slave
389
Mesh generation using snappyHexMesh
The constant/polyMesh/boundary file

18 9 Name
19 ( Name and type of the surface patches
20 minX
21 { • The name and base type of the patch is given by the user.
22 type wall; Type
23 inGroups 1(wall);
24 nFaces 400; • In this case the name and base type was assigned in the
25
26 }
startFace 466399;
dictionaries blockMeshDict and snappyHexMeshDict.
27 maxX
28 {
nFaces • You can change the name if you do not like it. Do not use
29 type wall;
30 inGroups 1(wall); startFace strange symbols or white spaces.
31 nFaces 400;
32
33 }
startFace 466799;
• You can also change the base type. For instance, you can
34 minY change the type of the patch maxY from wall to patch.
35 {
36 type empty;
37 inGroups 1(wall);
38 nFaces 400;
39 startFace 467199; nFaces and startFace keywords
40 }
41 maxY • Unless you know what are you doing, you do not
42 {
43 type wall; need to change this information.
44 inGroups 1(wall);
45
46
nFaces
startFace
400;
467599;
• Basically, this is telling you the starting face and ending face
47 } of the patch.
48 minZ
49 {
50 type wall; • This information is created automatically when generating
51
52
inGroups
nFaces
1(wall);
400;
the mesh or converting the mesh.
53 startFace 467999;
54 }

390
Mesh generation using snappyHexMesh
The constant/polyMesh/boundary file

55 maxZ
56 { Name and type of the surface patches
57 type wall;
58 inGroups 1(wall); • The name and base type of the patch is given by the user.
59 nFaces 400;
60 startFace 466399;
61 } Name • In this case the name and base type was assigned in the
62
63
wolf_wall
{
dictionaries blockMeshDict and snappyHexMeshDict.
64 type wall; Type
65 inGroups 1(wall); • You can change the name if you do not like it. Do not use
66 nFaces 400;
67 startFace 466799; strange symbols or white spaces.
68 }
69
70
sphere
{ nFaces • You can also change the base type. For instance, you can
71 type empty; startFace change the type of the patch maxY from wall to patch.
72 inGroups 1(wall);
73 nFaces 400;
74 startFace 467199;
75 }
76 sphere_slave nFaces and startFace keywords
77 {
78 type wall; • Unless you know what are you doing, you do not
79 inGroups 1(wall);
80 nFaces 400; need to change this information.
81 startFace 467599;
82
83 )
}
• Basically, this is telling you the starting face and ending face
of the patch.
• This information is created automatically when generating
the mesh or converting the mesh.

391
Mesh generation using snappyHexMesh

Cleaning the case directory


• When generating the mesh using OpenFOAM®, it is extremely important to
start from a clean case directory.

• To clean all the case directory, in the terminal type:

• $> foamCleanTutorials

• To only erase the mesh information, in the terminal type:

• $> foamCleanPolyMesh

• If you are planning to start the meshing from a previous saved state, you do
not need to clean the case directory.

• Before proceeding to compute the solution, remember to always check the


quality of the mesh.

392
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

393
snappyHexMesh guided tutorials
• Our first case will be a mesh around a cylinder.
• This is a simple geometry, but we will use it to study all the meshing steps
and introduce a few advanced features.
• This case is located in the directory $PTOFC/101SHM/M1cyl

394
snappyHexMesh guided tutorials

• Meshing with snappyHexMesh – Case 1.


• 3D cylinder with feature edge refinement (external mesh).
• You will find this case in the directory:

$PTOFC/101SHM/M1_cyl/C1

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
395
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

Sphere with no edge refinement Cylinder with edge refinement Cylinder with no edge refinement

• If the geometry has sharp angles and you want to resolve those edges, you should use edge
refinement.
• In the left figure there is no need to use edge refinement as there are no sharp angles.
• In the mid figure we used edge refinement to resolve the sharp angles.
• In the right figure we did not use edge refinement, therefore we did not resolve well the sharp
angles.

396
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we control curvature refinement and enable edge refinement?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{

...
...
...

//Local curvature and


//feature angle refinement
resolveFeatureAngle 30; To control curvature refinement

...
...
...

//Explicit feature edge refinement


features
(
{
To enable and
file “surfacemesh.eMesh";
control edge
level 0;
refinement level
}
);

...
...
...

} 397
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

How resolveFeatureAngle works?

angle < resolveFeatureAngle


If angle is more than resolveFeatureAngle
No curvature refinement
the adjacent STL faces will be marked for
refinement
angle

resolveFeatureAngle
STL

0: mark the whole surface for refinement


180: do not mark any STL face for refinement

398
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

How resolveFeatureAngle works?

angle > resolveFeatureAngle


If angle is more than resolveFeatureAngle
Curvature refinement
the adjacent STL faces will be marked for
refinement

angle

resolveFeatureAngle
STL

0: mark the whole surface for refinement


180: do not mark any STL face for refinement

399
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we control surface refinement?
• In the file snappyHexMeshDict, look for the following entry:

castellatedMeshControls
{
...
...
...

//Surface based refinement


refinementSurfaces
{
banana_stlSurface To control surface refinement.
{ The first digit controls the global
surface refinement level and the second
level (2 4); digit controls the curvature refinement
} level, according to the angle set in the
} entry resolveFeatureAngle

...
...
...

400
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we create refinement regions?
• In the file snappyHexMeshDict, look for the following entry:

geometry
{
...
...
...

refinementBox Name of refinement region


{
type searchableBox; Geometrical entity type.
min ( -2 -2 -2); This is the zone where we
max ( 2 2 2); want to apply the refinement
}

...
Dimensions of geometrical entity
...
...
};

401
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we create refinement regions?
• In the file snappyHexMeshDict, look for the following entry:

castellatedMeshControls
{
...
...
...

refinementRegions
{ Name of the region
refinementBox created in the geometry section
{
mode inside; Type of refinement (inside,
levels ((1e15 1)); outside, or distance mode)
}
}
Refinement level
...
... Distance from the surface
... A large value covers the whole region
}
402
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 0 Explicit feature edge refinement level 0
resolveFeatureAngle 110 resolveFeatureAngle 60
Surface based refinement level (2 2) Surface based refinement level (2 2)

• To control edges capturing you can decrease the value of resolveFeatureAngle.


• Be careful, this parameter also controls curvature refinement, so if you choose a low
value you also will be adding a lot of refinement on the surface.
403
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 0 Explicit feature edge refinement level 4
resolveFeatureAngle 60 resolveFeatureAngle 60
Surface based refinement level (2 2) Surface based refinement level (2 2)

• To control edges refinement level, you can change the value of the explicit feature
edge refinement level.

404
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 6 Explicit feature edge refinement level 0
resolveFeatureAngle 5 resolveFeatureAngle 5
Surface based refinement level (2 4) Surface based refinement level (2 4)

• To control edges refinement level, you can change the value of the explicit feature
edge refinement level.

405
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 0 Explicit feature edge refinement level 4
resolveFeatureAngle 60 resolveFeatureAngle 60
Surface based refinement level (2 4) Surface based refinement level (2 2)

• To control surface refinement level, you can change the value of the surface based
refinement level.
• The first digit controls the global surface refinement level and the second digit
controls the curvature refinement level. 406
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 0 Explicit feature edge refinement level 0
resolveFeatureAngle 60 resolveFeatureAngle 5
Surface based refinement level (2 4) Surface based refinement level (2 4)

• To control surface refinement due to curvature together with control based surface
refinement level, you can change the value of resolveFeatureAngle, and surface
based refinement level
407
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• Let us explore the dictionary surfaceFeaturesDict used by the utility
surfaceFeatures.
• This utility will extract surface features (sharp angles) according to an angle
criterion (includedAngle).
Features edges

Name of the STL.


surfaces (“surfacemesh.stl”) The STL file is located
in constant/triSurface

Angle criterion
includedAngle 150;
to extract features

subsetFeatures
{ Keep non-manifold edges
nonManifoldEdges yes; (edges with more that 2
connected faces)

Keep open edges


openEdges yes;
(edges with 1 connected face)
}
Features edges
If you want to save
writeObj yes;
the .obj files

408
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• Let us explore the dictionary surfaceFeaturesDict used by the utility
surfaceFeatures.
• This utility will extract surface features (sharp angles) according to an angle
criterion (includedAngle).

Name of the STL. If angle is less than includedAngle


surfaces (“surfacemesh.stl”) The STL file is located this feature will be marked
in constant/triSurface

angle
Angle criterion
includedAngle 150;
to extract features

subsetFeatures STL
{ Keep non-manifold edges includedAngle
nonManifoldEdges yes; (edges with more that 2
connected faces)

Keep open edges Mark edges whose adjacent surface normals


openEdges yes; are at an angle less than includedAngle
(edges with 1 connected face)
}
0: selects no edges
180: selects all edge
If you want to save
writeObj yes;
the .obj files

409
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• If you want to have a visual representation of the feature edges, you can use
paraview/paraFoam.
• Just look for the filter Feature Edges.
• Have in mind that the angle you need to define in paraview/paraFoam is the complement of the
angle you define in the dictionary surfaceFeaturesDict

410
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• In this case we are going to generate a body fitted mesh with edge refinement. This is an
external mesh.
• These are the dictionaries and files that will be used.
• system/snappyHexMeshDict
• system/surfaceFeaturesDict
• system/meshQualityDict
• system/blockMeshDict
• constant/triSurface/surfacemesh.stl
• constant/triSurface/surfacemesh.eMesh

• The file surfacemesh.eMesh is generated after using the utility surfaceFeatures, which
reads the dictionary surfaceFeaturesDict.
• The utility surfaceFeatures, will save a set of *.obj files with the captured edges. These files
are located in the directory constant/extendedFeatureEdgeMesh. You can use paraview
to visualize the *.obj files.

411
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

• Let us generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> surfaceFeatures
3. $> blockMesh
4. $> snappyHexMesh –overwrite
5. $> checkMesh –latestTime
6. $> paraFoam

• In step 2 we extract the sharp angles from the geometry.


• In step 3 we generate the background mesh.
• In step 4 we generate the body fitted mesh. Have in mind that as we use the
option –overwrite, we are not saving the intermediate steps.
• In step 5 we check the mesh quality.
412
snappyHexMesh guided tutorials
• Meshing with snappyHexMesh – Case 2.
• 3D cylinder with feature edge refinement and boundary layer (external
mesh).
• You will find this case in the directory:

$PTOFC/101SHM/M1_cyl/C2

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
413
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Your final mesh should looks like this one

414
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• How do we enable boundary layer?
• In the file snappyHexMeshDict, look for the following entry:

castellatedMesh true; //or false


Set this parameter to snap true; //or false
true if you want to
enable boundary layer
addLayers true; //or false
meshing

...
...
...

415
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• How do we enable boundary layer?
• In the file snappyHexMeshDict, look for the section addLayersControls:

addLayersControls
{

//Global parameters
relativeSizes true;
expansionRatio 1.2;
finalLayerThickness 0.5;
minThickness 0.1;

layers
{ Name of the surface or user-defined
banana_stlSurface patch where you want to add the
{ boundary layer mesh.
nSurfaceLayers 3;
}
}

// Advanced settings

...
...
...

416
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• How do we control boundary layer collapsing?
• In the file snappyHexMeshDict, look for the section addLayersControls:

addLayersControls
{

...
...
...

// Advanced settings
nGrow 0;
Increase this value to avoid BL
featureAngle 130; collapsing

...
...
...

417
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing

relativeSizes true relativeSizes false


expansionRatio 1.2 expansionRatio 1.2
finalLayerThickness 0.5 firstLayerThickness 0.025
minThickness 0.1 minThickness 0.01
featureAngle 130 featureAngle 130
nSurfaceLayers 3 nSurfaceLayers 3
Surface based refinement level (2 4) Surface based refinement level (2 4)

418
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing

• When the option relativeSizes is true, the boundary layer meshing is done relative to the size
of the cells next to the surface.
• This option requires less user intervention but can not guarantee a uniform boundary layer.
• Also, it is quite difficult to set a desired thickness of the first layer.
419
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing

• When the option relativeSizes is false, we give the actual thickness of the layers.
• This option requires a lot user intervention but it guarantees a uniform boundary layer and the
desired layer thickness. 420
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing

relativeSizes true relativeSizes true


expansionRatio 1.2 expansionRatio 1.2
finalLayerThickness 0.5 finalLayerThickness 0.5
minThickness 0.1 minThickness 0.1
featureAngle 130 featureAngle 130
nSurfaceLayers 3 nSurfaceLayers 3
Surface based refinement level (2 4) Surface based refinement level (2 2)

• When the option relativeSizes is true and in order to have a uniform boundary layer, we need
to have a uniform surface refinement.
• Nevertheless, we still do not have control on the desired thickness of the first layer. 421
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing

relativeSizes true relativeSizes true


expansionRatio 1.2 expansionRatio 1.2
finalLayerThickness 0.5 finalLayerThickness 0.5
minThickness 0.1 minThickness 0.1
featureAngle 130 featureAngle 30
nSurfaceLayers 3 nSurfaceLayers 3
Surface based refinement level (2 2) Surface based refinement level (2 2)

• To avoid boundary layer collapsing close to the corners, we can increase the value of the
boundary layer parameter featureAngle. 422
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing

relativeSizes false relativeSizes false


nSurfaceLayers 6 nSurfaceLayers 6
Refinement region at the stl surface:
mode distance;
levels ((0.05 4))

• The disadvantage of setting relativeSizes to false, is that it is difficult to control the expansion
ratio from the boundary layer meshing to the far mesh.
• To control this transition, we can add a refinement region at the surface with distance mode.
423
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

• To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> surfaceFeatures
3. $> blockMesh
4. $> snappyHexMesh -overwrite
5. $> checkMesh –latestTime
6. $> paraFoam

424
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

• At the end of the meshing process you will get the following information
regarding the boundary layer meshing:

patch faces layers overall thickness

[m] [%]

----- ----- ------ --- ---

banana_stlSurface 4696 3 0.0569 95.9

Layer mesh : cells:48577 faces:157942 points:61552

• This is a general summary of the boundary layer meshing.


• Pay particular attention to the overall and thickness information.
• Overall is roughly speaking the thickness of the whole boundary layer.
• Thickness is the percentage of the patch that has been covered with the boundary layer mesh. A thickness of
100% means that the whole patch has been covered (a perfect BL mesh). 425
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

• If you want to visualize the boundary layer thickness, you can enable
writeFlags in the snappyhexMeshDict dictionary,

...
...
...

writeFlags
(
scalarLevels; // write volScalarField with cellLevel for postprocessing
layerSets; // write cellSets, faceSets of faces in layer
layerFields; // write volScalarField for layer coverage
);

...
...
...

426
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

• Then you can use paraview/paraFoam to visualize the boundary layer


coverage.

Boundary layer thickness and number of layers

The yellow surface represent the BL coverage


427
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

• After creating the mesh and if you do not like the inflation layer or you want to
try different layer parameters, you do not need to start the meshing process
from scratch.
• To restart the meshing process from a saved state you need to save the
intermediate steps (castellation and snapping), and then create the inflation
layers starting from the snapped mesh.
• That is, do not use the option snappyHexMesh -overwrite.
• Also, in the dictionary controlDict remember to set the entry startFrom
to latestTime or the time directory where the snapped mesh is saved (in
this case 2).
• Before restarting the meshing, you will need to turn off the castellation and
snapping options and turn on the boundary layer options in the
snappyHexMeshDict dictionary.

428
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.

• Remember, before restarting the meshing you will need to modify the
snappyHexMeshDict dictionary as follows:

castellatedMesh false;
snap false;
addLayers true;

• At this point, you can restart the meshing process by typing in the terminal,
• $> snappyHexMesh

• By the way, you can restart the boundary layer mesh from a previous mesh
with a boundary layer.
• So in theory, you an add one layer at a time, this will give you more control
but it will require more manual work and some scripting.
429
snappyHexMesh guided tutorials
• Meshing with snappyHexMesh – Case 3.
• 3D cylinder with feature edge refinement and boundary layer using a STL
with multiple surfaces (external mesh).
• You will find this case in the directory:

$PTOFC/101SHM/M1_cyl/C3

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
430
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

STL visualization with a single surface using paraview (the STL visualization with multiple surfaces using paraview (each
single surface in represented with a single color) color corresponds to a different surface)

• When you use a STL with multiple surfaces, you have more control over the meshing process.
• By default, STL files are made up of one single surface.
• If you want to create the multiple surfaces you will need to do it in the solid modeler.
• Alternatively, you can split the STL manually or using the utility surfaceAutoPatch.
• Loading multiple STLs is equivalent to using a STL with multiple surfaces.
431
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

• When you use a STL with multiple surfaces, you have more control over the meshing process.
• In this case, we were able to use different refinement parameters in the lateral and central
surface patches of the cylinder. 432
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we assign different names to different surface patches?
• In the file snappyHexMeshDict, look for the following entry:
geometry
{
surfacemesh.stl
{
type triSurfaceMesh;
name stlSurface;

regions
{
patch0 Named region in the STL file
{
name surface0; User-defined patch name
} This is the name you need to use when setting the
patch1 boundary layer meshing
{
name surface1;
}
patch2
{
name surface2;
}
}
}
...
...
...
}
433
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we refine user defined surface patches?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
refinementSurfaces
{
level (2 2); Global refinement level
regions
{
patch0 Local surface patch
{
level (2 2); Local refinement level
patchInfo
{
type wall; Type of the patch.
} This information is optional
}
...
...
...
}
}
...
...
...
}
434
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we control curvature refinement on surface patches?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
refinementSurfaces
{
level (2 2); Global refinement level
regions
{
patch0 Local surface patch
{
level (2 4); Local curvature refinement (in red)
patchInfo
{
type wall;
}
}
...
...
...
}
}
...
...
...
}
435
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we control curvature refinement on surface patches?
• In the file snappyHexMeshDict, look for the following entry:

castellatedMeshControls
{

...
...
...

//Local curvature and


//feature angle refinement The default value is 30.
resolveFeatureAngle 60; Using a higher value will capture
less features.

...
...
...

436
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we control boundary layer meshing on the surface patches?
• In the file snappyHexMeshDict, look for the following entry:
addLayersControls
{

//Global parameters
relativeSizes true;
expansionRatio 1.2;
Global BL parameters
finalLayerThickness 0.5;
minThickness 0.1;
layers
{
“surface.*” POSIX wildcards are permitted
{
nSurfaceLayers 5;
}
surface0 Local surface patch
{
nSurfaceLayers 3;
expansionRatio 1.0;
finalLayerThickness 0.25; Local BL parameters
minThickness 0.1;
}
}

//Advanced settings
...
...
...
} 437
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

• Let us first create the STL file with multiple surfaces.


• In the directory geo, you will find the original STL file.
• In the terminal type:

1. $> cd geo

2. $> surfaceAutoPatch geo.stl output.stl 130

3. $> cp output.stl ../constant/triSurface/surfacemesh.stl

4. $> cd ..

5. $> paraview

• The utility surfaceAutoPatch will read the original STL file (geo.stl), and it will find the
patches using an angle criterion of 130 (similar to the angle criterion used with the utility
surfaceFeatures). It writes the new STL geometry in the file output.stl.
• By the way, it is better to create the STL file with multiple surfaces directly in the solid modeler.
• FYI, there is an equivalent utility for meshes, autoPatch. So if you forgot to define the
patches, this utility will automatically find the patches according to an angle criterion. 438
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

• If you open the file output.stl, you will notice that there are three
surfaces defined in the STL file. The different surfaces are defined in by the
following sections:

solid patch0
… Surface patch 1 • The name of the solid sections are
automatically given by the utility
endsolid patch0
surfaceAutoPatch.

solid patch1
• The convention is as follows: patch0,
… Surface patch 2
patch1, patch2, … patchN.
endsolid patch1

• If you do not like the names, you can


solid patch2
change them directly in the STL file.
… Surface patch 3

endsolid patch2

439
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

• The new STL file is already in the constant/triSurface directory.


• To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> surfaceFeatures
3. $> blockMesh
4. $> snappyHexMesh -overwrite
5. $> checkMesh –latestTime

• To visualize the mesh, in the terminal window type:


6. $> paraFoam

440
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

• This case is ready to run using the solver simpleFoam. But before running,
you will need to set the boundary and initial conditions.
• You will need to manually modify the file constant/polyMesh/boundary
• Remember:
• Base type boundary conditions are defined in the file boundary located
in the directory constant/polyMesh.
• Numerical type boundary conditions are defined in the field variables
files located in the directory 0 or the time directory from which you want
to start the simulation (e.g. U, p).
• The name of the base type boundary conditions and numerical type
boundary conditions needs to be the same.
• Also, the base type boundary condition needs to be compatible with the
numerical type boundary condition.
441
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.

• This case is ready to run with simpleFoam.


• To run the case (mesh and simulation), type in the terminal,

1. $> sh run_all.sh

• Feel free to open the files run_mesh.sh (meshing steps) and


run_solver.sh (simulation steps) to get an idea of all steps used.
• The most critical step is to give the right name and type to the boundary
patches, this is done in the file boundary and the input files located in the
directory 0 (boundary conditions and initial conditions).

442
snappyHexMesh guided tutorials

• Meshing with snappyHexMesh – Case 4.


• 2D cylinder (external mesh)
• You will find this case in the directory:

$PTOFC/101SHM/M1_cyl/C4

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
443
snappyHexMesh guided tutorials
2D Cylinder

From 3D To 2D

• To generate a 2D mesh using snappyHexMesh, we need to start from a 3D. After all,
snappyHexMesh is a 3D mesher.
• To generate a 2D mesh (and after generating the 3D mesh), we use the utility
extrudeMesh.
• The utility extrudeMesh works by projecting a face into a mirror face. Therefore,
the faces need to parallel. 444
snappyHexMesh guided tutorials
2D Cylinder

Geometry width
FACE 1

The utility extrudeMesh works by


projecting FACE 1 into FACE 2.
Therefore, the faces need to be
parallel.

FACE 2 Background mesh width

• At most, the input geometry and the background mesh need to have the same width.
• If the input geometry is larger than the background mesh, it will be automatically cut by the faces
of the background mesh.
• In this case, the input geometry will be cut by the two lateral patches of the background mesh.
• If you want to take advantage of symmetry in 3D, you can cut the geometry in half using one of
the faces of the background mesh.
• When dealing with 2D
• Extracting the features edges is optional for the 2D geometry extremes, but it is recommended if
there are internal edges that you want to resolve.
445
snappyHexMesh guided tutorials
2D Cylinder
• How do we create the 2D mesh?
• After generating the 3D mesh, we use the utility extrudeMesh.
• This utility reads the extrudeMeshDict,

constructFrom patch;

sourceCase “.”
sourcePatches (minZ); Name of source patch

exposedPatchName maxZ; Name of the mirror patch

extrudeModel linearNormal
Number of layers to use in the linear extrusion.
nLayers 1;
As this is a 2D case we must use 1 layer

linearNormalCoeffs
{
Thickness of the extrusion.
thickness 1;
It is highly recommended to use a value of 1
}

mergeFaces false;
446
snappyHexMesh guided tutorials
2D Cylinder

• To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> snappyHexMesh –overwrite
4. $> extrudeMesh
5. $> checkMesh –latestTime
6. $> paraFoam

• Remember, the utility extrudeMesh (step 4) reads the dictionary


extrudeMeshDict, which is located in the directory system.
• Also remember to set the empty patches in the dictionary boundary and in the
boundary conditions.
447
snappyHexMesh guided tutorials
Exercises
• To get a feeling of the surface refinement, try to change the value of the surface refinement in the dictionary
snappyHexMeshDict.
• In the dictionary snappyHexMeshDict, change the value of nCellsBetweenLevels and
resolveFeatureAngle. What difference do you see in the output?
• Use paraview to get a visual representation of the feature angles.
• In the dictionary snappyHexMeshDict, try to add curvature based refinement.
• In the dictionary snappyHexMeshDict, in the section addLayersControls change the value of
featureAngle. Use a value of 60 and 160 and compare the boundary layer meshing.
• To control the boundary layer collapsing, try to use a uniform surface refinement. For this you have two
options, set surface level refinement to a uniform value or adding distance region refinement at the wall.
• To control the boundary layer collapsing, try to use absolute sizes when creating the boundary layer mesh.
• To get a feeling of region refinement, try to change the value of the local refinement in the dictionary
snappyHexMeshDict. What difference do you see in the output?
• Try to use local inflation layers in the regions defined.
• In the dictionary extrudeMeshDict, change the value of nLayers and thickness.
• In the dictionary extrudeMeshDict, try to change the extrudeModel.

448
snappyHexMesh guided tutorials

• Meshing with snappyHexMesh – Case 5.


• Mixing elbow (internal mesh)
• You will find this case in the directory:

$PTOFC/101SHM/M2_mixing_elbow

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
449
snappyHexMesh guided tutorials
Mixing elbow.

Your final mesh should looks like this one


450
snappyHexMesh guided tutorials
Mixing elbow.
• How do we control surface refinement using region refinement?
• In the file snappyHexMeshDict, look for the following entry:

castellatedMeshControls
{
...
...
...

refinementRegions
{
mixing_elbow Name of surface
{
mode distance; Refinement using distance mode
levels ((1e-4 1));
}
}

... Distance from Refinement level


the surface patch
...
...
}
451
snappyHexMesh guided tutorials
Mixing elbow.
• In this case we are going to generate a body fitted mesh with edge
refinement and boundary layer meshing.
• This is an internal mesh.
• These are the dictionaries and files that will be used.
• system/snappyHexMeshDict
• system/surfaceFeaturesDict
• system/meshQualityDict
• system/blockMeshDict
• constant/triSurface/surfacemesh_multi.stl
• constant/triSurface/surfacemesh_multi.eMesh

• The file surfacemesh_multi.eMesh is generated after using the utility


surfaceFeatures, which reads the dictionary surfaceFeaturesDict.

452
snappyHexMesh guided tutorials
Mixing elbow.

• At this point, we are going to work in parallel (but you can work in serial as
well).
• To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> surfaceFeatures
3. $> blockMesh
4. $> decomposePar
5. $> mpirun -np 4 snappyHexMesh –parallel –overwrite
6. $> mpirun -np 4 checkMesh –parallel –latestTime
7. $> reconstructParMesh -constant
8. $> paraFoam

453
snappyHexMesh guided tutorials
Mixing elbow.
• So what did we do?
• Step 4: we distribute the mesh among the processors we want to use.
• Step 5 and 6: we run in parallel.
• Step 7: we put back together the decomposed mesh.
• Step 8: we visualize the reconstructed mesh.

• Notice that the utility blockMesh does not run in parallel.


• Remember to set the keyword numberOfSubdomains in the dictionary decomposeParDict
equal to the number of processors you want to use.
• In this case, as we are using 4 processors with mpirun, numberOfSubdomains needs to be
equal to 4.
• To run the simulation and after reconstructing the mesh, you will need to transfer the boundary
and initial conditions information to the decomposed mesh,
• $> decomposePar –fields
• Or you can force to decompose everything as follows,
• $> decomposePar –force
454
snappyHexMesh guided tutorials
Mixing elbow.
• After running checkMesh, you will get the following information regarding the patch
names:

Patch Faces Points Surface topology


mixing_elbow_inlet1 1264 1297 ok (non-closed singly connected)
pipe 38884 41118 ok (non-closed singly connected)
mixing_elbow_inlet2 314 337 ok (non-closed singly connected)
mixing_elbow_outlet 1264 1297 ok (non-closed singly connected)

• Sometimes you can get empty patches.

Patch Faces Points Surface topology


minX 0 0 ok (empty)
maxX 0 0 ok (empty)
minY 0 0 ok (empty)
maxY 0 0 ok (empty)
minZ 0 0 ok (empty)
maxZ 0 0 ok (empty)
mixing_elbow_inlet1 1264 1297 ok (non-closed singly connected)
pipe 38884 41118 ok (non-closed singly connected)
mixing_elbow_inlet2 314 337 ok (non-closed singly connected)
mixing_elbow_outlet 1264 1297 ok (non-closed singly connected)

455
snappyHexMesh guided tutorials
Mixing elbow.
• Empty patches are no problem, they remain from the background mesh.
• To erase the empty patches, you can do it manually (you will need to modify the file
boundary), or you can use the utility createPatch as follows (the utility runs in
parallel):
• $> createPatch -overwrite

• The surface patch pipe was created in the geometry section of the dictionary
snappyHexMeshDict.
• The patches mixing_elbow_outlet, mixing_elbow_inlet1 and
mixing_elbow_inlet2 were created automatically by snappyHexMesh.
• You have the choice of giving the names of the patches yourself or letting
snappyHexMesh assign the names automatically.
• Remember, when creating the boundary layer mesh, these are the names you need
to use to assign the layers.

456
snappyHexMesh guided tutorials
Mixing elbow.

• The mesh used in the previous case was a STL with multiple surfaces.
• In you do not create the regions in the geometry section of the dictionary
snappyHexMeshDict, snappyHexMesh will automatically assign the names of the
surface patches as follows:
system/surfaceFeaturesDict


• mixing_elbow_outlet …

• mixing_elbow_inlet1 geometry
{
surfacemesh.stl
• mixing_elbow_inlet2 {
type triSurfaceMesh;
name mixing_elbow;
regions
{
pipe NOTE 1
{
NOTE 2 name pipe;
}
}
}
NOTE 1:
};
This is the name of the region or surface patch in the STL file

NOTE 2:

User-defined patch name. This is the final name of the patch.

457
snappyHexMesh guided tutorials
Mixing elbow.

• The mesh used in the previous case was a STL with multiple surfaces.
• In you do not create the regions in the geometry section of the dictionary
snappyHexMeshDict, snappyHexMesh will automatically assign the names of the
surface patches as follows:
constant/triSurface/surfacemesh.stl

• mixing_elbow_outlet
solid outlet
• mixing_elbow_inlet1 …


• mixing_elbow_inlet2 solid outlet

solid inlet1



solid inlet1

solid inlet2



solid inlet2

458
snappyHexMesh guided tutorials
Mixing elbow.

• The mesh used in the previous case was a STL with multiple surfaces.
• In the directory geometry, you fill find the file allss.stl, this STL has one
single surface.
• Try to use this STL file to generate the mesh.
• You will notice that the final mesh has only one patch, namely
mixing_elbow (or whatever name you chose).
• Also, it is not possible to have local control on the mesh refinement and
boundary layer meshing.
• You will also face the conundrum that as there is only one surface patch, it is
not possible to assign boundary conditions.

459
snappyHexMesh guided tutorials
Mixing elbow.
• To solve the problem of the single surface patch, you can use the utility autoPatch.
To do so, you can proceed as follows:
• $> autoPatch 60 -overwrite
• The option -overwrite, will copy the new mesh in the directory
constant/polyMesh.
• The utility autoPatch will use an angle criterion to find the patches, and will assign
the name auto0, auto1, auto2 and auto3 to the new patches.
• The angle criterion is similar to that of the utility surfaceFeatures.
• The only difference is that it uses the complement of the angle. So, the smaller the
angle the more patches it will find.
• The naming convention is autoN, where N is the patch number.
• Remember, autoPatch will manipulate the mesh located in the directory
constant/polyMesh.
• FYI, autoPatch does not un in parallel.
460
snappyHexMesh guided tutorials
Exercises
• To get a feeling of the includedAngle value, try to change the value in the dictionary
surfaceFeaturesDict.
• Remember the higher the includedAngle value, the more features you will capture.
• In the dictionary snappyHexMeshDict, change the value of resolveFeatureAngle (try to use a lower value),
and check the mesh quality in the intersection between both pipes.
• In the castellatedMeshControls section, try to disable or modify the distance refinement of the
mixing_elbow region (refinementRegions).
• What difference do you see in the output?
• Starting from the body fitted mesh, add 3 inflation layers at the walls (save the intermediate step).
• Try to add local surface refinement at the surface patch inlet2 (look at the STL file
constant/triSurface/surfacemesh_multi.stl).
• Using paraview, extract the feature edge at the joint section of the pipes. Then, try to add local refinement at
this feature edge.
• Try to add curvature refinement at the feature edge extracted from the surface patch inlet1.

461
snappyHexMesh guided tutorials
Exercises
• Use the STL file with a single surface (surfacemesh_single.stl) and generate the same mesh, do not
add inflation layers.
• Use the utility autopatch to split the mesh in different surface patches. To get a feeling on how to use
this utility, use different angle values. Try to get four surface patches.
• After splitting the mesh in four surface patches, rename the boundary patches using the utility
createPatch.
• After renaming the boundary patches, change the type of each one using the utility foamDictionary.
• Starting from the body fitted mesh, add 3 inflation layers at the walls (do not save the intermediate step).
• Hints: if you do not know how to use the utilities createPatch and foamDictionary, look at the
script file run_mesh_single_surface.sh

• After generating the mesh, setup a simple incompressible simulation (with no turbulence model).
• Set the inlet velocity to 1 at both inlet patches and use a dynamic viscosity value equal to 0.01. Run the
simulation in steady and unsteady mode.

462
snappyHexMesh guided tutorials

• Meshing with snappyHexMesh – Case 6.


• Ahmed body (external mesh).
• You will find this case in the directory:

$PTOFC/101SHM/M4_ahmed

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
463
snappyHexMesh guided tutorials
Ahmed body

• At this point, we all have a clear idea of how snappyHexMesh works.


• If not, please raise your hand.
• So let us go free styling and let us play around with this case.
464
snappyHexMesh guided tutorials
Ahmed body
• In our YouTube channel you will find a playlist with many videos for this case. The playlist is
titled: CFD workflow tutorial using open-source tools.
• You can find our YouTube channel in the following link:
https://www.youtube.com/channel/UCNNBm3KxVS1rGeCVUU1p61g
• In these videos, we show a few extra features and some tips and tricks to take the most out of
snappyHexMesh.
• If you get lost, read the REAME.FIRST file that you will find in the working directory.
• The dictionaries snappyHexMeshDict and blockMeshDict used in this case are very
clean and ready to use. So feel free to use them as your templates.
• Our best advice is not to get lost in all the options available in the dictionary
snappyHexMeshDict. Most of the times the default options will work fine.
• That being said, you only need to read in the geometries, set the feature edges and surface
refinement levels, choose in which surfaces you want to add the boundary layers, and choose
how many layers you want to add.
• Final advices:
• If you are working with a complicated geometry, add one layer at a time.
• Use paraFoam/paraview to get visual references.
• Always check the quality of your mesh.

465
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

466
Mesh conversion
• OpenFOAM® gives users a lot of flexibility when it comes to meshing.
• You are not constrained to use OpenFOAM® meshing tools.
• To convert a mesh generated with a third-party software to OpenFOAM® format, you can use
the OpenFOAM® mesh conversion utilities.
• If your format is not supported, you can write your own conversion tool.
• By the way, many of the commercially available meshers can save the mesh in OpenFOAM®
format or in a compatible format.
• In the directory $PTOFC/mesh_conversion_sandbox you will find a few meshes generated
using the most popular third-party mesh generation applications.
• Feel free to play with these meshes.
• In the README.FIRST file of each case, you will find the instructions of how to convert the
mesh.

• Remember to always check the file boundary after converting the mesh. You
will need to change the name and type of the surface patches according to what
you would intent to do.
• Also, to convert the mesh you need to be in the top level of the case directory,
and you need to give to the conversion utility the path (absolute or relative) of
the mesh to be converted.

467
Mesh conversion
• In the directory $FOAM_UTILITIES/mesh/conversion you will find the source
code for the mesh conversion utilities:

• ansysToFoam • kivaToFoam
• cfx4ToFoam • mshToFoam
• datToFoam • netgenNeutralToFoam
• fluent3DMeshToFoam • Optional/ccm26ToFoam
• fluentMeshToFoam • plot3dToFoam
• foamMeshToFluent • sammToFoam
• foamToStarMesh • star3ToFoam
• foamToSurface • star4ToFoam
• gambitToFoam • tetgenToFoam
• gmshToFoam • vtkUnstructuredToFoam
• ideasUnvToFoam • writeMeshObj

• Take your time and read the instructions/comments contained in the source code of
the mesh conversion utilities so you can understand how to use these powerful tools.
468
Mesh conversion

• Let us convert to OpenFOAM® format a mesh generated using Salome.


• You will find this case in the directory:

$PTOFC/mesh_conversion_sandbox/M1_mixing_elbow_salome

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
469
Mesh conversion
Case 1. Mixing elbow (internal mesh).

• Remember to export the mesh in UNV format in Salome.


• Then use the utility ideasUnvToFoam to convert the mesh to OpenFOAM® native
format.
• In the terminal window type:

1. $> foamCleanTutorials
2. $> foamCleanPolyMesh
3. $> ideasUnvToFoam ../../meshes_and_geometries/salome_elbow3d/Mesh_1.unv

4. $> checkMesh
5. $> paraFoam

• Remember to always check the file boundary after converting the mesh.
• To convert the mesh, you need to be in the top level of the case directory, and you
need to give the path (absolute or relative) of the mesh to be converted.
470
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• ideasUnvToFoam output.

Create time

Processing tag:2411
Starting reading points at line 3.
Read 31136 points.

Processing tag:2412
Starting reading cells at line 62278.
First occurrence of element type 11 for cell 1 at line 62279
First occurrence of element type 41 for cell 361 at line 63359
First occurrence of element type 111 for cell 20933 at line 104503
Read 151064 cells and 20572 boundary faces. Internal cells and boundary faces read
Processing tag:2467
Starting reading patches at line 406633.
For group 1 named pipe trying to read 19778 patch face indices.
For group 2 named inlet1 trying to read 358 patch face indices.
For group 3 named inlet2 trying to read 78 patch face indices.
For group 4 named outlet trying to read 358 patch face indices.

Sorting boundary faces according to group (patch)


0: pipe is patch
1: inlet1 is patch
2: inlet2 is patch
3: outlet is patch

Constructing mesh with non-default patches of size:


pipe 19778
inlet1 358
inlet2 78 Boundary patches detected
outlet 358

End

471
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• checkMesh output.

Mesh stats
points: 31136
faces: 312414
internal faces: 291842
cells: 151064
faces per cell: 4
boundary patches: 4
point zones: 0
face zones: 0
cell zones: 0

Overall number of cells of each type:


hexahedra: 0
prisms: 0
wedges: 0
pyramids: 0
tet wedges: 0
tetrahedra: 151064
polyhedra: 0

Checking topology...
Boundary definition OK.
Cell to face addressing OK.
Point usage OK.
Upper triangular ordering OK.
Face vertices OK.
Number of regions: 1 (OK).

472
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• checkMesh output.

Checking patch topology for multiply connected surfaces...


Patch Faces Points Surface topology
pipe 19778 9938 ok (non-closed singly connected)
inlet1 358 200 ok (non-closed singly connected)
inlet2 78 50 ok (non-closed singly connected)
outlet 358 200 ok (non-closed singly connected)

Checking geometry...
Overall domain bounding box (0 -0.414214 -0.5) (5 5 0.5)
Mesh has 3 geometric (non-empty/wedge) directions (1 1 1)
Mesh has 3 solution (non-empty) directions (1 1 1)
Boundary openness (-1.0302e-17 -6.17232e-17 -1.77089e-16) OK.
Max cell openness = 2.32045e-16 OK.
Max aspect ratio = 4.67245 OK.
Minimum face area = 0.000286852. Maximum face area = 0.010949. Face area magnitudes OK.
Min volume = 2.74496e-06. Max volume = 0.00035228. Total volume = 6.75221. Cell volumes OK.
Mesh non-orthogonality Max: 54.2178 average: 15.1295
Non-orthogonality check OK.
Face pyramids OK.
Max skewness = 0.649359 OK.
Coupled point location match (average 0) OK.

Mesh OK. Everything is OK

End

473
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• The boundary file.

4 Number of boundary patches


(
pipe
{
Name of the boundary patches
type patch;
nFaces 19778;
startFace 291842; • In this case, the utility recognized the
}
inlet1 name of the boundary patches.
{
type
nFaces
patch;
358;
• If you do not like the names feel free to
}
startFace 311620; change them.
inlet2
{ • Remember, do not use spaces of
type
nFaces
patch;
78;
strange symbols.
startFace 311978;
}
outlet
{
type patch;
nFaces 358;
startFace 312056;
}
)

474
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• The boundary file.

4
(
pipe
{
type
nFaces
patch;
19778;
Base type of the boundary patches
startFace 291842;
}
inlet1
{
• In this case, the utility automatically
type patch; assigned the base type patch to all
nFaces 358;
startFace 311620; boundary patches.
}
inlet2
{
• Feel free to change the base type
type
nFaces
patch;
78;
according to your needs.
startFace 311978;
} • In this case, it will be wise to change
outlet
{
the base type of patch pipe to wall.
type patch;
nFaces 358;
startFace 312056;
}
)

475
Mesh conversion
Exercises
• Remember, you can change the name and type of the boundary patches manually, but as we want to do
things automatically, we will use the utilities createPatch and foamDictionary
• After converting the mesh to OpenFOAM® format, rename the boundary patches using the utility
createPatch.
• After converting the mesh to OpenFOAM® format, change the type of each boundary patch using the
utility foamDictionary.
• After converting the mesh to OpenFOAM® format, add 5 inflation layers at the walls (do not save the
intermediate step).
• Check the mesh quality before and after adding the inflation layers.
• After generating the mesh, setup a simple incompressible simulation (with no turbulence model).
• Set the inlet velocity to 1 at both inlet patches and use a dynamic viscosity value equal to 0.01. Run the
simulation in steady and unsteady mode.

476
Roadmap

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities

477
Geometry and mesh manipulation utilities
• First of all, by mesh manipulation we mean modifying a valid OpenFOAM®
mesh.
• These modifications can be scaling, rotation, translation, mirroring,
topological changes, mesh refinement and so on.
• In the directory $FOAM_UTILITIES/mesh/manipulation you will find the
mesh manipulation utilities. Just to name a few:

• autoPatch • rotateMesh
• checkMesh • setSet
• createBaffles • splitMesh
• mergeMeshes • splitMeshRegions
• mergerOrSplitBaffles • stitchMesh
• mirrorMesh • subsetMesh
• polyDualMesh • topoSet
• refineMesh • transformPoints
• renumberMesh
478
Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES/mesh/manipulation you will find the
following mesh manipulation utilities.
• Inside each utility directory you will find a *.C file with the same name as the
directory. This is the main file, where you will find the top-level source code and a
short description of the utility.
• For instance, in the directory checkMesh, you will find the file checkMesh.C, which
is the source code of the utility checkMesh. In the source code you will find the
following description:

Checks validity of a mesh.

Usage
- checkMesh [OPTION]

\param -allGeometry \n
Checks all (including non finite-volume specific) geometry

\param -allTopology \n
Checks all (including non finite-volume specific) addressing

\param -meshQuality \n
Checks against user defined (in \a system/meshQualityDict) quality settings

\param -region \<name\> \n


Specify an alternative mesh region.
479
Geometry and mesh manipulation utilities
• In OpenFOAM® it is also possible to manipulate the geometries in STL
format.
• These modifications can be scaling, rotation, translation, mirroring,
topological changes, normal orientation, and so on.
• In the directory $FOAM_UTILITIES/surface you will find the mesh
manipulation utilities. Just to name a few:

• surfaceAdd • surfaceMeshConvert
• surfaceAutoPatch • surfaceMeshExport
• surfaceBooleanFeatures • surfaceMeshTriangulate
• surfaceCheck • surfaceOrient
• surfaceConvert • surfaceSplitByPatch
• surfaceFeatureConvert • surfaceSubset
• surfaceFeatures • surfaceToPatch
• surfaceInertia • surfaceTransformPoints
480
Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES/surface you will find the following surface
manipulation utilities.
• Inside each utility directory you will find a *.C file with the same name as the
directory. This is the main file, where you will find the top-level source code and a
short description of the utility.
• For instance, in the directory surfaceTransformPoints, you will find the file
surfaceTransformPoints.C, which is the source code of the utility
surfaceTransformPoints. In the source code you will find the following
description:

Transform (scale/rotate) a surface.


Like transformPoints but for surfaces.
The rollPitchYaw option takes three angles (degrees):
- roll (rotation about x) followed by
- pitch (rotation about y) followed by
- yaw (rotation about z)
The yawPitchRoll does yaw followed by pitch followed by roll.

481
Geometry and mesh manipulation utilities

• Let us do some surface manipulation.


• For this we will use the ahmed body tutorial.
• You will find this case in the directory:

$PTOFC/mesh_quality_manipulation/M5_ahmed_body_transform

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
482
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• We will now manipulate a STL geometry. In the terminal type:

1. $> foamCleanTutorials
2. $> surfaceMeshInfo ./constant/triSurface/ahmed_body.stl
3. $> surfaceCheck ./constant/triSurface/ahmed_body.stl
$> surfaceTransformPoints -rollPitchYaw '(0 0 15)’
4. ./constant/triSurface/ahmed_body.stl rotated.stl
$> surfaceTransformPoints -translate '(0 0.12 0)'
5. ./constant/triSurface/ahmed_body.stl translated.stl
$> surfaceTransformPoints -scale '(0.9 1.1 1.3)'
6. ./constant/triSurface/ahmed_body.stl scaled.stl
$> surfaceInertia -density 2700 –noFunctionObjects
7. ./constant/triSurface/ahmed_body.stl
$> surfaceOrient ./constant/triSurface/ahmed_body_wrong_normals.stl
8. out.stl ‘(1e10 1e10 1e10)’

483
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• In step 2 we use the utility surfaceMeshInfo to get general information about the STL (such
as number of faces and so on).
• In step 3 we use the utility surfaceCheck to check the STL file.
• In step 4 we use the utility surfaceTransformPoints to rotate the STL. We read in the STL
./constant/triSurface/ahmed_body.stl and we write out the STL rotated.stl
• In step 5 we use the utility surfaceTransformPoints to translate the STL. We read in the
STL ./constant/triSurface/ahmed_body.stl and we write out the STL
translated.stl
• In step 6 we use the utility surfaceTransformPoints to scale the STL. We read in the STL
./constant/triSurface/ahmed_body.stl and we write out the STL scaled.stl
• In step 7 we use the utility surfaceInertia to compute the inertia of the STL. We read in the
STL ./constant/triSurface/ahmed_body.stl. Notice that we need to give a reference
density value.
• In step 8 we use the utility surfaceOrient to orient the normals of the STL in the same way.
We read in the STL ./constant/triSurface/ahmed_body_wrong_normals.stl and we
write out the STL out.stl. Notice that we give an outside point or ‘(1e10 1e10 1e10)’, if
this point is outside the STL all normals will be oriented outwards, if the point is inside the STL
all normals will be oriented inwards.
484
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• Pay particular attention to step 8.
• We already have seen that snappyHexMesh computes surface angles using the surface
normals as a reference, so it is extremely important to have the normals oriented in the same
way and preferably outwards.

ahmed_body_wrong_normals.stl STL after orienting all normals in the same


direction.

485
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• To plot the normals in paraview/paraFoam you can use the filter Normal Glyphs
Select the Normal Glyphs from the filter menu

Apply the Normal Glyphs


filter to the STL

Uncheck this option

Scale the vectors to fit the screen

486
Geometry and mesh manipulation utilities

• Let us do some mesh manipulation.


• For this we will use the 2D cylinder tutorial.
• You will find this case in the directory:

$PTOFC/mesh_quality_manipulation/M7_cylinder_transform

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
487
Geometry and mesh manipulation utilities
Mesh manipulation in OpenFOAM®
• We will now manipulate a mesh. In the terminal type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> transformPoints -rollPitchYaw '(0 0 90)'
4. $> transformPoints -scale '(0.01 0.01 0.01)'
5. $> transformPoints -translate '(0 0 1)'
6. $> createPatch -noFunctionObjects –overwrite
7. $> checkMesh
8. $> paraFoam

• In step 3 we use the utility transformPoints to rotate the mesh. We rotate the mesh by 90° about the Z
axis.
• In step 4 we use the utility transformPoints to scale the mesh. We scale the mesh by a factor of '(0.01
0.01 0.01)'.
• In step 5 we use the utility transformPoints to translate the mesh. We translate the mesh by the vector
'(0 0 1)'.
• In step 6 we use the utility createPatch to rename the patches of the mesh. This utility reads the dictionary
system/createPatchDict. Instead of using the utility createPatch we could have modified the
boundary file directly.
• This case is ready to run using the solver buoyantBoussinesqPimpleFoam. 488
Geometry and mesh manipulation utilities
Mesh manipulation in OpenFOAM®

Original mesh

After renaming the patches and transforming the mesh, we can


use it to conduct this buoyant flow simulation
www.wolfdynamics.com/wiki/heated_cyl/ani1.gif

Transformed mesh 489


Module 4
Running in parallel

490
Roadmap

1. Running in parallel

491
Running in parallel
• First of all, to know how many processors/cores you have available in your computer, type in the
terminal:
• $> lscpu
• The output for this particular workstation is the following:

Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Total number of cores available after
CPU(s): 24
hyper threading (virtual cores)
On-line CPU(s) list: 0-23
Thread(s) per core: 2
Core(s) per socket: 6 Number of threads per core (hyper threading)
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel Number of cores per socket or physical
CPU family: 6 processor
Model: 44
Model name: Intel(R) Xeon(R) CPU X5670 @ 2.93GHz
Stepping: 2 Number of sockets (physical processors)
CPU MHz: 1600.000
CPU max MHz: 2934.0000
CPU min MHz: 1600.0000
BogoMIPS: 5851.91
Total number of physical cores
Virtualization: VT-x
=
L1d cache: 32K
Number of cores per socket X Number of sockets
L1i cache: 32K
L2 cache: 256K
L3 cache: 12288K Total number of physical cores = 6 X 2 = 12 cores
NUMA node0 CPU(s): 0-5,12-17
NUMA node1 CPU(s): 6-11,18-23

This is what makes a processor expensive


492
Running in parallel
• OpenFOAM® does not take advantage of hyper threading technology (HT).
• HT is basically used by the OS to improve multitasking performance.
• This is what we have in the workstation of the previous example:
• 24 virtual cores (hyper threaded)
• 12 physical cores

• To take full advantage of the hardware, we use the maximum number of physical
cores (12 physical cores in this case) when running in parallel.
• If you use the maximum number of virtual cores, OpenFOAM® will run but it will be
slower in comparison to running with the maximum number of physical cores (or even
less cores).
• Same rule applies when running in clusters/super computers, so always read the
hardware specifications to know the limitations.

493
Running in parallel
Why use parallel computing?

• Solve larger and more complex problems (scale-up):

Thanks to parallel computing we can solve bigger problems (scalability). A single computer has limited
physical memory, many computers interconnected have access to more memory (distributed memory).

• Provide concurrency (scale-out):

A single computer or processor can only do one thing at a time. Multiple processors or computing
resources can do many things simultaneously.

• Save time (speed-up):

Run faster (speed-up) and increase your productivity, with the potential of saving money in the design
process.

• Save money:

In theory, throwing more resources at a task will shorten its time to completion, with potential cost
savings. Parallel computers can be built from cheap, commodity components.

• Limits to serial computing:

Both physical and practical reasons pose significant constraints to simply building ever faster serial
computers (e.g, transmission speed, CPU clock rate, limits to miniaturization, hardware cooling).

494
Running in parallel
Speed-up and scalability example

• In the context of high-performance computing (HPC), there are two common metrics that measure the
scalability of the application:
• Strong scaling (Amdahl’s law): which is defined as how the solution time varies with the number of
processors for a fixed problem size (number of cells in CFD)
• Weak scaling (Gustafson’s law): which is defined as how the solution time varies with the number of
processors for a fixed problem size per processor (or increasing the problem size with a fix number of
processors).
• In this example, when we reach 12 cores inter-processor communication slow-downs the computation. But if we
increase the problem size for a fix number of processors, we will increase the speed-up.
• The parallel case with 1 processor runs slower than the serial case due to the extra overhead when calling the
MPI library. 495
Running in parallel
• The method of parallel computing used by OpenFOAM® is known as domain
decomposition, in which the geometry and associated fields are broken into pieces
and distributed among different processors.

Shared memory architectures – Workstations and portable computers

Distributed memory architectures – Clusters and super computers


496
Running in parallel
Some facts about running OpenFOAM® in parallel:
• Applications generally do not require parallel-specific coding. The parallel
programming implementation is hidden from the user.
• In order to run in parallel you will need an MPI library installation in your system.
• Most of the applications and utilities run in parallel.
• If you write a new solver, it will be in parallel (most of the times).
• We have been able to run in parallel up to 15000 processors.
• We have been able to run OpenFOAM® using single GPU and multiple GPUs.
• Do not ask about scalability, that is problem/hardware specific.
• If you want to learn more about MPI and GPU programming, do not look in my
direction.
• And of course, to run in parallel you need the hardware.

497
Running in parallel
To run OpenFOAM® in parallel you will need to:

• Decompose the domain.


To do so we use the decomposePar utility. You also need the dictionary
decomposeParDict which is located in the system directory.

• Distribute the jobs among the processors or computing nodes.


To do so, OpenFOAM® uses the standard message passing interface (MPI).
By using MPI, each processor runs a copy of the solver on a separate part
of the decomposed domain.

• Additionally, you might want to reconstruct (put back together) the


decomposed domain.
This is done by using the reconstrucPar utility. You do not need a
dictionary to use this utility.
498
Running in parallel
Domain Decomposition in OpenFOAM®
• The mesh and fields are decomposed using the decomposePar utility.
• They are broken up according to a set of parameters specified in a dictionary named
decomposeParDict that is located in the system directory of the case.
• In the decomposeParDict dictionary the user must set the number of domains in which the
case should be decomposed (using the keyword numberOfSubdomains). The value used
should correspond to the number of physical cores available.

numberOfSubdomains 128; Number of subdomains

method scotch; Decomposition method

• In this example, we are subdividing the domain in 128 subdomains, therefore we should have
128 physical cores available.
• The main goal of domain decomposition is to minimize the inter-processors communication and
the processor workload.
499
Running in parallel
Domain Decomposition Methods
• These are the decomposition methods available in OpenFOAM® 8. To name a few:
• hierarchical
• manual
• metis
• multiLevel
• none We highly recommend you to use this method.
The only input that requires from the user is
• scotch the number of subdomains/cores. This method
attempts to minimize the number of processor
• simple
boundaries.
• structured

• If you want more information about each decomposition method, just read the source code:
• $WM_PROJECT_DIR/src/parallel/decompose/

500
Running in parallel
Running in parallel – Gathering all together

The information inside the


directories polyMesh/ and
0/ is decomposed using the
utility decomposePar

decomposePar

processor0 processor1 processor2 processor3

• Inside each processorN directory you will have the mesh information, boundary conditions,
initial conditions, and the solution for that processor.
501
Running in parallel
Running in parallel – Gathering all together
• After decomposing the mesh, we can run in parallel using MPI.

• The interface between each region, is know


as halo zone.
• The inter-processor communication in the
halo zone is managed by the MPI library.
• Remember, the main goal is to minimize the
halo zone, therefore, the inter-processor
communication.

$> mpirun –np <NPROCS> <application/utility> –parallel

• The number of processors to use or <NPROCS>, needs to be the same as the number of
partitions (numberOfSubdomains).
• Do not forget to use the flag –parallel.

502
Running in parallel
Running in parallel – Gathering all together
• In the decomposed case, you will find the mesh
information, boundary conditions, initial conditions, and
the solution for every processor.
• The information is inside the directory processorN
(where N is the processor number).

reconstructPar

• When you reconstruct the case, you glue together all the
information contained in the decomposed case.
• All the information (mesh, boundary conditions, initial
conditions, and the solution), is transfer to the original
case folder (polyMesh and time solution directories).

503
Running in parallel
Running in parallel – Gathering all together
• Summarizing, to run in parallel we proceed in the following way:

1. $> decomposePar
2. $> mpirun –np <NPROCS> <application/utility> –parallel
3. $> reconstructPar

• When running in parallel, do not forget to add this flag.


• If you do not add this flag, the application will run, but
it will execute <NPROCS> duplicates of the same job
(it will be slower).

• You can do the post-processing and visualization on the decomposed case or reconstructed
case. We are going to address this later on.
• If you are dealing with moving bodies where the mesh topology is changed or if you are using
AMR, you will need to use reconstructParMesh before reconstrucPar.

504
Running in parallel
Kelvin Helmholtz instability in a coarse mesh

Mesh size
Processors Clock time (seconds)
in x, y, and z directions

1 955 800 X 160 X 1

2 564 800 X 160 X 1

4 333 800 X 160 X 1

8 234 800 X 160 X 1

12 244 800 X 160 X 1

Volume fraction
www.wolfdynamics.com/wiki/kelvin_helmholtz/ani1.gif

You will find this case in the directory: $PTOFC/parallel/kelvin_helmholtz 505


Running in parallel
Visualization of a parallel case

• The traditional way is to first reconstruct the case and then do the post-processing and
visualization on the reconstructed case.
• To do so, we type in the terminal:

1. $> reconstructPar
2. $> paraFoam

• Step 1 reconstruct the case. Remember, you can choose to reconstruct all the time steps, the
last time step or a range of time steps.
• In step 2, we use paraFoam to visualize the reconstructed case.

506
Running in parallel
Visualization of a parallel case
• An alternative way to visualize the solution, is by proceeding in the following way
• $> paraFoam –builtin

• The option –builtin let us post-process the decomposed case directly.


• Remember, you will need to select on the object inspector the Decomposed Case option.

507
Running in parallel
Visualization of a parallel case
• Both of the previous methods are valid.
• When we use the option –builtin with paraFoam, we have the option to work on the
decomposed case directly. In other words, we do not need to reconstruct the case.
• This option is also faster than running paraFoam with no flags.
• But wait, there is a third option.
• The third option consist in post-processing each decomposed domain individually.
• To load all processor directories, you will need to manually create the file
processorN.OpenFOAM (where N is the processor number) in each processor folder.
• After creating all processorN.OpenFOAM files, you can launch paraFoam and load each file
(the processorN.OpenFOAM files).
• As you can see, this option requires more input from the user.

508
Running in parallel
Decomposing big meshes
• One final word, the utility decomposePar does not run in parallel.
• So, it is not possible to distribute the mesh among different computing nodes to do the
partitioning in parallel.
• If you need to partition big meshes, you will need a computing node with enough memory to
handle the mesh.
• We have been able to decompose meshes with up to 500 000 000 elements, but we used a
computing node with 512 gigs of memory.
• For example, in a computing node with 16 gigs of memory, it is not possible to decompose a
mesh with 30 000 000. You will need to use a computing node with at least 32 gigs of memory.
• Same applies for the utility reconstructPar.

509
Running in parallel
Do all utilities run in parallel?
• At this point, you might be wondering if all solvers/utilities run in parallel.
• To know what solvers/utilities do not run in parallel, in the terminal type:
• $> find $WM_PROJECT_DIR -type f | xargs grep –sl ‘noParallel’
• Paradoxically, the utilities used to decompose the domain and reconstruct the domain do not
run in parallel.
• Another important utility that does not run in parallel is blockMesh. So to generate big meshes
with blockMesh you need to use a big fat computing node.
• Another important utility that does not run in parallel by default is paraFoam.
• To compile paraFoam with MPI support, in the file makeParaView (located in the directory
$WM_THIRD_PARTY_DIR), set the option withMPI to true,
• withMPI = true
• While you are working with the file makeParaView, you might consider enabling Python
support,
• withPYTHON = true

510
Running in parallel
Exercises
• Choose any tutorial or design your own case and do a scalability test. Scale your case with two different
meshes (a coarse and a fine mesh).
• Run the same case using different partitioning methods. Which method scales better? Do you get the same
results?
• Do you think that the best partitioning method is problem dependent?
• Compare the wall time of a test case using the maximum number of cores and the maximum number of virtual
cores. Which scenario is faster and why?
• Run a parallel case without using the –parallel option. Does it run? Is it faster of slower? How many
outputs do you see on the screen?
• Do you get any speed-up by using renumberMesh?
• What applications do not run in parallel?

511
Module 5
The postprocess utility – Sampling – Probing
– On-the-fly postprocessing – Field
manipulation – Data conversion

512
Roadmap

1. On-the-fly postprocessing – functionObjects and the


postProcess utility
2. Sampling with the postProcess utility
3. Field manipulation
4. Data conversion

513
On-the-fly postprocessing – functionObjects

• It is possible to perform data extraction/manipulation operations while the simulation


is running by using functionObjects.
• functionObjects are small pieces of code executed at a regular interval without
explicitly being linked to the application.
• When using functionObjects, files of sampled data can be written for plotting and
post processing.
• functionObjects are specified in the controlDict dictionary and executed at pre-
defined intervals.
• All functionObjects are runtime modifiable.
• Depending of the functionObject you are using, its output is saved in the directory
postProcessing or in the solution directory (time directories).
• It is also possible to execute functionObject after the simulation is over, we will call
this running functionObject a-posteriori.
• For example, you can use functionObjects to compute the Mach number, the
vorticity field, and to sample the velocity at given points or along a line, and
everything while the simulation is running.

514
On-the-fly postprocessing – functionObjects
• In the directory $FOAM_SRC/functionObjects you will find the source code for the
functionObjects.
• There are many functionObjects, and according to what they do, they are located in different
sub-directories, namely, field, forces, lagrangian, solvers, and utilities. Just to
name a few functionObjects:

• courantNo • forceCoeffs
• div • forces
• fieldAverage • icoUncoupledKinematicCloud
• fieldMinMax • scalarTransport
• grad • codedFunctionObject
• MachNo • residuals
• Q • systemCall
• vorticity • timeActivatedFileUpdate
• yPlus • writeObjects

• In addition to the functionObjects located in the directory $FOAM_SRC/functionObjects,


you can also run the sampling and co-processing utilities on-the-fly.
• You will find the source code for the sampling and co-processing utilities in the directory
$FOAM_SRC/sampling. 515
On-the-fly postprocessing – functionObjects
• functionObjects are defined in the controlDict dictionary.
• To execute a functionObject you need to at least define the following entries:

function_object_name User given name

type function_object_to_use; functionObject to use

functionObjectLibs ("function_object_library.so"); Library to use

enabled true; Turn on/off functionObject

log true; Show on screen the output of


the functionObject
writeControl outputTime;
timeStart 0; Output frequency
timeEnd 20;

// ...
// functionObject Keywords and sub-dictionaries
// keywords and sub-dictionaries specific to the functionObject
// ...

516
On-the-fly postprocessing – functionObjects
• There are many functionObjects implemented in OpenFOAM®, and sometimes is
not very straightforward how to use a specific functionObject.
• Also, functionObjects can have many options and some limitations.
• Our best advice is to read the doxygen documentation or the source code to learn
how to use functionObjects.
• Remember, the source code of the functionObjects is located in the directory:
$WM_PROJECT_DIR/src/postProcessing/functionObjects

• The source code of the sampling and co-processing utilities is located in the directory:
$WM_PROJECT_DIR/src/sampling

• The source code of the database entries required for the functionObjects is located
in the directory:
$FOAM_SRC/OpenFOAM/db/functionObjects

• Here after we are going to study a few commonly used functionObjects.


517
On-the-fly postprocessing – functionObjects

• Let us do some on-the-fly postprocessing.


• For this we will use the multi-element airfoil 2D case.
• You will find this case in the directory:

$PTOFC/101postprocessing/MDA_30P30N

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
518
On-the-fly postprocessing – functionObjects
At the end of the day, you should get something like this

Qualitative post-processing Quantitative post-processing

cd cl

Experimental values 0.0332 2.167

Numerical values 0.0346 2.238

Additionally, by using functionObjects we will


compute many derived quantities, such as,
• yPlus.
• Voriticity.
• Mean values of the field variables (notice
that we will compute the average of a
steady solution).
• Forces.
• Force coefficients.
• Minimum and maximum values of the field
variables.
• Sampling at given points.
• Mass flow at inlets and outlets.
519
On-the-fly postprocessing – functionObjects
At the end of the day, you should get something like this

Quantitative post-processing 520


On-the-fly postprocessing – functionObjects
At the end of the day, you should get something like this

Should I stop here? Or should I stop here?

Quantitative post-processing – Assessing residuals 521


On-the-fly postprocessing – functionObjects
Running the case

• Let us run this case using the automatic scripts distributed with the tutorial. In the
terminal type:

1. $> sh run_all.sh

• After the simulation is finish, you will find the decomposed directories (processor0,
processor1, processor2 and processor3), the postProcessing directory,
and the 2000 directory. The solution, and output of the functionObjects, is saved in
these directories.
• Remember, to visualize the decomposed solution you will need to launch paraFoam
as follows,

1. $> paraFoam -builtin

• Do not erase the solution as we are going to use it in the next section.

522
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us take a look at the bottom of the controlDict
51 functions dictionary file. In this dictionary is where we define all
52 {
functionObjects.
name_of_the_functionObject_dictionary
{ • Within this dictionary, functionObjects are defined in
}
Sub-dictionary with functionObject entries
the sub-dictionary functions, i.e.,

206 #include "externalFunctionObject"


functions
211 }
{
functionObjects definition
};

• In this case, the functionObjects are defined in lines


51-211 (the sub-dictionary functions).
• Each defined functionObject has its own name and its
compulsory keywords and entries.
• Notice that in line 206 we use the directive include to call
an external dictionary with the functionObjects
definition.
• If you do not give the path of the external dictionary, the
solver will look for it in the directory system.
• If you use the include directive, you will need to update
the controlDict dictionary in order to read any
modification done in the included dictionary files. 523
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us explain in detail how to setup a functionObject.
51 functions
52 { • As the names implies, this functionObject is used to
56 forces_object
functionObject identifier compute the forces on a given body or set of bodies
57 { (user given)
58 type forces; (line 56).
• You can add as many forces functionObjects (or any
59 functionObjectLibs ("libforces.so");
60 other one) as you like, but you should assign them
61
62 writeControl timeStep;
different identifiers (line 56). Remember not to use
63 writetInterval 1; white spaces when naming functionObjects.
64
65
66
enabled true; • The output of this functionObject is saved in the
67 //// Patches to sample directory postProcessing/forces_object,
68 patches ("wall_slat" "wall_airfoil" "wall_flap");
where the directory name is taken from line 56.
70 //// Name of fields • Inside this directory, you will find the subdirectory 0,
71 pName p;
72 Uname U; which means that you started to sample data from time
0. If you start from a different time, you will find a
different subdirectory, e.g., 86.05
74 //only for incompressible flows
75
76
rho rhoInf;
rhoInf 1.0;
• Remember, different functionObjects will have
different entries, to know the entries just refer to the
online documentation or skim the source code, which
78 //// Centre of rotation is located in the directory,
79 CofR (0 0 0);
80 }
• $WM_PROJECT_DIR/src/postProcessing/f
211 } unctionObjects
524
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us study all entries of the forces functionObject
51 functions
52 {

56 forces_object functionObject identifier (user given)


57 {
58 type forces;
functionObject to use

59 functionObjectLibs ("libforces.so"); functionObject library to use


60
61
62 writeControl timeStep; Controls for saving frequency
63 writetInterval 1;
64
65 enabled true; Turn on/off functionObject
66
67 //// Patches to sample
68 patches ("wall_slat" "wall_airfoil" "wall_flap"); Compute the forces on these patches

70 //// Name of fields Name of the velocity and pressure fields. If you use
71 pName p;
72 Uname U; different fields, e.g., pMean and Umean, they need to be
computed before this functionObject

74 //only for incompressible flows Reference density value. It only needs to be defined for
75 rho rhoInf;
76 rhoInf 1.0;
incompressible flows. For compressible flows, the
computed density is used instead (you will need to define
a dummy value, though)
78 //// Centre of rotation
79 CofR (0 0 0); Reference center of rotation to compute moments
80 }
Note:
211 } • The source code of this functionObject is located in the directory
$FOAM_SRC/functionObjects/forces/forces
• Use the banana method to know all the options available for each entry. 525
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us study now the functionObject used to
51 functions
52 { functionObject compute the force coefficients.
86 forceCoeffs_object
identifier (user given)
87 {
88 type forceCoeffs;
89 functionObjectLibs ("libforces.so");
90
91 enabled true;
92 • This functionObject computes the force coefficients.
93 patches ("wall_slat" "wall_airfoil" "wall_flap");
94
• These entries are similar to those of the force
95 pName p; functionObject
96 Uname U;
97
99 rho rhoInf;
100 rhoInf 1.0;
101
This option will output the values to a text file located in the
103 log true; directory postProcessing/forceCoeffs_object
104
105 CofR (0.0 0 0);
106 Reference center of rotation to compute moments
107 pitchAxis (0 0 1);
108 magUInf 1.0;
109 lRef 1; Reference values used to compute coefficients
110 Aref 1;
111
115 writeControl timeStep;
116 writeInterval 1; Controls for saving frequency
117
119 liftDir (0 1 0);
120 dragDir (1 0 0); Reference axes to compute the lift and drag coefficients.
121
125 }

211 }

526
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us study now the functionObject used to
51 functions
52 { functionObject compute the force coefficients.
86 forceCoeffs_object
identifier (user given)
87 {
88 type forceCoeffs;
89 functionObjectLibs ("libforces.so");
90
91 enabled true;
92
93 patches ("wall_slat" "wall_airfoil" "wall_flap");
94
95 pName p;
96 Uname U;
97
99 rho rhoInf;
100 rhoInf 1.0;
101
103 log true;
104
105 CofR (0.0 0 0);
106
107 pitchAxis (0 0 1);
108 magUInf 1.0;
109 lRef 1;
110 Aref 1;
111
115 writeControl timeStep;
116 writeInterval 1;
117 • Reference axes to compute the lift and drag coefficients.
119 liftDir (0 1 0);
120 dragDir (1 0 0); • Remember, lift and drag are perpendicular and parallel
121
125 } to the incoming flow, respectively.

211 } • So if the inlet velocity is entering at a given angle, you


should adjust the vectors liftDir and dragDir so they are
aligned with the incoming flow (rotation matrix).
527
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• fieldMinMax functionObject
51 functions
52 { • This functionObject is used to compute the minimum
131 minmaxdomain
and maximum values of the field variables.
132 {
133 type fieldMinMax;
• The output of this functionObject is saved in ascii format
134 in the file fieldMinMax.dat located in the directory
135 functionObjectLibs ("libfieldFunctionObjects.so");
136 postProcessing/minmaxdomain/0
137 enabled true;
138 • Remember, the name of the directory where the output
139 mode component;
140 data is saved is the same as the name of the
141 writeControl timeStep; functionObject (line 131).
142 writeInterval 1;
143
144 log true;
145
146 fields (p U nuTilda nut k omega);
• yPlus functionObject
147 }
148 • This functionObject is used to compute the yPlus field.
149
150 • This functionObject has two outputs, one output saved
151 in the solution directories (1, 2, 3, and so on). You can
152
153 yplus visualize this output using paraview/paraFoam.
154 {
155 type yPlus; • The second output is located in the directory
156 functionObjectLibs ("libfieldFunctionObjects.so");
157 enabled true; postProcessing/yplus/0.
158 log true;
159 writeControl outputTime; • In this file you will find the minimum, maximum and
160 }
average values of yPlus in all patches defined as walls.
211 }
• Remember, the name of the directory where the output
data (descriptive statistics) is saved is the same as the
name of the functionObject (line 153).
528
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• fieldAverage functionObject
51 functions
52 {
• This functionObject is used to compute the average
166 fieldAverage1 values of the field variables.
167 {
168 type fieldAverage; • The output of this functionObject is saved in the time
169 libs ( "libfieldFunctionObjects.so" );
170 writeControl writeTime;
solution directories.

177 fields • In this case, we are computing the field averages of


178 ( velocity (U), pressure (p), and turbulent viscosity (nut).
179 U
180 { • In this functionObject, prime2Mean is the average of the
181 mean on;
182 prime2Mean on;
product of the fluctuations of the variable,
183 base time;
184 }
185
186 p
187 {
188 mean on;
189 prime2Mean on; • In line 206 we add a functionObject definition using an external
190 base time; file.
191 }
192
193 nut
• In this case, the functionObject is located in the directory
194 { system
195 mean on;
196 prime2Mean on; • If you want to run this functionObject online, do not add
197 base time;
198 }
lines 51, 52, and 211 in the file
199 ); externalFunctionObject.
200 }
• To run this functionObject a-posteriori (after the simulation
206 #include "externalFunctionObject"
is over by using the saved solution); add lines 51, 52, and
211 } 211 to the file externalFunctionObject. We explain
how to run functionObjects a posteriori later.
User given file name 529
On-the-fly postprocessing – functionObjects
The externalFunctionObject dictionary

24 probes_online
• probes functionObject
25 {
26 type probes; • This functionObject is used to probe field data at the
27 functionObjectLibs ("libfieldFunctionObjects.so"); given locations.
28 enabled true;
29 writeControl timeStep; • In this case, we are sampling the fields U and p (lines 35-
30 writeInterval 1;
31 39)
32 probeLocations
33 ( • The output of this functionObject is saved in ascii format
34 (1 0 0) in the files p and U located in the directory
35 (2 0 0)
36 (2 0.25 0)
postProcessing/probes_online/0
37 (2 -0.25 0)
38 );
39 • Remember, the name of the directory where the output
40 fields data is saved is the same as the name of the
41 (
42 U
functionObject (line 19).
43 p
44 );
45
46 } • vorticity functionObject
52 vorticity • This functionObject is used to compute the vorticity field.
53 {
54 type vorticity; • The output of this functionObject is saved in the solution
55 functionObjectLibs ("libfieldFunctionObjects.so");
56 enabled true;
directories (1, 2, 3, and so on). You can visualize this
57 log true; output using paraview/paraFoam.
58 writeControl outputTime;
59 }

530
On-the-fly postprocessing – functionObjects
Final remarks on functionObjects
• A functionObject that is very useful, but we did not use in this case:

inlet_massflow
{
type surfaceRegion;
functionObjectLibs ("libfieldFunctionObjects.so");
writeControl timeStep;
writesInterval 1;
log true;
Compute functionObject in a boundary patch
writeFields false;
regionType patch;
name inlet;
operation sum;
Compute functionObject in this boundary patch
fields (phi);
}

• This functionObject is used to computed the mass flow across a boundary patch.
• Remember, the method is conservative so what is going in, is going out (unless you have
source terms).
• So if you want to measure the mass imbalance, setup this function object for each boundary
patch where you have flow entering or going out of the domain.
531
On-the-fly postprocessing – functionObjects
Final remarks on functionObjects

• As you can see, there are many functionObjects implemented in OpenFOAM®.


• We just explained the most common functionObjects.
• You can use the banana method to know all the options available for each entry,
search in the documentation, or read the source code located in the directory
$FOAM_SRC/functionObjects
• In the supplement slides you will find more examples of more complex
functionObjects.
• You will also find a deck of slides with a detailed explanation of advanced paraview
features and some basic instructions for data plotting and analysis using gnuplot.
• Remember, you can also do the same postprocessing using paraview/paraFoam, but
you will only work on the saved fields.
• A great advice before running your simulation, setup all your functionObjects and
gather as much as possible quantitative data.

532
On-the-fly postprocessing – functionObjects
Running functionObjects a-posteriori
• Sometimes it can happen that you forget to use a functionObject or you want to execute a
functionObject a-posteriori (when the simulation is over).
• The solution to this problem is to use the solver with the option -postProcess. This will only
compute the new functionObject, it will not rerun the simulation.
• For instance, let us say that you forgot to use a given functionObject. Open the dictionary
controlDict, add the new functionObject, and type in the terminal,
• $> name_of_the_solver -postProcess –dict dictionary_location

• You also have the option of adding the new functionObject in an external file. If you chose this
option, do not forget to add the functionOption within the function sub-dictionary block:

function
{
//functionObject definitions here
};

• By proceeding in this way you do not need to rerun the simulation, you just compute the new
functionObject.
533
On-the-fly postprocessing – functionObjects
Running functionObjects a-posteriori
• In the directory system, you will find the following functionObject external
dictionaries: externalFunctionObject
• To run this functionObject a-posteriori, type in the terminal:

1. $> simpleFoam -postProcess -dict system/externalFunctionObject –noZero

2. $> simpleFoam -postProcess -dict system/externalFunctionObject –time 500:2000

3. $> simpleFoam -postProcess -dict system/functionObject3 –latestTime

• In step 1, we are reading the dictionary system/externalFunctionObject and


we are doing the computation for all the saved solutions, except time zero.
• In step 2, we are reading the dictionary system/externalFunctionObject and
we are doing the computation for the time range 500 to 2000
• In step 3, we are reading the dictionary functionObject3 and we are doing the
computation only for he latest saved solution.
• If you do not give any time manipulator, the computation will be carried out on every
saved solution. 534
On-the-fly postprocessing – functionObjects
Exercises
• Where is located the source code of the functionObjects?
• Try to run in parallel? Do all functionObjects work properly?
• Compute the Courant number using functionObjects.
• Compute the total pressure and velocity gradient using functionObjects (on-the-fly and a-posteriori).
• Sample data (points, lines and surfaces) using functionObjects (a-posteriori).
• Is it possible to do system calls using functionObjects? If so what functionObject will you use and how do
you use it? Setup a sample case.
• Is it possible to update dictionaries using functionObjects? If so what functionObjects will you use and how
do you use it? Setup a sample case.
• What are the compulsory entries of the functionObjects?

535
Roadmap

1. On-the-fly postprocessing – functionObjects and the


postProcess utility
2. Sampling with the postProcess utility
3. Field manipulation
4. Data conversion

536
Sampling with the postProcess utility
• OpenFOAM® provides the postProcess utility to sample field data for plotting.
• The sampling parameters are specified in a dictionary located in the case system
directory.
• You can give any name to the input dictionary, hereafter we are going to name them
sampleDict (to sample along a line) and probesDict (to sample in a set of
probes).
• During the sampling, and inside the case directory, a new directory named
postProcessing will be created. In this directory, the sampled values are stored in
a sub-directory with the name of the input dictionary, in this case, sampleDict and
probesDict.
• This utility can sample points, lines, and surfaces.
• Data can be written in a range of formats including well-known plotting packages
such as: grace/xmgr, gnuplot and jPlot.
• The sampling can be executed by running the utility postProcess in the case
directory and according to the application syntax.
• A final word, this utility does not do the sampling while the solver is running. It does
the sampling after you finish the simulation.
537
Sampling with the postProcess utility
• To do sampling, we will use the solution from the previous case.
• If you do not have the solution, follow the instructions given in the previous slides.
• Hereafter, we will sample along a line and in a few probe locations, as illustrated in
the figure below.

538
Sampling with the postProcess utility
Running the case

• Let us do the sampling,

1. $> postProcess -func sampleDict –time 2000


2. $> postProcess -func probesDict –time 2000

• In step 1, we do some sampling using the dictionary sampleDict. We also do the


sampling only for time 2000
• In step 2, we do some sampling using the dictionary probesDict. We also do the
sampling only for time 2000.
• Remember, you can use different time manipulators.
• If you do not give any time manipulator option, the sampling will be computed for all
saved solutions (including time directory 0).

539
Sampling with the postProcess utility
The sampleDict and probesDict dictionaries
• These dictionaries are located in the directory system.
• In this case, the sampleDict dictionary is used to sample along a line. This file
contains several entries to be set according to the user needs. The following entries
can be set,
• The choice of the interpolationScheme.
• The format of the line data output.
• The format of the surface data output.
• The fields to be sample.
• The sub-dictionaries that controls each sampling operation.
• In these sub-dictionaries you can set the name, type and geometrical
information of the sampling operation.
• In this case, the probesDict is used to sample in a set of points. This file contains
several entries to be set according to the user needs. The following entries,
• The fields to be sample.
• Location of the probes.
• The following functionObjects type can be used to do sampling: patchProbes,
probes, sets, or surfaces.
540
Sampling with the postProcess utility
The sampleDict dictionary

17 type sets; Sample sets (points and lines).

18 libs ("libsampling.so"); Use sampling library

22 interpolationScheme cellPoint; Interpolation method at the solution level (location of the


interpolation points).
25 setFormat raw;
Format of the output file, raw format is a generic format that can be
27 surfaceFormat raw; read by many applications. The file is human readable (ascii
30 fields
format).
31 (
32 U Fields to sample. No need to mention that they must exist.
33 wallShearStress
34 );

36 sets Sub-dictionary where we define all sampling objects (sets)


37 (

39 profile0 Name of the set and output file


40 {

42 type lineCellFace; Interpolation method (from the solution to the line).


44 axis distance;
Sample method definition

46 start ( 0.75150 0.04767 0 );


47 end ( 0.76168 0.14715 0 ); Location of the sample line. Definition if the start and end point
48 }

Note:
66 );
Use the banana method to know all the options available. 541
Sampling with the postProcess utility
The sampleDict dictionary

17 type sets; • Remember, the sampled data is always saved in the


directory postProcessing
18 libs ("libsampling.so");
• Then, in the sub-directory sampleDict (whose name
22 interpolationScheme cellPoint;
corresponds to the name of the input file), you will find the
data sampled in a directory corresponding to the sampled
25 setFormat raw; time.
27 surfaceFormat raw; • For example, in this case you fill find the data in the
30 fields directory postProcessing/sampleDict/2000
31 (
32 U • Then, in the file profile0_U_wallShearStress.xy
33 wallShearStress
34 ); you will find the data.
36
37
sets
(
• The name of the output file corresponds to the name of the
Name of sampled set, appended by the name of the sampled fields.
39 profile0
40 { sampled set • Different files will be created for tensor, vector and scalar
42 type lineCellFace; fields.
44 axis distance;
• Feel free to open the output files using your favorite text
editor.
46 start ( 0.75150 0.04767 0 );
47 end ( 0.76168 0.14715 0 );

48 }

66 );
542
Sampling with the postProcess utility
The probesDict dictionary

17 type probes; Sample points.

20 (
21 p
22 U Fields to sample. No need to mention that they must exist.
23 );

27 probeLocations
28 (
29 (1.0 0 0)
30 (1.25 0 0)
31 (1.5 0 0)
32 (1.75 0 0)
33 (2.0 0 0) Location of the points.
34 (2.0 -.25 0)
35 (2.0 -.5 0)
36 (2.0 .25 0)
37 (2.0 .5 0)
38 );

Note:
Use the banana method to know all the options available. 543
Sampling with the postProcess utility
The probesDict dictionary

17 type probes; • Remember, the sampled data is always saved in the


directory postProcessing
• Then, in the sub-directory probesDict (whose name
20 (
corresponds to the name of the input file), you will find the
21 p data sampled in a directory corresponding to the sampled
22 U
23 ); time.
• For example, in this case you fill find the data in the
directory postProcessing/probesDict/2000
27
28
probeLocations
(
• Then, inside this directory, you will find several files
29 (1.0 0 0) containing the sampled data.
30 (1.25 0 0)
31
32
(1.5 0 0)
(1.75 0 0)
• The name of the output file corresponds to the name of the
33 (2.0 0 0) sampled fields, in this case, U and p.
34 (2.0 -.25 0)
35
36
(2.0 -.5 0)
(2.0 .25 0)
• Feel free to open the output files using your favorite text
37 (2.0 .5 0) editor.
38 );

544
Sampling with the postProcess utility
The output files – functionObject type sets or surfaces

• The output format of the point sampling (cloud) is as follows:

Scalars

#POINT_COORDINATES (X Y Z) SCALAR_VALUE
0 0 0.05 13.310995
0 0 0.1 19.293817

Vectors

#POINT_COORDINATES (X Y Z) VECTOR_COMPONENTS (X Y Z)
0 0 0.05 0 0 2.807395
0 0 0.1 0 0 2.826176

545
Sampling with the postProcess utility
The output files – functionObject type sets or surfaces

• The output format of the line sampling is as follows:

Scalars

#AXIS_COORDINATE SCALAR_VALUE
0 18.594038
0.0015 18.249091

Vectors

#AXIS_COORDINATE VECTOR_COMPONENTS (X Y Z)
0 0 0 1.6152966
0.0015 0 0 1.8067536

546
Sampling with the postProcess utility
The output files – functionObject type sets or surfaces

• The output format of the surface sampling is as follows:

Scalars

#POINT_COORDINATES (X Y Z) SCALAR_VALUE
0 0 0.05 13.310995
0 0 0.1 19.293817

Vectors

#POINT_COORDINATES (X Y Z) VECTOR_COMPONENTS (X Y Z)
0 0 0.05 0 0 2.807395
0 0 0.1 0 0 2.826176

547
Sampling with the postProcess utility
The output files – functionObject type probes

• The output format of the probing is as follows:

Scalars

# Probe 0 (0 0 0.025)
# Probe 1 (0 0 0.05)
# Probe 2 (0 0 0.075)
# Probe 3 (0 0 0.1)
# Probe 0 1 2 3
# Time
0 0 0 0 0
0.005 19.1928 16.9497 14.2011 11.7580
0.01 16.6152 14.5294 12.1733 10.0789


548
Sampling with the postProcess utility
The output files – functionObject type probes

• The output format of the probing is as follows:

Vectors

# Probe 0 (0 0 0.025)
# Probe 1 (0 0 0.05)
# Probe 2 (0 0 0.075)
# Probe 3 (0 0 0.1)
# Probe 0 1 2 3
# Time
0 (0 0 0) (0 0 0) (0 0 0) (0 0 0)
0.005 (0 0 2.1927) (0 0 2.1927) (0 0 2.1927) (0 0 2.1927)
0.01 (0 0 2.5334) (0 0 2.5334) (0 0 2.5334) (0 0 2.5334)


549
Sampling with the postProcess utility
Exercises
• Where is located the source code of the utility postProcess?
• Try to do the sampling in parallel? Does it run? What about the output file?
• How many options are there available to do sampling in a line?
• Do point, line, and surface sampling using paraFoam/ParaView and compare with the output of the
postProcess utility. Do you get the same results?
• Compute the descriptive statistics of each column of the output files using gnuplot. Be careful with the
parentheses of the vector files.
(Hint: you can use sed within gnuplot)

550
Roadmap

1. On-the-fly postprocessing – functionObjects and the


postProcess utility
2. Sampling with the postProcess utility
3. Field manipulation
4. Data conversion

551
Field manipulation
• Hereafter we are going to deal with field manipulation
• Field manipulation means modifying a field variable or deriving a new field
variable using the primitive variables computed during the solution stage.
• We will do the post-processing using the command line interface (CLI), or
non-GUI mode.
• The utility postProcess can be used as a single application, e.g.,
• $> postProcess –func vorticity

• Or it can be used with a solver using the option –postprocess, e.g.,


• $> simpleFoam -postprocess –func vorticity

• Running the solver with the option –postprocess will only execute the
post-processing and it will let you access data available on the database for
the particular solver (such as physical properties or turbulence model).

552
Field manipulation
• To get a list of what can be computed using the postProcess utility, type in
the terminal:
• $> postProcess –list

• The utility postProcess can take many options. To get more information
on how to use the utility, type in the terminal:
• $> postProcess –help
• $> simpleFoam -postProcess –help

• The options of the solver using the –postProcess flag are the same as the
options of the utility postProcess.
• In the sub-directory $FOAM_UTILITIES/postProcessing/postProcess
you will find the utility postProcess.
• In the directory $FOAM_SRC/functionObjects, you will find the source
code of the objects that can be used to compute a new field.
553
Field manipulation

• We will now do some field manipulation using the cylinder case.


• For this we will use the supersonic wedge tutorial located in the
directory:

$PTOFC/101postprocessing/supersonic_wedge/

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.

554
Field manipulation
After computing the solution, we can compute derived fields (e.g., Mach number, density,
Courant number, vorticity, and so on), using the primitive fields (U, p, T)
Mach number Total pressure

Divergence of U Divergence of density gradient (numerical shadowgraph)

555
Field manipulation
What are we going to do?
• We will use this case to introduce the postProcess utility for field manipulation.
• We will also show how to run the solver with the option -postProcess. This will let us do only
the post-processing after the solution has been computed, and it will let us access the database
of the solver.
• To find the numerical solution we will use the solver rhoPimpleFoam.
• rhoPimpleFoam is a transient solver for laminar or turbulent flow of compressible gas.

Running the case


• Let us run this case using the automatic script, in the terminal type,

1. $> sh run_solver.sh
2. $> paraFoam

• Fell free to open the file run_solver.sh to know all the steps.

556
Field manipulation
• After finding the solution, we can compute the new field variables using the
primitive variables computed during the solution stage. In the terminal type:

1. $> rhoPimpleFoam -postProcess -func MachNo

2. $> rhoPimpleFoam -postProcess -func CourantNo

3. $> rhoPimpleFoam -postProcess -func wallShearStress

4. $> rhoPimpleFoam -postProcess -func 'writeObjects(rho)' -time 0

5. $> rhoPimpleFoam -postProcess -func vorticity

6. $> postProcess -func vorticity

7. $> rhoPimpleFoam -postProcess -dict system/externalFunctionObject -latestTime

• If the new field variables require information of the simulation database


(fluxes, turbulence properties, transport properties), you will need to process
as in steps 1-5.
• If the new field variable only requires to use a variable that already exist in
the solution folder, you can proceed as in step 6.
557
Field manipulation
• In step 1 we compute the Mach number. To compute this value, the postProcess
utility needs to access the thermophysicalProperties dictionary.
• In step 2 we compute the Courant number. To compute this value, the postProcess
utility needs to access the face fluxes (phi).
• In step 3 we compute the wall shear stress. To compute this value, the postProcess
utility needs to access the transport and turbulence properties.
• In step 4 we compute the density (rho) for the initial time (time = 0). To compute this
value, the postProcess utility needs to access the simulation database.
• In steps 5 and 6 we compute the vorticity field, this field is derived from the velocity
field. The postProcess utility does not need to access any particular solver
information. Both options will give the same output.
• In step 7 we use an external file to compute the derived fields. In this case we are
computing the density gradient (grad(rho)) and the divergence of the density gradient
(div(grad(rho)).
• Remember, in order to compute the derived field div(grad(rho), you need to compute
first grad(rho).

558
Field manipulation
• After finding the solution, we can compute new field variables using the primitive
variables computed during the solution stage. In the terminal type:

1. $> postProcess -func 'grad(U)'


2. $> postProcess -func 'components(U)'
3. $> postProcess -func 'mag(U)'
4. $> postProcess -func 'magSqr(U)'
5. $> postProcess -func 'totalPressureCompressible(rho,U,p)' -noZero
6. $> postProcess -func 'div(U)' -time 500:1000
7. $> postProcess -func 'mag(grad(U))' -latestTime

• We can also use the utility postProcess to compute the average and integral of a
specified field over a patch. In the terminal type:

8. $> postProcess -func 'patchAverage(name=inlet,p)' –latestTime


9. $> postProcess -func 'patchAverage(name=outlet,U)' –latestTime
10. $> postProcess -func 'patchIntegrate(name=inlet,p)' –latestTime
11. $> postProcess -func 'patchIntegrate(name=outlet,U)' -latestTime
559
Field manipulation
• In steps 1-11, all the fields are derived from pre-existing fields. The postProcess utility does
not need to access any particular solver information.
• In step 1 we compute the gradient of the velocity vector U. The field is saved as grad(U).
• In step 2 we compute the components of the velocity vector U. The components are saved as
Ux, Uy and Uz.
• In step 3 we compute the magnitude of the velocity vector U. The output is saved as mag(U).
• In step 4 we compute the magnitude squared of the velocity vector U. The output is saved as
magSqr(U).
• In step 5 we compute the total pressure. The output is saved as total(p). The option –noZero
means do not compute the value for time zero.
• In step 6 we compute the divergence of the velocity vector U. The output is saved as div(U).
You will need to define how to interpolate div(U) in the fvSchemes dictionary. The option –time
500:1000 means save the values between the given range (500-1000).
• In step 7 we compute the magnitude of the gradient of the velocity vector U. The output is
saved as mag(Grad(U)). The option –latestTime will compute the value only for the latest
saved solution.
• In step 8 we compute the average of p over the patch inlet.
• In step 9 we compute the average of U over the patch outlet.
• In step 10 we compute the integral of p over the patch inlet.
• In step 11 we compute the integral of U over the patch outlet.

560
Roadmap

1. On-the-fly postprocessing – functionObjects and the


postProcess utility
2. Sampling and probing with the postProcess utility
3. Field manipulation
4. Data conversion

561
Data conversion
• OpenFOAM® gives users a lot of flexibility when it comes to scientific visualization.
• You are not obliged to use OpenFOAM® visualization tools (paraFoam or paraview).
• You can convert the solution obtained with OpenFOAM® to many third-party formats
by using OpenFOAM® data conversion utilities.
• If you are looking for a specific format and it is not supported, you can write your own
conversion tool.
• In the directory $FOAM_UTILITIES/postProcessing/dataConversion, you will
find the source code of the following data conversion utilities:

• foamDataToFluent • foamToTecplot360
• foamToEnsight • foamToTetDualMesh
• foamToEnsightParts • foamToVTK
• foamToGMV • smapToFoam

• To get more information on how to use a data conversion utility, you can read the
source code or type in the terminal:
• $> name_of_data_conversion_utility -help
562
Data conversion
ASCII ↔ Binary conversion
• Another utility that might come in handy, specially when dealing with
large meshes is foamFormatConvert.
17
18
application icoFoam; • This utility converts the mesh and field variables into ascii or binary
19 startFrom startTime; format.
20
21 startTime 0; • In order to manually edit the boundary file and the field variables
22
23 stopAt endTime; dictionaries (initial and boundary conditions), they must be in ascii
24
25 endTime 50; format.
26
27 deltaT 0.01; • After editing these files, we can convert them into binary format.
28
29
30
writeControl runTime;
• Working in binary format can significantly reduce data parsing and
31 writeInterval 1; dimension of the files (specially for large meshes).
32
33
34
purgeWrite 0;
• The drawback is that the files are not human readable anymore.
35 writeFormat binary;
36 • To convert ascii files into binary files, just type in the terminal:
37 writePrecision 8;
38 • $> foamFormatConvert
39 writeCompression off;
40
41 timeFormat general; • Remember you will need to set the keyword writeFormat to binary
42
43 timePrecision 6;
in the controlDict dictionary.
44
45 runTimeModifiable true; • In the same way, if you want to convert from binary to ascii, set the
keyword writeFormat to ascii in the controlDict dictionary and
type in the terminal:
• $> foamFormatConvert
563
Module 6
Finite volume method overview

564
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

565
Finite Volume Method: A Crash introduction
• This a brief introduction to the FVM to illustrate some basic concepts.
• There is much more under the hood.
• We will use the general transport equation as the starting point to explain the FVM,

• Starting from this equation, we can write down the Navier-Stokes equations (NSE).
• So everything we are going to address also applies to the NSE or any set of
equations that can be derived form the general transport equation.

566
Finite Volume Method: A Crash introduction
• This a brief introduction to the FVM to illustrate some basic concepts.
• There is much more under the hood.
• We will use the general transport equation as the starting point to explain the FVM,

Problem statement
• Find the approximate solution to the general transport equation for the transported
quantity in a given domain, with given boundary conditions (BC) and initial
conditions (IC).
• It is an initial boundary value problem (IBVP).
• This is a second order equation. Therefore, for good accuracy, it is necessary that
the order of the discretization is equal or higher than the order of the equation that is
being discretized (in space and time).
567
Finite Volume Method: A Crash introduction
• Let us use the general transport equation as the starting point to explain the FVM,

• Hereafter we are going to assume that the discretization practice is at least second
order accurate in space and time.
• As consequence of the previous requirement, all dependent variables are assumed
to vary linearly around a point P in space and instant t in time,

Profile assumptions using Taylor expansions around point P (in space) and point t (in time)

568
Finite Volume Method: A Crash introduction
Domain discretization – Mesh information and variable arrangement
• Domain discretization (or mesh generation), consist in dividing the solution domain into a finite
number of arbitrary control volumes or cells, such as the one illustrated below.
• Inside each control volume the solution is sought.
• The control volumes can be of any shape (e.g., tetrahedrons, hexes, prisms, pyramids,
dodecahedrons, and so on). The only requirement is that the faces that made up the control
volume need to be planar.
• We also know which control volumes are internal and which control volumes lie on the
boundaries.

569
Finite Volume Method: A Crash introduction
Domain discretization – Mesh information and variable arrangement
• In the control volume illustrated, the centroid P and face center f are known.
• We also assume that the values of all variables are computed and stored in the centroid of the
control volume Vp and that they are represented by a piecewise constant profile (the mean
value),

• This is known as the cell centered collocated arrangement.


• All approximations used so far are at least second order accurate.

570
Finite Volume Method: A Crash introduction
Domain discretization – Mesh information and variable arrangement
• Putting all together, it is a lot geometrical information that we need to track.
• A lot of overhead goes into the data book-keeping.
• At the end of the day, the FVM simply consist in conservation of the transported quantities and
interpolating information from cell centers to face centers.

Summary:
• The control volume has a volume V and is constructed
around point P, which is the centroid of the control volume.
Therefore the notation .
• The vector from the centroid P of to the centroid N of the
neighboring control volume is named d.
• We also know all neighbors of the control volume
• The control volume faces are labeled f, which also denotes the
face center.
• The location where the vector d intersects a face is .
• The face area vector point outwards from the control
volume, is located at the face centroid, is normal to the face and
has a magnitude equal to the area of the face.
• The vector from the centroid P to the face center f is named Pf.
571
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Let us recall the Gauss or Divergence theorem,

where is a closed surface bounding the control volume and represents an


infinitesimal surface element are with associated normal pointing outwards of the
surface , and

• The Gauss or Divergence theorem simply states that


the outward flux of a vector field through a closed
surface is equal to the volume integral of the divergence
over the region inside the surface.
• This theorem is fundamental in the FVM.
• It is used to convert the volume integrals appearing in
the governing equations into surface integrals.

572
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Let us use the Gauss theorem to convert the volume integrals into surface integrals,

• At this point the problem reduces to interpolating somehow the cell centered values (known
quantities) to the face centers.
• That is, we need to compute the gradient terms, source terms, and convective and diffusive
fluxes across the faces. 573
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Integrating in space each term of the general transport equation and by using Gauss theorem,
yields to the following discrete equations for each term

Convective term:

By using Gauss theorem we convert volume where we have approximated the integrant by means of
integrals into surface integrals the mid point rule, which is second order accurate

Gauss theorem:

574
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Integrating in space each term of the general transport equation and by using Gauss theorem,
yields to the following discrete equations for each term

Diffusive term:

By using Gauss theorem we convert volume where we have approximated the integrant by means of
integrals into surface integrals the mid point rule, which is second order accurate

Gauss theorem:

575
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Integrating in space each term of the general transport equation and by using Gauss theorem,
yields to the following discrete equations for each term

Gradient term:

where we have approximated the centroid gradients by using the Gauss theorem.
This method is second order accurate and is known as Gauss cell-based.

Gauss theorem:

Note:
• There are more methods for gradients
computation, e.g., least squares, node-
based reconstruction, and so on.
• As there is some algebra involved, we
do not provide the demonstration.
576
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Integrating in space each term of the general transport equation and by using Gauss theorem,
yields to the following discrete equations for each term

Source term:

This approximation is exact if is either constant or varies linearly within the control volume; otherwise is
second order accurate.
Sc is the constant part of the source term and Sp is the non-linear part

Gauss theorem:

577
Finite Volume Method: A Crash introduction
Gauss theorem and face fluxes computation
• Using the previous equations to evaluate the general transport equation over all the control
volumes, we obtain the following semi-discrete equation

where is the convective flux and is the diffusive flux.

• And recall that all variables are computed and stored at the centroid of the control volumes.

• The face values appearing in the convective and diffusive fluxes have to be computed by
some form of interpolation from the centroid values of the control volumes at both sides of
face f.

578
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be computed
as follows,

• This type of interpolation scheme is known as linear interpolation or central differencing and it is
second order accurate.
• However, it may generate oscillatory solutions (unbounded solutions).
579
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be computed
as follows,

• This type of interpolation scheme is known as upwind differencing and it is first order accurate.
• This scheme is bounded (non-oscillatory) and diffusive.

580
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be computed
as follows,

• This type of interpolation scheme is known as second order upwind differencing (SOU), linear
upwind differencing (LUD) or Beam-Warming (BW), and it is second order accurate.
• For highly convective flows or in the presence of strong gradients, this scheme is oscillatory
(unbounded).
581
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes
• To prevent oscillations in the SOU, we add a gradient or slope limiter function .

• When the limiter detects strong gradients or changes in slope, it switches locally to low
resolution (upwind).
• The concept of the limiter function is based on monitoring the ratio of successive
gradients, e.g.,

• By adding a well-designed limiter function , we get a high resolution (second order


accurate) and bounded scheme (HR). This is a TVD scheme.

582
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes

• A TVD scheme, is a scheme that does not create


new local undershoots and/or overshoots in the
solution or amplify existing extremes.
• In CFD we want stable, non-oscillatory, bounded,
high order schemes.
• The Sweby diagram (Sweby, 1984), gives the
necessary and sufficient conditions for a scheme to
be TVD.
• In the figure, the shaded area represents the
admissible TVD region. However, not all limiter
functions are second order.
• High resolution schemes falls in the blue area and
low resolution schemes falls in the grey area.
• The drawback of the limiters is that they reduce the
accuracy of the scheme locally to first order (low
resolution scheme), when r < 0 (sharp gradient,
opposite slopes or zero gradient). However, this is
justified when it serves to suppress oscillations.
• No particular limiter has been found to work well for UD = upwind
SOU = second order upwind
all problems, and a particular choice is usually made CD = central differencing
on a trial and error basis. D = downwind

583
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes
• Let us see how the upwind, linear upwind, linear, and Minmod TVD schemes behave in a
numerical schemes killer test case:
• The oblique double step profile in a uniform vector field (pure convection).
• Even if this problem seems to be easy, from the numerical point of view is difficult to resolve due
to the strong discontinuities.
• This problem has an exact solution.

584
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes
• Qualitative comparison of the upwind, linear upwind, linear, and Minmod TVD schemes

Upwind – 1st order Linear – 2nd order Linear Upwind – 2nd order
Very bounded but too Diffusive Very accurate but too oscillatory Bounded and accurate

SuperBee – TVD high resolution Minmod – TVD high resolution vanLeer – TVD high resolution
Compressive Diffusive Smooth

585
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes
• Quantitative comparison of the upwind, linear upwind, linear, and Minmod TVD schemes

586
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Unstructured meshes
• In the previous explanation, we assumed a line structure (figure A). That is, the cell centers PP,
P, and N are all aligned.
• In unstructured meshes (which are often used in industrial cases), most of the times the cell
center PP is not aligned with the vector connecting cells P and N (figure B). Therefore,
extending the previous formulations to these meshes is not very straightforward.
• Higher-order schemes for unstructured meshes are an area of active research, and new ideas
continue to emerge.

587
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Unstructured meshes
• A simple way around this problem is to redefine
higher-order schemes in terms of gradients at the
control volume P.
• For example, using the gradient of the cells, we can
compute the face values as follows,

Upwind →

Central difference →

Second order upwind differencing →

• Notice that in this new formulation the cell PP does not appear anymore.
• The problem now turns in the accurate evaluation of the gradients at the cell and face centers.
• For example, the gradients at the cell centers can be computed using the Gauss method, and
then interpolated to the face centers.
• At this point, we are only missing the reconstruction of the cell center gradients at the face
centers, this is explained latter. 588
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Unstructured meshes
• In unstructured meshes, as often the value of the node PP (of NN) is not available or
straightforward to compute, the ratio of successive gradients r can be computed as follows [1],

U → Upwind
D → Downwind

• As you can see, the value of r depends on the flow direction.


• There are many ways to compute r. This is an area of active research

Reference:
[1] Darwish, M. S., Moukalled, F., “TVD schemes for unstructured grids” 589
Finite Volume Method: A Crash introduction
Gradients computation at cell centers
• There are many methods for the computation of the cell centered gradients, e.g., least squares,
Gauss cell-based, Gauss node-based, and so on.
• Using the Gauss cell-based method, the cell centered gradients can be computed as follows,

• This approximation is second order accurate given that the mesh quality is acceptable, and the
volume of the cell is finite.
• In general, the least squares method tends to be more accurate.

590
Finite Volume Method: A Crash introduction
Gradients reconstruction at face centers
• Face gradients arise from the discretization process of the convective and diffusive terms.
• One way to reconstruct the face gradient , is by using weighted interpolation of the cell
centered quantities and .
• Mesh non-orthogonality and skewness introduce errors when approximating the face gradients,
so corrections need to be added.
• This is an iterative process, where we compute successively better approximations to the
gradients starting from an initial approximation.

where

Face gradient

591
Finite Volume Method: A Crash introduction
Interpolation of diffusive fluxes in an orthogonal mesh
• By looking the figure below, the face values • By looking the figure below, the face values
appearing in the diffusive flux in an orthogonal appearing in the diffusive flux in a non-orthogonal
mesh can be computed as follows, mesh (20°) can be computed as follows,

• This is a central difference approximation of the • This type of approximation is second order accurate
first order derivative. This type of but involves a larger truncation error. It also uses a
approximation is second order accurate. larger numerical stencil, which make it less stable.

• Remember, the non-orthogonal angle is the angle between the vector S and the vector d
592
Finite Volume Method: A Crash introduction
Correction of diffusive fluxes in a non-orthogonal mesh
• By looking the figures below, the face values appearing in the diffusive flux in a non-orthogonal
mesh ( ) can be computed as follows.
• Using the over-relaxed approach, the diffusive fluxes can be corrected as follow,

Over-relaxed approach

593
Finite Volume Method: A Crash introduction
Mesh induced errors
• In order to maintain second order accuracy, and to avoid unboundedness, we need to correct
non-orthogonality and skewness errors.
• The ideal case is to have an orthogonal and non skew mesh, but this is the exception rather
than the rule.

Orthogonal and non skew mesh Non-orthogonal and non skew mesh

Orthogonal and skew mesh Non-orthogonal and skew mesh 594


Finite Volume Method: A Crash introduction
Temporal discretization
• Using the previous equations to evaluate the general transport equation over all the control
volumes, we obtain the following semi-discrete equation,

where is the convective flux and is the diffusive flux.

• After spatial discretization, we can proceed with the temporal discretization. By proceeding
in this way we are using the Method of Lines (MOL).
• The main advantage of the MOL method, is that it allows us to select numerical
approximations of different accuracy for the spatial and temporal terms. Each term can be
treated differently to yield to different accuracies.

595
Finite Volume Method: A Crash introduction
Temporal discretization
• Now, we evaluate in time the semi-discrete general transport equation

• At this stage, we can use any time discretization scheme, e.g., Crank-Nicolson, euler implicit,
forward euler, backward differencing, adams-bashforth, adams-moulton.
• It should be noted that the order of the temporal discretization of the transient term does not
need to be the same as the order of the discretization of the spatial terms.
• Each term can be treated differently to yield different accuracies. As long as the individual terms
are at least second order accurate, the overall accuracy will also be second order.

596
Finite Volume Method: A Crash introduction
Linear system solution
• After spatial and temporal discretization and by using equation

in every control volume of the domain, a system of linear algebraic equations for the
transported quantity is assembled,

• This system can be solved by using any iterative or direct method. 597
Finite Volume Method: A Crash introduction
So, what does OpenFOAM® do?
• It simply discretize in space and time the governing equations in arbitrary polyhedral control
volumes over the whole domain.
• Assembling in this way a large set of linear discrete algebraic equations (DAE), and then it solves
this system of DAE to find the solution of the transported quantities.
• Therefore, we need to give to OpenFOAM® the following information:
• Discretization of the solution domain or the mesh.
• This information is contained in the directory constant/polyMesh
• Boundary conditions and initials conditions.
• This information is contained in the directory 0
• Physical properties such as density, gravity, diffusion coefficient, viscosity, etc.
• This information is contained in the directory constant
• Physics involve, such as turbulence modeling, mass transfer, source terms, dynamic
meshes, multiphase models, combustion models, etc.
• This information is contained in the directories constant and/or system

598
Finite Volume Method: A Crash introduction
So, what does OpenFOAM® do?
• Therefore, we need to give to OpenFOAM® the following information:
• How to discretize in space each term of the governing equations (diffusive, convective,
gradient and source terms).
• This information is set in the system/fvSchemes dictionary.
• How to discretize in time the obtained semi-discrete governing equations.
• This information is set in the system/fvSchemes dictionary.
• How to solve the linear system of discrete algebraic equations (crunch numbers).
• This information is set in the system/fvSolution dictionary.
• Set runtime parameters and general instructions on how to run the case (such as time step,
maximum CFL number, solution saving frequency, and so on).
• This information is set in the system/controlDict dictionary.
• Additionally, we may set sampling and monitors for post-processing (functionObjects).
• This information is set in the system/fvSchemes dictionary or in the specific
sampling dictionaries located in the directory system/

599
Finite Volume Method: A Crash introduction
Where do we set all the discretization schemes in OpenFOAM®?
ddtSchemes • The fvSchemes dictionary contains the information related to
{ the discretization schemes for the different terms appearing in
default backward;
}
the governing equations.

gradSchemes
• The discretization schemes can be chosen in a term-by-term
{ basis.
default Gauss linear;
grad(p) Gauss linear; • The keyword ddtSchemes refers to the time discretization.
}
• The keyword gradSchemes refers to the gradient term
divSchemes discretization.
{
default none; • The keyword divSchemes refers to the convective term
div(phi,U) Gauss linear; discretization.
}
• The keyword laplacianSchemes refers to the Laplacian term
laplacianSchemes
{
discretization.
default Gauss linear orthogonal; • The keyword interpolationSchemes refers to the method used
}
to interpolate values from cell centers to face centers. It is
interpolationSchemes unlikely that you will need to use something different from
{ linear.
default linear;
} • The keyword snGradSchemes refers to the discretization of
snGradSchemes
the surface normal gradients evaluated at the faces.
{
default orthogonal;
• Remember, if you want to know the options available for each
} keyword you can use the banana method.
600
Finite Volume Method: A Crash introduction
Time discretization schemes
• There are many time discretization schemes available in OpenFOAM®.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/ddtSchemes

• These are the time discretization schemes that you will use most of the times:
• steadyState: for steady state simulations (implicit/explicit).
• Euler: time dependent first order (implicit/explicit), bounded.
• backward: time dependent second order (implicit), bounded/unbounded.
• CrankNicolson: time dependent second order (implicit), bounded/unbounded.

• First order methods are bounded and stable, but diffusive.


• Second order methods are accurate, but they might become oscillatory.
• At the end of the day, we always want a second order accurate solution.
• If you keep the CFL less than one when using the Euler method, numerical diffusion is not that
much (however, we advise you to do your own benchmarking).

601
Finite Volume Method: A Crash introduction
Time discretization schemes
• The Crank-Nicolson method as it is implemented in OpenFOAM®, uses a blending factor.

ddtSchemes
{
default CrankNicolson ;
}

• Setting to 0 is equivalent to running a pure Euler scheme (robust but first order accurate).
• By setting the blending factor equal to 1 you use a pure Crank-Nicolson (accurate but
oscillatory, formally second order accurate).
• If you set the blending factor to 0.5, you get something in between first order accuracy and
second order accuracy, or in other words, you get the best of both worlds.
• A blending factor of 0.7-0.9 is safe to use for most applications (stable and accurate).

602
Finite Volume Method: A Crash introduction
Convective terms discretization schemes
• There are many convective terms discretization schemes available in OpenFOAM® (more than
50 last time we checked).
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/interpolation/surfaceInterpolation

• These are the convective discretization schemes that you will use most of the times:
• upwind: first order accurate.
• linearUpwind: second order accurate, bounded.
• linear: second order accurate, unbounded.
• A good TVD scheme (vanLeer or Minmod): TVD, second order accurate, bounded.
• limitedLinear: second order accurate, unbounded, but more stable than pure linear.
Recommended for LES simulations (kind of similar to the Fromm method).
• LUST: blended 75% linear and 25% linearUpwind scheme

• First order methods are bounded and stable but diffusive.


• Second order methods are accurate, but they might become oscillatory.
• At the end of the day, we always want a second order accurate solution. 603
Finite Volume Method: A Crash introduction
Convective terms discretization schemes
• When you use linearUpwind for div(phi,U), you need to tell OpenFOAM® how to compute the
velocity gradient or grad(U):

gradSchemes
{
grad(U) cellMDLimited Gauss linear 1.0;
}

divSchemes
{
div(phi,U) Gauss linearUpwind grad(U);
}

• Same applies for every transported quantity (e.g. k, epsilon, omega, T)

604
Finite Volume Method: A Crash introduction
Gradient terms discretization schemes
• There are many gradient discretization schemes available in OpenFOAM®.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/gradSchemes
• These are the gradient discretization schemes that you will use most of the times:
• Gauss linear (cell-based method)
• Gauss pointLinear (node-based method; more accurate than the cell-based method)
• leastSquares

• To avoid overshoots or undershoots when computing the gradients, you can use gradient
limiters.
• Gradient limiters increase the stability of the method but add diffusion due to clipping.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/gradSchemes/limitedGradSchemes
• These are the most important gradient limiter schemes available in OpenFOAM®:
• cellLimited, cellMDLimited, faceLimited, faceMDLimited
• All of the gradient discretization schemes are at least second order accurate.
605
Finite Volume Method: A Crash introduction
Gradient terms discretization schemes
• These are the gradient limiter schemes available in OpenFOAM®:

cellMDLimited Less diffusive


Note: for smooth field variation, cell
cellLimited limiting may provide less numerical
dissipation on meshes with skewed
faceMDLimited
cells
faceLimited
More diffusive

• Cell limiters will limit cell-to-cell values.


• Face limiters will limit face-to-cell values.
• The multi-directional (dimensional) limiters (cellMDLimited and faceMDLimited), will apply the
limiter in each face direction separately.
• The standard limiters (cellLimited and faceLimited), will apply the limiter to all components of
the gradient.
• The default method is the Minmod.
606
Finite Volume Method: A Crash introduction
Gradient terms discretization schemes
• The gradient limiter implementation in OpenFOAM®, uses a blending factor .

It can be any method

gradSchemes
{
default cellLimited Gauss linear ;
}

Gradient limiter scheme

• Setting to 0 is equivalent to turning off the gradient limiter. You gain accuracy but the solution
might become unbounded.
• By setting the blending factor equal to 1 the limiter is set to be very aggressive (kind of saying
that it is always on). You gain stability but you give up accuracy (due to gradient clipping).
• If you set the blending factor to 0.5, you get the best of both worlds.
• You can use limiters with all gradient discretization schemes.

607
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• There are many Laplacian terms discretization schemes available in OpenFOAM®.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/snGradSchemes

• These are the Laplacian terms discretization schemes that you will
use most of the times:
• orthogonal: mainly limited for hexahedral meshes with no
grading (a perfect mesh). Second order accurate, bounded
on perfect meshes, without non-orthogonal corrections.
• corrected: for meshes with grading and non-orthogonality. Can be computed using the over-relaxed approach

Second order accurate, bounded depending on the quality of


the mesh, with non-orthogonal corrections.
• limited: for meshes with grading and non-orthogonality.
Second order accurate, bounded depending on the quality of
the mesh, with non-orthogonal corrections.
• uncorrected: usually limited to hexahedral meshes with very
low non-orthogonality. Second order accurate, without non-
orthogonal corrections. Stable but more diffusive than the
limited and corrected methods.
Can be computed using the over-relaxed approach
608
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• The limited method uses a blending factor .
Surface normal gradients discretization

Only option
laplacianSchemes
{
default Gauss linear limited ;
}
Interpolation method of the diffusion coefficient

• Setting to 1 is equivalent to using the corrected method. You gain accuracy, but the solution might
become unbounded.
• By setting the blending factor equal to 0 is equivalent to using the uncorrected method. You give up accuracy
but gain stability.
• If you set the blending factor to 0.5, you get the best of both worlds. In this case, the non-orthogonal
contribution does not exceed the orthogonal part. You give up accuracy but gain stability.
• For meshes with non-orthogonality less than 70, you can set the blending factor to 1.
• For meshes with non-orthogonality between 70 and 85, you can set the blending factor to 0.5
• For meshes with non-orthogonality more than 85, it is better to get a better mesh. But if you want to use that
mesh, you can set the blending factor to 0.333-0.5, and increase the number of non-orthogonal corrections.
• If you are doing LES or DES simulations, use a blending factor of 1 (this means that you need good meshes). 609
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• Just to make it clear, the blending factor is used to avoid the non-orthogonal contribution
exceeding the orthogonal part.
• That is, non-orthogonal contribution ≤ orthogonal contribution.

The blending factor works as a limiter acting on this term (non-orthogonal contribution)

Implicit part Explicit part

• In meshes with large non-orthogonality, the explicit term can lead to unboundedness and
eventually divergence.
• This limiting is local, similar to the treatment done for the connective terms when using slope
limiters and TVD schemes.
• The explicit contribution is added to the RHS of the linear system (source term), so if this term
becomes too large it will lead to convergence problems.
• It becomes harder to guarantee diagonal dominance of the matrix of coefficient.
610
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• The surface normal gradients terms usually use the same method as the one chosen for the
Laplacian terms.
• For instance, if you are using the limited 1 method for the Laplacian terms, you can use the
same method for snGradSchemes:

laplacianSchemes
{
default Gauss linear limited 1;
}

snGradSchemes
{
default limited 1;
}

611
Finite Volume Method: A Crash introduction
What method should I use?
ddtSchemes • This setup is recommended for most of
{
default CrankNicolson 0;
the cases.
}
gradSchemes • It is equivalent to the default method you will find in
{ commercial solvers.
default cellLimited Gauss linear 0.5;
grad(U) cellLimited Gauss linear 1; • In overall, this setup is second order accurate and
}
divSchemes
fully bounded.
{
default none;
• According to the quality of your mesh, you will need
div(phi,U) Gauss linearUpwindV grad(U); to change the blending factor of the
div(phi,omega) Gauss linearUpwind default; laplacianSchemes and snGradSchemes
div(phi,k) Gauss linearUpwind default;
keywords.
div((nuEff*dev(T(grad(U))))) Gauss linear;
}
laplacianSchemes
• To keep temporal diffusion to a minimum, use a CFL
{ number less than 2, and preferably below 1.
default Gauss linear limited 1;
} • If during the simulation the turbulence quantities
interpolationSchemes
{
become unbounded, you can safely change the
default linear; discretization scheme to upwind. After all,
}
snGradSchemes
turbulence is diffusion.
{
default limited 1; • For gradient discretization the leastSquares
} method is more accurate. But we have found that it
is a little bit oscillatory in tetrahedral meshes.
612
Finite Volume Method: A Crash introduction
A very accurate but oscillatory numerics
ddtSchemes • If you are looking for more accuracy, you can use
{
default backward;
this method.
}
gradSchemes • In overall, this setup is second order accurate but
{ oscillatory.
default Gauss leastSquares;
} • Use this setup with LES simulations or laminar
divSchemes
{ flows with no complex physics and meshes with
default none; overall good quality.
div(phi,U) Gauss linear;
div(phi,omega) Gauss limitedlinear 1; • Use this method with good quality meshes.
div(phi,k) Gauss limitedLinear 1;
div((nuEff*dev(T(grad(U))))) Gauss linear; • According to the quality of your mesh, you will need
}
laplacianSchemes
to change the blending factor of the
{ laplacianSchemes and snGradSchemes
default Gauss linear limited 1; keywords.
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default limited 1;
}

613
Finite Volume Method: A Crash introduction
A very stable but too diffusive numerics
ddtSchemes • If you are looking for extra stability, you can use this
{
default Euler;
method.
}
gradSchemes • This setup is very stable but too diffusive.
{
default cellLimited Gauss linear 1; • This setup is first order in space and time.
grad(U) cellLimited Gauss linear 1;
}
• You can use this setup to start the solution in the
divSchemes presence of bad quality meshes or strong
{
default none;
discontinuities.
div(phi,U) Gauss upwind;
• Remember, you can start using a first order method
div(phi,omega) Gauss upwind;
div(phi,k) Gauss upwind; and then switch to a second order method.
div((nuEff*dev(T(grad(U))))) Gauss linear;
} • According to the quality of your mesh, you will need
laplacianSchemes to change the blending factor of the
{
default Gauss linear limited 0.5; laplacianSchemes and snGradSchemes
} keywords.
interpolationSchemes
{ • Start robustly, end with accuracy.
default linear;
}
snGradSchemes
• You can use this method for troubleshooting. If the
{ solution diverges, you better check boundary
}
default limited 0.5;
conditions, physical properties, and so on.

614
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

615
On the CFL number
• First of all, what is the CFL or Courant number?
• In one dimension, the CFL number is defined as,

• The CFL number is a measure of how much information ( ) traverses a


computational grid cell ( ) in a given time-step ( ).
• The CFL number is not a magical number.
• The CFL number is a necessary condition to guarantee the stability of the numerical
scheme.
• But not all numerical schemes have the same stability requirements.
• By doing a linear stability study, we can find the stability requirements of each
numerical scheme (but this is out of the scope of this lecture).
616
On the CFL number
• Let us now talk about the CFL number condition. The CFL number condition is the maximum allowable
CFL number a solver can use.
• For the N dimensional case, the CFL number condition becomes,

• CFD solvers can be explicit and implicit.


• Explicit and implicit solvers have different stability requirements.
• Implicit numerical methods are unconditionally stable.
• In other words, they are not constrained to the CFL number condition.
• However, the fact that you are using a numerical method that is unconditionally stable, does not mean that
you can choose a time step of any size.
• The time-step must be chosen in such a way that it resolves the time-dependent features, and it maintains the
solver stability.
• When we use implicit solvers, we need to assemble a large system of equations.
• The memory requirements of implicit methods are much higher than those of explicit methods.
• In OpenFOAM®, most of the solvers are implicit.
• In our personal experience, we have been able to go up to a CFL = 5.0 while maintaining the accuracy and
without increasing too much the computational cost.
• But as we are often interested in the unsteadiness of the solution, we usually use a CFL number in the order of
1.0 617
On the CFL number
The CFL number for dummies
• I like to see the CFL number as follows,

• It is an indication of the amount of information that


propagates through one cell (or many cells), in one
time-step.

• By the way, and this is extremely important, the CFL condition is a necessary
condition for stability (and hence convergence).
• But it is not always sufficient to guarantee stability.
• Other properties of the discretization schemes that you should observe are:
conservationess, boundedness, transportiveness, and accuracy.

618
On the CFL number
How to control the CFL number

application pimpleFoam; • You can control the CFL number by changing the mesh cell
size or changing the time-step size.
startFrom latestTime;

startTime 0; • The time step size is set in the controlDict dictionary.


stopAt endTime; • The easiest way is by changing the time-step size.
endTime 10;
• If you refine the mesh, and you would like to have the same
deltaT 0.0001; CFL number as the base mesh, you will need to decrease the
writeControl runTime; time-step size.
writeInterval 0.1; • On the other side, if you coarse the mesh and you would like
purgeWrite 0; to have the same CFL number as the base mesh, you will
writeFormat ascii;
need to increase the time-step size.
writePrecision 8; • The keyword deltaT controls the time-step size of the
writeCompression off;
simulation (0.0001 seconds in this generic case).
timeFormat general; • If you use a solver that supports adjustable time-step
timePrecision 6;
(adjustTimeStep), you can set the maximum CFL number
and maximum allowable time-step using the keywords
runTimeModifiable yes;
maxCo and maxDeltaT, respectively.
adjustTimeStep yes;

maxCo 2.0;
maxDeltaT 0.001;

619
On the CFL number
How to control the CFL number

application pimpleFoam; • The option adjustTimeStep will automatically adjust the time
step to achieve the maximum desired courant number
startFrom latestTime;
(maxCo) or time-step size (maxDeltaT).
startTime 0;

stopAt endTime;
• When any of these conditions is reached, the solver will stop
scaling the time-step size.
endTime 10;

deltaT 0.0001;
• To use these features, you need to turn-on the option
adjustTimeStep.
writeControl runTime;

writeInterval 0.1;
• Remember, the first time-step of the simulation is done using
the value defined with the keyword deltaT and then it is
purgeWrite 0;
automatically scaled (up or down), to achieve the desired
writeFormat ascii; maximum values (maxCo and maxDeltaT).
writePrecision 8;
• It is recommended to start the simulation with a low time-step
writeCompression off;
in order to let the solver scale-up the time-step size.
timeFormat general;
• If you want to change the values on-the-fly, you need to turn-
timePrecision 6;
on the option runTimeModifiable.
runTimeModifiable yes;
• The feature adjustTimeStep is only present in the PIMPLE
adjustTimeStep yes;
family solvers, but it can be added to any solver by modifying
maxCo 2.0; the source code.
maxDeltaT 0.001;

620
On the CFL number
The output screen
• This is the output screen of a solver supporting the option adjustTimeStep.
• In this case maxCo is equal 2 and maxDeltaT is equal to 0.001.
• Notice that the solver reached the maximum allowable maxDeltaT.

Courant Number mean: 0.10863988 max: 0.73950028 Courant number (mean and maximum values)
deltaT = 0.001 Current time-step
Time = 30.000289542261612 Simulation time

PIMPLE: iteration 1 One PIMPLE iteration (outer loop), this is equivalent to PISO
DILUPBiCG: Solving for Ux, Initial residual = 0.003190933, Final residual = 1.0207483e-09, No Iterations 5
DILUPBiCG: Solving for Uy, Initial residual = 0.0049140114, Final residual = 8.5790109e-10, No Iterations 5
DILUPBiCG: Solving for Uz, Initial residual = 0.010705877, Final residual = 3.5464756e-09, No Iterations 4
GAMG: Solving for p, Initial residual = 0.024334674, Final residual = 0.0005180308, No Iterations 3
GAMG: Solving for p, Initial residual = 0.00051825089, Final residual = 1.6415538e-05, No Iterations 5
time step continuity errors : sum local = 8.768064e-10, global = 9.8389717e-11, cumulative = -2.6474162e-07
GAMG: Solving for p, Initial residual = 0.00087813032, Final residual = 1.6222017e-05, No Iterations 3
GAMG: Solving for p, Initial residual = 1.6217958e-05, Final residual = 6.4475277e-06, No Iterations 1
time step continuity errors : sum local = 3.4456296e-10, global = 2.6009599e-12, cumulative = -2.6473902e-07
ExecutionTime = 33091.06 s ClockTime = 33214 s
CPU time and wall clock
fieldMinMax domainminandmax output:
min(p) = -0.59404715 at location (-0.019 0.02082288 0.072) on processor 1
max(p) = 0.18373302 at location (-0.02083962 -0.003 -0.136) on processor 1
min(U) = (0.29583255 -0.4833922 -0.0048229716) at location (-0.02259661 -0.02082288 -0.072) on processor 0
max(U) = (0.59710937 0.32913292 0.020043679) at location (0.11338793 -0.03267608 0.12) on processor 3
min(nut) = 1.6594481e-10 at location (0.009 -0.02 0.024) on processor 0
max(nut) = 0.00014588174 at location (-0.02083962 0.019 0.072) on processor 1

yPlus yplus output:


patch square y+ : min = 0.44603573, max = 6.3894913, average = 2.6323389
writing field yPlus
621
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

622
Linear solvers in OpenFOAM®
• After spatial and temporal discretization and by using equation

in every control volume of the domain, a system of linear algebraic equations for the
transported quantity is assembled

• This system can be solved by using any iterative or direct method.


623
Linear solvers in OpenFOAM®
Linear solvers – fvSolution dictionary
solvers • The equation solvers, tolerances, and algorithms are controlled
{ from the sub-dictionary solvers located in the fvSolution
p
{
dictionary file.
solver PCG;
• In the dictionary file fvSolution and depending on the solver
preconditioner DIC;
tolerance 1e-06; you are using you will find the additional sub-dictionaries PISO,
relTol 0; PIMPLE, and SIMPLE, which will be described later.
}
pFinal • In this dictionary is where we tell OpenFOAM® how to crunch
{ numbers.
$p;
relTol 0; • The solvers sub-dictionary specifies each linear solver that is
} used for each equation being solved.
U
{ • The linear solvers distinguish between symmetric matrices and
solver PBiCGStab;
asymmetric matrices.
preconditioner DILU;
tolerance 1e-08; • If you forget to define a linear-solver or use the wrong one,
relTol 0;
} OpenFOAM® will let you know.
}
• The syntax for each entry within the solvers sub-dictionary uses
PISO
a keyword that is the word relating to the variable being solved
{ in the particular equation and the options related to the linear
nCorrectors 2; solver.
nNonOrthogonalCorrectors 1;
}

624
Linear solvers in OpenFOAM®
Linear solvers – fvSolution dictionary
solvers • In this generic case, to solve the pressure (p) we are using the
{ PCG method with the DIC preconditioner, an absolute
p
{
tolerance equal to 1e-06 and a relative tolerance relTol equal
solver PCG; to 0.
preconditioner DIC;
tolerance 1e-06; • The entry pFinal refers to the final pressure correction (notice
relTol 0; that we are using macro syntax), and we are using a relative
}
tolerance relTol equal to 0 (disabled).
pFinal
{ • To solve the velocity field (U) we are using the PBiCGStab
$p; method with the DILU preconditoner, an absolute tolerance
relTol 0;
}
equal to 1e-08 and a relative tolerance relTol equal to 0.
U
{
• The linear solvers will iterative until reaching any of the
solver PBiCGStab; tolerance values set by the user or reaching a maximum value
preconditioner DILU; of iterations (optional entry).
tolerance 1e-08;
relTol 0; • FYI, solving for the velocity is relatively inexpensive, whereas
} solving for the pressure is expensive.
}
• The pressure equation is particularly important as it governs
PISO mass conservation.
{
nCorrectors 2; • If you do not solve the equations accurately enough (tolerance),
nNonOrthogonalCorrectors 1;
the physics might be wrong.
}
• Selection of the tolerance is of paramount importance and it
might be problem dependent.
625
Linear solvers in OpenFOAM®
Linear solvers – fvSolution dictionary
solvers • The linear solvers are iterative, i.e., they are based on reducing
{ the equation residual over a succession of solutions.
p
{ • The residual is a measure of the error in the solution so that the
solver PCG;
preconditioner DIC;
smaller it is, the more accurate the solution.
tolerance 1e-06;
• More precisely, the residual is evaluated by substituting the
relTol 0;
} current solution into the equation and taking the magnitude of
pFinal the difference between the left- and right-hand sides (L2-norm).
{
$p;
relTol 0;
}
U
{
solver PBiCGStab;
preconditioner DILU;
• It is also normalized to make it independent of the scale of the
tolerance 1e-08; problem being analyzed.
relTol 0;
}
}

PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}

626
Linear solvers in OpenFOAM®
Linear solvers – fvSolution dictionary
solvers • Before solving an equation for a particular field, the initial
{ residual is evaluated based on the current values of the field.
p
{ • After each solver iteration the residual is re-evaluated. The
solver PCG;
preconditioner DIC;
solver stops if either of the following conditions are reached:
tolerance 1e-06;
• The residual falls below the solver tolerance, tolerance.
relTol 0;
} • The ratio of current to initial residuals falls below the solver
pFinal
{ relative tolerance, relTol.
$p; • The number of iterations exceeds a maximum number of
relTol 0;
}
iterations, maxIter.
U
{
• The solver tolerance should represent the level at which the
solver PBiCGStab; residual is small enough that the solution can be deemed
preconditioner DILU; sufficiently accurate.
tolerance 1e-08;
relTol 0; • The keyword maxIter is optional and the default value is 1000.
minIter 3;
maxIter 100; • The user can also define the minimum number of iterations
} using the keyword minIter. This keyword is optional, and the
}
default value is 0.
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}

627
Linear solvers in OpenFOAM®
Linear solvers
• These are the linear solvers (segregated) available in OpenFOAM®:

• GAMG → Multigrid solver • PCG → Newton-Krylov solver


• PBiCG → Newton-Krylov solver • smoothSolver → Smooth solver
• PBiCGStab → Newton-Krylov solver • diagonalSolver

• You will find the source code of the linear solvers in the following directory:
• $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/solvers

• When using Newton-Krylov solvers, you need to define preconditoners.


• These are the preconditioners available in OpenFOAM®:

• DIC • FDIC • diagonal


• DILU • GAMG • noPreconditioner

• You will find the source code in the following directory:


• $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/preconditioners

• The smoothSolver solver requires the specification of a smoother.


• These are the smoothers available in OpenFOAM®:

• DIC • DILUGaussSeidel • nonBlockingGaussSeidel


• DICGaussSeidel • FDIC • symGaussSeidel
• DILU • GaussSeidel

• You will find the source code in the following directory:


• $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/smoothers 628
Linear solvers in OpenFOAM®
Linear solvers – General remarks
• As you can see, when it comes to linear solvers there are many options and combinations available in
OpenFOAM®.
• When it comes to choosing the linear solver, there is no written theory.
• It is problem and hardware dependent (type of the mesh, physics involved, processor cache memory, network
connectivity, partitioning method, and so on).
• Most of the times using the GAMG method (geometric-algebraic multi-grid), is the best choice for symmetric
matrices (e.g., pressure).
• The GAMG method should converge fast (less than 20 iterations). If it’s taking more iterations, try to change the
smoother.
• And if it is taking too long or it is unstable, use the PCG solver.
• When running with many cores (more than 1000), using the PCG might be a better choice.
• For asymmetric matrices, the PBiCGStab method with DILU preconditioner is a good choice.
• The smoothSolver solver with smoother GaussSeidel, also performs very well.
• If the PBiCGStab method with DILU preconditioner mysteriously crashed with an error related to the
preconditioner, use the smoothSolver or change the preconditioner.
• But in general the PBiCGStab solver should be faster than the smoothSolver solver.
• Remember, asymmetric matrices are assembled from the velocity (U), and the transported quantities (k,
omega, epsilon, T, and so on).
• Usually, computing the velocity and the transported quantities is inexpensive and fast, so it is a good idea to use
a tight tolerance (1e-8) for these fields.
• The diagonal solver is used for back-substitution, for instance, when computing density using the equation of
state (we know p and T). 629
Linear solvers in OpenFOAM®
Linear solvers – General remarks
• A few comments on the linear solvers residuals (we will talk about monitoring the residuals
later on).
• Residuals are not a direct indication that you are converging to the right solution.
• The first time-steps the solution might not converge, this is acceptable.
• Also, you might need to use a smaller time-step during the first iterations to maintain solver
stability.
• If the solution is not converging after a while, try to reduce the time-step size.

Time = 50

Courant Number mean: 0.044365026 max: 0.16800273


smoothSolver: Solving for Ux, Initial residual = 1.0907508e-09, Final residual = 1.0907508e-09, No Iterations 0
smoothSolver: Solving for Uy, Initial residual = 1.4677462e-09, Final residual = 1.4677462e-09, No Iterations 0
DICPCG: Solving for p, Initial residual = 1.0020944e-06, Final residual = 1.0746895e-07, No Iterations 1
time step continuity errors : sum local = 4.0107145e-11, global = -5.0601748e-20, cumulative = 2.637831e-18
ExecutionTime = 4.47 s ClockTime = 5 s

fieldMinMax minmaxdomain output:


min(p) = -0.37208345 at location (0.025 0.975 0.5)
max(p) = 0.77640927 at location (0.975 0.975 0.5)
min(U) = (0.00028445255 -0.00028138799 0) at location (0.025 0.025 0.5)
max(U) = (0.00028445255 -0.00028138799 0) at location (0.025 0.025 0.5)
Residuals

630
Linear solvers in OpenFOAM®
Linear solvers tolerances
• So how do we set the tolerances?
• The pressure equation is particularly important, so we should resolve it accurately. Solving the
pressure equation is the expensive part of the whole iterative process.
• For the pressure equation (symmetric matrix), you can start the simulation with a tolerance
equal to 1e-6 and relTol equal to 0.01.
• And after a while, you change these values to 1e-6 and 0.0, respectively.
• If the linear solver is taking too much time, you can change the convergence criterion to 1e-4
and relTol equal to 0.05. You usually will do this during the first iterations.

Loose tolerance Tight tolerance

p p
{ {
solver PCG; solver PCG;
preconditioner DIC; preconditioner DIC;
tolerance 1e-6; tolerance 1e-6;
relTol 0.01; relTol 0.0;
} }

631
Linear solvers in OpenFOAM®
Linear solvers tolerances
• For the velocity field (U) and the transported quantities (asymmetric matrices), you can use the
following criterion.
• Solving for these variables is relatively inexpensive, so you can start right away with a tight
tolerance.
• As a side note, the relative tolerance (relTol) is the difference between the initial residuals and
the current final residuals.

Loose tolerance Tight tolerance

U U
{ {
solver PBiCGStab; solver PBiCGStab;
preconditioner DILU; preconditioner DILU;
tolerance 1e-8; tolerance 1e-8;
relTol 0.001; relTol 0.0;
} }

632
Linear solvers in OpenFOAM®
Linear solvers tolerances
• It is also a good idea to set the minimum number of iterations (minIter), we recommend using a
value of 3.
• If your solver is doing too many iterations, you can set the maximum number of iterations
(maxIter).
• But be careful, if the solver reach the maximum number of iterations it will stop, we are talking
about unconverged time-steps or outer-iterations.
• Setting the maximum number of iterations is especially useful during the first time-steps where
the linear solver takes longer to converge.
• You can set minIter and maxIter in all symmetric and asymmetric linear solvers.

p
{
solver PCG;
preconditioner DIC;
tolerance 1e-6;
relTol 0.01;
minIter 3;
maxIter 100;
}
633
Linear solvers in OpenFOAM®
Linear solvers tolerances
• When you use the PISO or PIMPLE method with the momentumPredictor option (which is
enabled by default), you also have the option to set the tolerance for the final pressure corrector
step (pFinal).
• By proceeding in this way, you can put all the computational effort only in the last corrector step
(pFinal).
• For all the intermediate corrector steps, you can use a more relaxed convergence criterion.
• For example, you can use the following solver and tolerance criterion for all the intermediate
corrector steps (p), then in the final corrector step (pFinal) you tight the solver tolerance.

Loose tolerance for p Tight tolerance for pFinal

p pFinal
{ {
solver PCG; solver PCG;
preconditioner DIC; preconditioner DIC;
tolerance 1e-4; tolerance 1e-6;
relTol 0.05; relTol 0.0;
} }

634
Linear solvers in OpenFOAM®
Linear solvers tolerances
• When you use the PISO or PIMPLE method with the momentumPredictor option (which is
enabled by default), you also have the option to set the tolerance for the final pressure corrector
step (pFinal).
• By proceeding in this way, you can put all the computational effort only in the last corrector step
(pFinal in this case).
• For all the intermediate corrector steps (p), you can use a more relaxed convergence criterion.
• If you proceed in this way, it is recommended to do at least 2 corrector steps (nCorrectors).

Courant Number mean: 0.10556573 max: 0.65793603


deltaT = 0.00097959184
Time = 10

PIMPLE: iteration 1
DILUPBiCG: Solving for Ux, Initial residual = 0.0024649332, Final residual = 2.3403547e-09, No Iterations 4
DILUPBiCG: Solving for Uy, Initial residual = 0.0044355904, Final residual = 1.8966277e-09, No Iterations 4
DILUPBiCG: Solving for Uz, Initial residual = 0.010100894, Final residual = 1.4724403e-09, No Iterations 4
GAMG: Solving for p, Initial residual = 0.018497918, Final residual = 0.00058090899, No Iterations 3
1 p
GAMG: Solving for p, Initial residual = 0.00058090857, Final residual = 2.5748489e-05, No Iterations 5
time step continuity errors : sum local = 1.2367812e-09, global = 2.8865505e-11, cumulative = 1.057806e-08
GAMG: Solving for p, Initial residual = 0.00076032002, Final residual = 2.3965621e-05, No Iterations 3 p
2 GAMG: Solving for p, Initial residual = 2.3961044e-05, Final residual = 6.3151172e-06, No Iterations 2 pFinal
time step continuity errors : sum local = 3.0345314e-10, global = -3.0075104e-12, cumulative = 1.0575052e-08
DILUPBiCG: Solving for omega, Initial residual = 0.00073937735, Final residual = 1.2839908e-10, No Iterations 4
DILUPBiCG: Solving for k, Initial residual = 0.0018291502, Final residual = 8.5494234e-09, No Iterations 3
ExecutionTime = 29544.18 s ClockTime = 29600 s

nCorrectors
635
Linear solvers in OpenFOAM®
Linear solvers – Matrix reordering
• As we are solving a sparse matrix, the more diagonal the matrix is, the best the convergence
rate will be.
• So it is highly advisable to use the utility renumberMesh before running the simulation.
• $> renumberMesh –overwrite
• The utility renumberMesh can dramatically increase the speed of the linear solvers, specially
during the first iterations.
• The idea behind reordering is to make the matrix more diagonally dominant, therefore, speeding
up the iterative solver.

Matrix structure plot before reordering Matrix structure plot after reordering

Note: this is the actual pressure matrix from an OpenFOAM® model case 636
Linear solvers in OpenFOAM®
On the multigrid solvers
• The development of multigrid solvers (GAMG in OpenFOAM®), together with the development
of high-resolution TVD schemes and parallel computing, are among the most remarkable
achievements of the history of CFD.
• Most of the time using the GAMG linear solver is fine.
• However, if you see that the GAMG linear solver is taking too long to converge or is converging
in more than 100 iterations, it is better to use the PCG linear solver.
• Particularly, we have found that the GAMG linear solver in OpenFOAM® does not perform very
well when you scale your computations to more than 500 processors.
• Also, we have found that for some multiphase cases the PCG method outperforms the GAMG.
• But again, this is problem and hardware dependent.
• As you can see, you need to always monitor your simulations (stick to the screen for a while.
• Otherwise, you might end-up using a solver that is performing poorly, and this translate in
increased computational time and costs.

637
Linear solvers in OpenFOAM®
On the multigrid solvers tolerances
• If you go for the GAMG linear solver for symmetric matrices (e.g., pressure), the following
tolerances are acceptable for most of the cases.

Loose tolerance for p Tight tolerance for pFinal

p pFinal
{ {
solver GAMG; solver GAMG;
tolerance 1e-6; tolerance 1e-6;
relTol 0.01; relTol 0;
smoother GaussSeidel; smoother GaussSeidel;
nPreSweeps 0; nPreSweeps 0;
nPostSweeps 2; nPostSweeps 2;
cacheAgglomeration on; cacheAgglomeration on;
agglomerator faceAreaPair; agglomerator faceAreaPair;
nCellsInCoarsestLevel 100; nCellsInCoarsestLevel 100;
mergeLevels 1; mergeLevels 1;
minIter 3; minIter 3;
} }

NOTE:
The GAMG parameters are not optimized, that is up to you.
Most of the times is safe to use the proposed parameters.
638
Linear solvers in OpenFOAM®
Linear solvers tolerances – Steady simulations
• The previous tolerances are fine for unsteady solver.
• For extremely coupled problems you might need to have tighter tolerances.
• You can use the same tolerances for steady solvers. However, it is acceptable to use a looser
criterion.
• For steady simulations using the SIMPLE method, you can set the convergence controls based
on residuals of fields.
• The controls are specified in the residualControls sub-dictionary of the dictionary file
fvSolution.

SIMPLE
{
nNonOrthogonalCorrectors 2;

residualControl
{
p 1e-4; Residual control for every
U 1e-4; field variable you are solving
}
}

639
Linear solvers in OpenFOAM®
Linear solvers benchmarking of a model case

Case Linear solver for P Preconditioner or smoother MR Time QOI

IC1 PCG FDIC NO 278 2.8265539

IC2 smoothSolver symGaussSeidel NO 2070 2.8271198

IC3 ICCG GAMG NO 255 2.8265538

IC4 GAMG GaussSeidel NO 1471 2.8265538

IC5 PCG GAMG-GaussSeidel NO 302 2.8265538

IC6 GAMG GaussSeidel YES 438 2.8265539

IC7 PCG FDIC YES 213 2.8265535

IC8 PCG GAMG-GaussSeidel YES 283 2.8265538

IC9 ICCG GAMG YES 261 2.8265538

IC10 PCG DIC NO 244 2.8265539

Solver used = icoFoam – Incompressible case


MR = matrix reordering (renumberMesh)
QOI = quantity of interest. In this case the maximum velocity at the outlet (m/s)
TIME = clock time (seconds)
640
Linear solvers in OpenFOAM®
Exercises
• Choose any tutorial or a case of your own and do a benchmarking of the linear solvers.
• Using your benchmarking case, conduct the following numerical experiments:
• Find the optimal parameters for the GAMG solver.
• Use different linear solvers for p and pFinal (symmetric matrices). Do you see any advantage?
• Do a benchmarking of the different reordering methods available
(Hint: look for the dictionary renumberMeshDict)
• Compare the performance of the asymmetric solvers PBiCG, PBiCGStab, and smoothSolver. Do you
see any significant difference between both solvers?

• Is it possible to switch between segregated and coupled linear solvers on-the-fly?


• In what files are located the controls of the SIMPLE, PISO, and PIMPLE methods?
(Hint: for example, using grep look for the keyword nCorrectors in the directory src/finiteVolume)

641
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

642
Pressure-Velocity coupling in OpenFOAM®
• To solve the Navier-Stokes equations we need to use a solution approach able to
deal with the nonlinearities of the governing equations and with the coupled set of
equations.

Additional equations deriving from models, such as, volume fraction,


chemical reactions, turbulence modeling, combustion, multi-species, etc.

643
Pressure-Velocity coupling in OpenFOAM®
• Many numerical methods exist to solve the Navier-Stokes equations, just to name a
few:
• Pressure-correction methods (Predictor-Corrector type).
• SIMPLE, SIMPLEC, SIMPLER, PISO.
• Projection methods.
• Fractional step (operator splitting), MAC, SOLA.
• Density-based methods and preconditioned solvers.
• Riemann solvers, ROE, HLLC, AUSM+, ENO, WENO.
• Artificial compressibility methods.
• Artificial viscosity methods.

• The most widely used approaches for solving the NSE are:
• Pressure-based approach (predictor-corrector).
• Density-based approach.

644
Pressure-Velocity coupling in OpenFOAM®
• Historically speaking, the pressure-based approach was developed for low-speed
incompressible flows, while the density-based approach was mainly developed for
high-speed compressible flows.
• However, both methods have been extended and reformulated to solve and operate
for a wide range of flow conditions beyond their original intent.
• In OpenFOAM®, you will find segregated pressure-based solvers.
• The segregated pressure-based solvers in OpenFOAM®, solve a modified pressure
equation (pressure-Poisson equation).
• The following methods are available:
• SIMPLE (Semi-Implicit Method for Pressure-Linked Equations)
• SIMPLEC (SIMPLE Corrected/Consistent)
• PISO (Pressure Implicit with Splitting Operators)
• You will find the solvers in the following directory:
• $WM_PROJECT_DIR/applications/solvers
• Additionally, you will find something called PIMPLE, which is a hybrid between
SIMPLE and PISO (known as iterative PISO outside OpenFOAM® jargon).
• This formulation can give you more accuracy and stability when using very
large time-steps or in pseudo-transient simulations.
645
Pressure-Velocity coupling in OpenFOAM®
• In OpenFOAM®, the PISO and PIMPLE methods are formulated for unsteady
simulations.
• Whereas, the SIMPLE and SIMPLEC methods are formulated for steady simulations.
• If conserving time is not a priority, you can use the PIMPLE method in pseudo
transient mode.
• The pseudo transient PIMPLE method is more stable than the SIMPLE method, but it
has a higher computational cost.
• Also, the pseudo transient PIMPLE method tends to be faster than the fully transient
PIMPLE when reaching steady states.
• Depending on the method and solver you are using, you will need to define a specific
sub-dictionary in the dictionary file fvSolution.
• For instance, if you are using the PISO method, you will need to specify the PISO
sub-dictionary.
• And depending on the method, each sub-dictionary will have different entries.

646
Pressure-Velocity coupling in OpenFOAM®
On the origins of the methods
• SIMPLE
• S. V. Patankar and D. B. Spalding, “A calculation procedure for heat, mass and momentum
transfer in three-dimensional parabolic flows”, Int. J. Heat Mass Transfer, 15, 1787-1806 (1972).

• SIMPLE-C
• J. P. Van Doormaal and G. D. Raithby, “Enhancements of the SIMPLE method for predicting
incompressible fluid flows”, Numerical Heat Transfer, 7, 147-163 (1984).

• PISO
• R. I. Issa, “Solution of the implicitly discretized fluid flow equations by operator-splitting”, J.
Comput. Phys., 62, 40-65 (1985).

• PIMPLE
• Unknown origins outside OpenFOAM® ecosystem (we are referring to the semantics).
• It is equivalent to PISO with outer iterations (iterative time-advancement of the solution).
• Useful reference (besides PISO reference):
• I. E. Barton, “Comparison of SIMPLE and PISO-type algorithms for transient flows, Int. J.
Numerical methods in fluids, 26,459-483 (1998).
• P. Oliveira and R. I. Issa, “An improved piso algorithm for the computation of buoyancy-driven
flows”, Numerical Heat Transfer, 40, 473-493 (2001).

647
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution.
• It controls the options related to the SIMPLE pressure-velocity coupling method.
• The SIMPLE method only makes one correction.
• An additional correction to account for mesh non-orthogonality is available when using the
SIMPLE method. The number of non-orthogonal correctors is specified by the
nNonOrthogonalCorrectors keyword.
• The number of non-orthogonal correctors is chosen according to the mesh quality.
• For orthogonal meshes you can use 0 non-orthogonal corrections. However, it is strongly
recommended to do at least 1 non-orthogonal correction (this helps stabilizing the solution).
• For non-orthogonal meshes, it is recommended to do at least 1 correction.

SIMPLE
{
nNonOrthogonalCorrectors 1;
}

648
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
• You can use the optional keyword consistent to enable or disable the SIMPLEC method.
• This option is disable by default.
• In the SIMPLEC method, the cost per iteration is marginally higher but the convergence rate is
better, so the number of iterations is reduced.
• The SIMPLEC method relaxes the pressure in a consistent manner and additional relaxation of
the pressure is not generally necessary (but it is recommended).
• In addition, convergence of the p-U system is better and still is reliable with less aggressive
relaxation factors of the momentum equation.

SIMPLE
{
consistent yes;
nNonOrthogonalCorrectors 1;
}

649
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
• These are the typical (or industry standard) under-relaxation factors for the SIMPLE and
SIMPLEC methods.
• Remember the under-relaxation factors are problem dependent.

SIMPLE SIMPLEC

relaxationFactors relaxationFactors
{ {
fields fields
{ {
p 0.3; p 1.0;
} } Usually there is no need
to under-relax pressure;
equations equations however, it is advisable.

{ {
U 0.7; p 1.0;
k 0.7; U 0.9;
omega 0.7; k 0.9;
} omega 0.9;
} }
}
650
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary

SIMPLEC

relaxationFactors
• If you are planning to use the SIMPLEC method,
{
we recommend you to use under-relaxation factors
that are little bit more smaller that the industry fields
standard values. {
p 0.7;
• If during the simulation you still have some stability
}
problems, try to reduce all the values to 0.5.
equations
• Remember the under-relaxation factors are {
problem dependent. p 0.7;
• If you are having convergence problems, it is U 0.7;
recommended to start the simulation with low k 0.7;
values (about 0.3), and then increase the values omega 0.7;
slowly up to 0.7 or 0.9 (for faster convergence). }
}

651
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE loop in OpenFOAM®

fvVectorMatrix UEqn
(
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
);

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

fvScalarMatrix pEqn
(
fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
);

U = HbyA – rAU*fvc::grad(p);

This is an excerpt of the actual source code of


the solver

652
Pressure-Velocity coupling in OpenFOAM®
The PISO sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution.
• It controls the options related to the PISO pressure-velocity coupling method.
• The PISO method requires at least one correction (nCorrectors).
• For good accuracy and stability (specially in unstructured meshes), it is recommended to use at
least 2 nCorrectors.
• An additional correction to account for mesh non-orthogonality is available when using the PISO
method. The number of non-orthogonal correctors is specified by the
nNonOrthogonalCorrectors keyword.
• The number of non-orthogonal correctors is chosen according to the mesh quality.
• For orthogonal meshes you can use 0 non-orthogonal corrections. However, it is strongly
recommended to do at least 1 non-orthogonal correction (this helps stabilizing the solution).
• For non-orthogonal meshes, it is recommended to do at least 1 correction.

PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
653
Pressure-Velocity coupling in OpenFOAM®
The PISO sub-dictionary
• You can use the optional keyword momentumPredictor to enable or disable the momentum
predictor step.
• The momentum predictor helps in stabilizing the solution as we are computing better
approximations for the velocity.
• It is clear that this will add an extra computational cost, which most of the times is negligible.
• In most of the solvers, this option is enabled by default.
• It is recommended to use this option for highly convective flows (high Reynolds number). If you
are working with low Reynolds flow or creeping flows it is recommended to turn it off.
• Note that when you enable the option momentumPredictor, you will need to define the linear
solvers for the variables .*Final (we are using regex notation).
• Also, if you want to use URF you will need to apply then to all field variables (including .*Final).

PISO
{
momentumPredictor yes;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
654
Pressure-Velocity coupling in OpenFOAM®
The PISO loop in OpenFOAM®
(PISO with non-iterative marching – NITA – )

fvVectorMatrix UEqn
(
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
);

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

fvScalarMatrix pEqn
(
fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
);

U = HbyA – rAU*fvc::grad(p);

This is an excerpt of the actual source code of


the solver
655
Pressure-Velocity coupling in OpenFOAM®
The PIMPLE sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution. It controls the options related to the PIMPLE
pressure-velocity coupling method.
• The PIMPLE method works very similar to the PISO method.
• In fact, setting the keyword nOuterCorrectors to 1 is equivalent to running using the PISO method.
• The keyword nOuterCorrectors controls a loop outside the PISO loop.
• To gain more stability, especially when using large time-steps or when dealing with complex physics
(combustion, chemical reactions, shock waves, and so on), you can use more outer correctors
(nOuterCorrectors).
• Usually between 2 and 5 corrections for computational efficiency.
• Have in mind that increasing the number of nOterCorrectors will highly increase the computational cost.

PIMPLE
{
momentumPredictor yes;
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
656
Pressure-Velocity coupling in OpenFOAM®
The PIMPLE sub-dictionary
• You can use under-relaxation factors (URF) with the PIMPLE solvers.
• By using URF, you will gain more stability in time dependent solutions (as they control the amount of change of
field variables within the time-step).
• However, if you use too low URF values, your solution might not be time-accurate anymore.
• You can use the same or larger URF values as those for steady simulation.
• Note that when you enable the option momentumPredictor, you will need to define the linear solvers for the
variables .*Final (we are using regex notation).
• You can assign URF to all variables (including .*Final), to only the intermediate field variables (U, p, k, and so
on), or to only the .*Final variables (UFinal, pFinal, kFinal, and so on).
• We recommend to use URF in all variables.

PIMPLE
{
momentumPredictor yes;
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
657
Pressure-Velocity coupling in OpenFOAM®
The PIMPLE loop in OpenFOAM®
(PISO with iterative marching – ITA – )

fvVectorMatrix UEqn
(
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
);

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

fvScalarMatrix pEqn
(
fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
);

U = HbyA – rAU*fvc::grad(p);

This is an excerpt of the actual source code of


the solver

658
Pressure-Velocity coupling in OpenFOAM®
Comparison of PISO with non-iterative time-advancement (PISO-NITA)
against PISO with Iterative time-advancement (PISO-ITA)

• The main difference between both methods is the outer loop present in the PISO-ITA.
• This outer loop gives more stability and allow the use of very large time-steps (CFL numbers).
• The recommended CFL number of the PISO-NITA is below 2 (for good accuracy and stability).

PISO-NITA PISO-ITA (PIMPLE in OpenFOAM®)


659
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

660
Unsteady and steady simulations
Sliding grids – Continuous stirred tank reactor
• Nearly all flows in nature and industrial applications www.wolfdynamics.com/wiki/FVM_uns/ani5.gif
are unsteady (also known as transient or
time-dependent).
• Unsteadiness can be due to:
• Instabilities.
• Non-equilibrium initial conditions.
• Time-dependent boundary conditions. Multiphase flow
www.wolfdynamics.com/wiki/FVM_uns/ani3.gif
• Source terms.
• Chemical reactions and finite rate chemistry.
• Phase change.
• Moving or deforming bodies.
• Turbulence.
• Buoyancy and heat transfer.
• Discontinuities.
Turbulent flows - SRS
• Multiple phases. www.wolfdynamics.com/wiki/FVM_uns/ani4.gif

• Fluid structure interaction.


• Combustion.
• And much more.

661
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
• Select the time step. The time-step must be chosen in such a way that it resolves the time-dependent features
and maintains solver stability.
• Select the temporal discretization scheme.
• Set the tolerance (absolute and/or relative) of the linear solvers.
• Monitor the CFL number.
• Monitor the stability and boundedness of the solution.
• Monitor a quantity of interest.
• And of course, you need to save the solution with a given frequency.
• Have in mind that unsteady simulations generate a lot of data.
• End time of the simulation?, it is up to you.
• In the controlDict dictionary you need to set runtime parameters and general instructions on how to run the
case (such as time step and maximum CFL number). You also set the saving frequency.
• In the fvSchemes dictionary you need to set the temporal discretization scheme.
• In the fvSolution dictionary you need to set the linear solvers.
• Also, you will need to set the number of corrections of the velocity-pressure coupling method used (e.g. PISO
or PIMPLE), this is done in the fvSolution dictionary.
• Additionally, you may set functionObjects in the controlDict dictionary. The functionObjects are used to
do sampling, probing and co-processing while the simulation is running.
662
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?

ddtSchemes • The fvSchemes dictionary contains the information related to


{ time discretization and spatial discretization schemes.
default backward;
} • In this generic case we are using the backward method for time
gradSchemes
discretization (ddtSchemes).
{
default Gauss linear;
• This scheme is second order accurate but oscillatory.
grad(p) Gauss linear;
• The parameters can be changed on-the-fly.
}

divSchemes
{
default none;
div(phi,U) Gauss linear;
}

laplacianSchemes
{
default Gauss linear orthogonal;
}

interpolationSchemes
{
default linear;
}

snGradSchemes
{
default orthogonal;
}
663
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?

startFrom latestTime; • The controlDict dictionary contains runtime simulation


controls, such as, start time, end time, time step, saving
startTime 0;
frequency and so on.
stopAt endTime;
• Most of the entries are self-explanatory.
endTime 10;
• This generic case starts from time 0 (startTime), and it will run
deltaT 0.0001; up to 10 seconds (endTime).

writeControl runTime; • It will write the solution every 0.1 seconds (writeInterval) of
simulation time (runTime).
writeInterval 0.1;
• The time step of the simulation is 0.0001 seconds (deltaT).
purgeWrite 0;
• It will keep all the solution directories (purgeWrite).
writeFormat ascii;
• It will save the solution in ascii format (writeFormat) with a
writePrecision 8; precision of 8 digits (writePrecision).
writeCompression off; • And as the option runTimeModifiable is on (yes), we can
modify all these entries while we are running the simulation.
timeFormat general;
• To reduce parsing time and file size, it is recommended to use
timePrecision 6;
binary format to write the solution.
runTimeModifiable yes;

adjustTimeStep yes;
maxCo 2.0;
maxDeltaT 0.001;
664
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?

startFrom latestTime; • In this generic case, the solver supports adjustable time-step
(adjustTimeStep).
startTime 0;
• The option adjustTimeStep will automatically adjust the time
stopAt endTime;
step to achieve the maximum desired courant number (maxCo)
endTime 10; or time-step size (maxDeltaT).
deltaT 0.0001; • When any of these conditions is reached, the solver will stop
scaling the time-step size.
writeControl runTime;
• Remember, the first time-step of the simulation is done using the
writeInterval 0.1; value defined with the keyword deltaT and then it is
purgeWrite 0;
automatically scaled (up or down), to achieve the desired
maximum values (maxCo and maxDeltaT).
writeFormat ascii;
• It is recommended to start the simulation with a low time-step in
writePrecision 8; order to let the solver scale-up the time-step size.
writeCompression off; • The feature adjustTimeStep is only present in the PIMPLE
family solvers, but it can be added to any solver by modifying
timeFormat general;
the source code.
timePrecision 6;
• If you are planning to use large time steps (CFL much higher
runTimeModifiable yes; than 1), it is recommended to do at least 3 correctors steps
(nCorrectors) in PISO/PIMPLE loop, and at least 2 outer
adjustTimeStep yes;
maxCo 2.0;
correctors in the PIMPLE loop.
maxDeltaT 0.001;
665
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
solvers • The fvSolution dictionary contains the instructions of how to
{
p
solve each discretized linear equation system.
{ • As for the controlDict and fvSchemes dictionaries, the
solver PCG;
preconditioner DIC; parameters can be changed on-the-fly.
tolerance 1e-06;
relTol 0; • To set these parameters, follow the guidelines given in the
} previous section.

pFinal
• Depending on the solver you are using, you will need to define
{ the sub-dictionary PISO or PIMPLE.
$p;
• Setting the keyword nOuterCorrectors to 1 in PIMPLE solvers
relTol 0;
} is equivalent to running using the PISO method.
• To gain more stability, especially when using large time-steps,
“U.*”
{
you can use more outer correctors (nOuterCorrectors).
solver smoothSolver;
• If you are using large time steps (CFL much higher than 1), it is
smoother symGaussSeidel;
tolerance 1e-08; recommended to do at least 3 correctors steps (nCorrectors) in
relTol 0; PISO/PIMPLE loop.
}
} • Remember, in both PISO and PIMPLE method you need to do
PIMPLE at least one correction (nCorrectors).
{
nOuterCorrectors 1; • Adding corrections increase the computational cost
nCorrectors 2;
nNonOrthogonalCorrectors 1;
(nOuterCorrectors and nCorrectors).
}
666
Unsteady and steady simulations
How to choose the time-step in unsteady simulations and monitor the solution

• Remember, when running unsteady simulations the time-step must be chosen in such a way
that it resolves the time-dependent features and maintains solver stability.

When you use large time steps you do not


resolve well the physics

By using a smaller time step you resolve


better the physics and you gain stability

667
Unsteady and steady simulations
Monitoring unsteady simulations
• When running unsteady simulations, it is highly advisable to monitor a quantity of interest.
• The quantity of interest can fluctuate in time, this is an indication of unsteadiness.

668
Unsteady and steady simulations
What about steady simulations?
• First of all, steady simulations are a big simplification of reality.
• Steady simulations is a trick used by CFDers to get fast outcomes with results that might be
even more questionable.
• Remember, most of the flows you will encounter are unsteady so be careful of this hypothesis.
• In steady simulations, we made two assumptions:
• We ignore unsteady fluctuations. That is, we neglect the time derivative in the governing
equations.
• We perform time averaging when dealing with stationary turbulence (RANS modeling)
• The advantage of steady simulations is that they require low computational resources, give fast
outputs, and are easier to post-process and analyze.
• To do so, you need to use the appropriate solver and use the right discretization scheme.
• As you are not solving the time derivative, you do not need to set the time step. However, you
need to tell OpenFOAM® how many iterations you would like to run.
• You can also set the residual controls (residualControl), in the fvSolution dictionary file.
You set the residualControl in the SIMPLE sub-dictionary.
• If you do not set the residual controls, OpenFOAM® will run until reaching the maximum
number of iterations (endTime).
669
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
• In the controlDict dictionary you need to set runtime parameters and general instructions on
how to run the case (such as the number of iterations to run).
• Remember to set also the saving frequency.
• In the fvSchemes dictionary you need to set the time discretization scheme, for steady
simulations it must be steadyState.
• In the fvSolution dictionary you need to set the linear solvers, under-relaxation factors, and
residual controls.
• Also, you will need to set the number of corrections of the velocity-pressure coupling method
used (e.g. SIMPLE or SIMPLEC), this is done in the fvSolution dictionary.
• Additionally, you may set functionObjects in the controlDict dictionary.
• The functionObjects are used to do sampling, probing and co-processing while the simulation
is running.

670
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?

• The under-relaxation factors (URF) control the change of the variable .

• Under-relaxation is a feature typical of steady solvers using the SIMPLE family of methods.
• These are the URF commonly used with SIMPLE and SIMPLEC (industry standard),

SIMPLE SIMPLEC

p 0.3; p 1; Pressure Usually does not require under-relaxing

U 0.7; U 0.9;
k 0.7; k 0.9;
omega 0.7; omega 0.9;

• According to the physics involved you will need to add more under-relaxation factors.
• Finding the right URF involved experience and some trial and error.
• Selecting the URF it is kind of equivalent to selecting the right time step.
• Many times, steady simulations diverge because of wrongly chosen URF. 671
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?

• The URF are bounded between 0 and 1.


• If you set the URF close to one you increase the
convergence rate but loose solution stability.
• On the other hand, if you set the URF close to zero
you gain stability but reduce convergence rate.

• An optimum choice of under-relaxation factors is one that is small enough to ensure stable
computation but large enough to move the iterative process forward quickly.
• Under-relaxation can be implicit (equation in OpenFOAM) or explicit (field in OpenFOAM).

Implicit URF Explicit URF

• You can relate URF to the CFL number as follows,

• A small CFL number is equivalent to small URF. 672


Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?

ddtSchemes • The fvSchemes dictionary contains the information related to


{ time discretization and spatial discretization schemes.
default steadyState;
} • In this generic case and as we are interested in using a steady
gradSchemes
solver, we are using the steadyState method for time
{ discretization (ddtSchemes).
default Gauss linear;
grad(p) Gauss linear; • It is not a good idea to switch between steady and unsteady
} schemes on-the-fly.
divSchemes • For steady state cases, the bounded form can be applied to the
{ divSchemes, in this case, div(phi,U) bounded Gauss linear.
default none;
div(phi,U) bounded Gauss linear; • This adds a linearized, implicit source contribution to the
}
transport equation of the form,
laplacianSchemes
{
default Gauss linear orthogonal;
}

interpolationSchemes
{
default linear; • This term removes a component proportional to the continuity
}
error. This acts as a convergence aid to tend towards a bounded
snGradSchemes solution as the calculation proceeds.
{
default orthogonal; • At convergence, this term becomes zero and does not
} contribute to the final solution.
673
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?

startFrom latestTime; • The controlDict dictionary contains runtime simulation


controls, such as, start time, end time, time step, saving
startTime 0;
frequency and so on.
stopAt endTime;
• Most of the entries are self-explanatory.
endTime 10000;
• As we are doing a steady simulation, let us talk about iterations
deltaT 1; instead of time (seconds).

writeControl runTime; • This generic case starts from iteration 0 (startTime), and it will
run up to 10000 iterations (endTime).
writeInterval 100;
• It will write the solution every 100 iterations (writeInterval) of
purgeWrite 10; simulation time (runTime).
writeFormat ascii; • It will advance the solution one iteration at a time (deltaT).
writePrecision 8; • It will keep the last 10 saved solutions (purgeWrite).
writeCompression off; • It will save the solution in ascii format (writeFormat) with a
precision of 8 digits (writePrecision).
timeFormat general;
• And as the option runTimeModifiable is on (true), we can
timePrecision 6;
modify all these entries while we are running the simulation.
runTimeModifiable yes;

674
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
solvers • The fvSolution dictionary contains the instructions of how to
{
p
solve each discretized linear equation system.
{ • As for the controlDict and fvSchemes dictionaries, the
solver PCG;
preconditioner DIC; parameters can be changed on-the-fly.
tolerance 1e-06;
relTol 0; • To set these parameters, follow the guidelines given in the
} previous section.

U
• Increasing the number of nNonOrthogonalCorrectors
{ corrections will add more stability but at a higher computational
solver smoothSolver; cost.
smoother symGaussSeidel;
tolerance 1e-08; • Remember, nNonOrthogonalCorrectors is used to improve
relTol 0; the gradient computation due to mesh quality.
}
} • The SIMPLE sub-dictionary also contains convergence controls
based on residuals of fields. The controls are specified in the
SIMPLE
{
residualControls sub-dictionary.
nNonOrthogonalCorrectors 2;
• The user needs to specify a tolerance for one or more solved
residualControl fields and when the residual for every field falls below the
{ corresponding residual, the simulation terminates.
p 1e-4;
U 1e-4; • If you do not set the residualControls, the solver will iterate
} until reaching the maximum number of iterations set in the
}
controlDict dictionary.
675
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
• The fvSolution dictionary also contains the
relaxationFactors relaxationFactors sub-dictionary.
{
fields • The relaxationFactors sub-dictionary which controls under-
{ relaxation, is a technique used for improving stability when using
p 0.3;
}
steady solvers.
equations
{
• Under-relaxation works by limiting the amount which a variable
U 0.7; changes from one iteration to the next, either by modifying the
} solution matrix and source prior to solving for a field (equations
}
keyword) or by modifying the field directly (fields keyword).
• Under-relaxing the equations is also known as implicit under-
relaxation.
• Whereas, under-relaxing the fields is also known as explicit
under-relaxation.
• An optimum choice of under-relaxation factors is one that is
small enough to ensure stable computation but large enough to
move the iterative process forward quickly.
• In this case we are using the industry standard URF.
• Remember, URF are problem dependent.
• If you do not define URF, the solver will not under-relax.

676
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?

• To enable the consistent formulation of the SIMPLE method, you need to add the following
keywork to the SIMPLE sub-dictionary,

SIMPLE
{
Enabled/disabled consistent formulation of the
consistent yes; SIMPLE loop
nNonOrthogonalCorrectors 3;
}

• The following URF are recommended,


SIMPLE SIMPLEC
relaxationFactors relaxationFactors
{ {
fields fields
{ {
p 0.3; p 0.7;
} }
equations equations
{ {
U 0.7; U 0.7;
k 0.6; k 0.7;
omega 0.6; omega 0.7;
} }
} }
677
Unsteady and steady simulations
Steady simulations vs. Unsteady simulations
• Steady simulations require less computational power than unsteady simulations.
• They are also much faster than unsteady simulations.
• But sometimes they do not converge to the right solution.
• They are easier to post-process and analyze (you just need to take a look at the last saved
solution).
• You can use the solution of an unconverged steady simulation as initial conditions for an
unsteady simulation.
• Remember, steady simulations are not time accurate. Therefore is not a good idea to compute
a dominant frequency using steady simulations, e.g., vortex shedding frequency.

Steady solution QOI unsteady solution QOI

678
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

679
Understanding residuals
• Before talking about residuals, let us clarify something.
• When we talk about iterations in unsteady simulations, we are talking about the time-step or
outer-iterations.

1. To arrive to this physical time of the monitored QOI

2. We iterate this many times

3. And we iterate inside each time-step (or outer-


iteration), until reaching the linear solver tolerance
or maximum number of iterations.

680
Understanding residuals
• To get a better idea of how iterative methods work, and what are initial residuals and final residuals, let us
take another look at a residual plot.

• is the initial guess used to start the iterative solver.


• You can use any value at iteration 0, but usually is a good choice to take the previous solution vector.
• If the following condition is fulfilled (where r is the convergence criterion or tolerance), the linear solver will
stop iterating and will advance to the next time-step.
• By working in an iterative way, every single iteration is a better approximation of the previous iteration .
• Sometimes the linear solver might stop before reaching the predefined convergence criterion because it has reached the
maximum number of iterations, you should be careful of this because we are talking about unconverged iterations. 681
Understanding residuals
• This is a typical residual plot for an unsteady simulation. • This is a typical residual plot for a steady simulation.
• Ideally, the solution should converge at every time-step (final • In this case, the initial residuals are falling below the
residuals tolerance). convergence criterion (monotonic convergence), hence we
have reached a steady-state.
• If the solution is not converging, that is, the residuals are not
reaching the predefined final residual tolerance, try to reduce • In the solver does not reach the convergence criteria or the
the time-step size. residuals get stalled, it does not mean that the solution is
diverging, it is just an indication of unsteadiness and it
• The first time-steps the solution might not converge, this is
might be better to run using an unsteady solver.
acceptable.
• In comparison to unsteady solvers, steady solvers require
• Also, you might need to use a smaller time-step during the
less iterations to arrive to a converge solution, if they arrive.
first iterations to maintain solver stability.
• You can also increase the number of maximum inner
iterations.
• If the initial residuals fall bellow the convergence criterion, you
might say that you have arrived to a steady solution (the
exception rather than the rule).

Unsteady solution residuals Steady solution residuals

682
Understanding residuals
• Remember, residuals are not a direct indication that you are converging to the right solution.
• It is better to monitor a quantity of interest (QOI).
• And by the way, you should get physically realistic values.
• In this case, if you monitor the residuals you might get the impression that the simulation is diverging.
• Instead, if you monitor a QOI you will realize that there is an initial transient (long one by the way), then the
onset of an instability, and then a periodic behavior of the phenomenon.
• You should assess the convergence of the solution and compute the unsteady statistics in the time window
where the behavior of the QOI is periodic.
• To monitor the stability, you can check the minimum and maximum values of the field variables.
• If you have bounded quantities, check that you do not have over-shoots or under-shoots.

Residuals QOI

683
Understanding residuals
• This is the output of the residuals for all field • This is the output of the residuals for all field
variables of an unsteady case. variables of a steady case.
• Notice that at the beginning the residuals show a • The jumps are due to the changes in tolerance
monotonic behavior. introduced while running the simulation.
• Then, after a while the convergence rate changes. • As you can see, the residuals are falling in a
monotonic way.
• This not necessarily means that the solution is
diverging, it might be an indication of unsteadiness.

684
Understanding residuals
• This is the output of the aerodynamic • This is the output of the aerodynamic
coefficients for an unsteady case. coefficients for a steady case.

685
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

686
Boundary conditions and initial conditions
On the initial boundary value problem (IBVP)
• First of all, when we use a CFD solver to find the approximate solution of the governing
equations, we are solving an Initial Boundary Value Problem (IBVP).
• In an IBVP, we need to impose appropriate boundary conditions and initial conditions.
• No need to say that the boundary conditions and initial conditions need to be physically realistic.
• Boundary conditions are a required component of the numerical method, they tell the solver
what is going on at the boundaries of the domain.
• You can think of boundary conditions as source terms.
• Initial conditions are also a required component of the numerical method, they define the initial
state of the problem.

687
Boundary conditions and initial conditions
A few words about boundary conditions
• Boundary conditions (BC) can be divided into three fundamental mathematical types:
• Dirichlet boundary conditions: when we use this BC, we prescribe the value of a variable at the
boundary.
• Neumann boundary conditions: when we use this BC, we prescribe the gradient normal to the
boundary.
• Robin Boundary conditions: this BC is a mixed of Dirichlet boundary conditions and Neumann
boundary
• You can use any of these three boundary conditions in OpenFOAM®.
• During this discussion, the semantics is not important, that depends of how you want to call the BCs or how
they are named in the solver, i.e., in, inlet, inflow, velocity inlet, incoming flow and so on.
• Defining boundary conditions involves:
• Finding the location of the boundary condition in the domain.
• Determining the boundary condition type.
• Giving the required physical information.
• The choice of the boundary conditions depend on:
• Geometrical considerations.
• Physics involved.
• Information available at the boundary condition location.
• Numerical considerations.
• And most important, you need to understand the physics involved.
688
Boundary conditions and initial conditions
A few words about boundary conditions
• To define boundary conditions you need to know the location of the boundaries (where they are
in your mesh).
• You also need to supply the information at the boundaries.
• Last but not least important, you must know the physics involved.

689
Boundary conditions and initial conditions
A few words about initial conditions
• Initial conditions (IC) can be divided into two groups:
• Uniform initial conditions.
• Non-uniform initial conditions.

• For non-uniform IC, the value used can be obtained from:


• Another simulation (including a solution with • A mathematical function
different grid resolution).
• A potential solver. • Reduced order models.
• Experimental results.

• Defining initial conditions involves:


• Finding the location of the initial condition in the domain.
• Determining the initial condition type.
• Giving the required physical information.
• The choice of the initial conditions depend on:
• Geometrical considerations.
• Physics involved.
• Information available.
• Numerical considerations.
• And most important, you need to understand the physics involved. 690
Boundary conditions and initial conditions
A few words about initial conditions
• For initial conditions, you need to supply the initial information or initial state of your problem.
• This information can be a uniform value or a non-uniform value.
• You can apply the initial conditions to the whole domain or separated zones of the domain.
• Last but not least important, you must know the physics involved.

691
Boundary conditions and initial conditions
• Inlets and outlets boundary conditions:
• Inlets are for regions where inflow is expected; however, inlets might support outflow when
a velocity profile is specified.
• Pressure boundary conditions do not allow outflow at the inlets.
• Velocity specified inlets are intended for incompressible flows.
• Pressure and mass flow inlets are suitable for compressible and incompressible flows.
• Same concepts apply to outlets, which are regions where outflow is expected.

692
Boundary conditions and initial conditions
• Zero gradient (Neumann) and backflow boundary conditions:
• Zero gradient boundary conditions extrapolates the values from the domain. They require
no information.
• Zero gradient boundary conditions can be used at inlets, outlets, and walls.
• Backflow boundary conditions provide a generic outflow/inflow condition, with specified
inflow/outflow for the case of backflow.
• In the case of a backflow outlet, when the flux is positive (out of domain) it applies a
Neumann boundary condition (zero gradient), and when the flux is negative (into of
domain), it applies a Dirichlet boundary condition (fixed value).
• Same concept applies to backflow inlets.

693
Boundary conditions and initial conditions
• On the outlet pressure boundary condition
• Some combinations of boundary conditions are very stable, and some are less reliable.
• And some configurations are unreliable.
• Inlet velocity at the inlet and pressure zero gradient at the outlet. This combination
should be avoided because the static pressure level is not fixed.
• Qualitatively speaking, the results are very different.
• This simulation will eventually crash.

BCs 1. Inlet velocity and fixed outlet pressure BCs 2. Inlet velocity and zero gradient outlet pressure
www.wolfdynamics.com/wiki/BC/aniBC1.gif www.wolfdynamics.com/wiki/BC/aniBC2.gif

694
Boundary conditions and initial conditions
• On the outlet pressure boundary condition
• If you only rely on a QOI and the residuals, you will not see any major difference between
the two cases with different outlet pressure boundary condition.
• This is very misleading.
• However, when you visualize the solution you will realize that something is wrong. This is
a case where pretty pictures can be used to troubleshoot the solution.
• Quantitative speaking, the results are very similar.
• However, this simulation will eventually crash.

Residual plot for pressure Quantity of interest – Force coefficient on the body

695
Boundary conditions and initial conditions
• Symmetry boundary conditions:
• Symmetry boundary conditions are a big simplification of the problem. However, they help
to reduce mesh cell count.
• Have in mind that symmetry boundary conditions only apply to planar faces.
• To use symmetry boundary conditions, both the geometry and the flow field must be
symmetric.
• Mathematically speaking, setting a symmetry boundary condition is equivalent to zero
normal velocity at the symmetry plane, and zero normal gradients of all variables at the
symmetry plane.
• Physically speaking, they are equivalent to slip walls.

696
Boundary conditions and initial conditions
• Location of the outlet boundary condition:
• Place outlet boundary conditions as far as possible from recirculation zones or backflow
conditions, by doing this you increase the stability.
• Remember, backflow conditions requires special treatment.
Far enough so the flow can be
Possible backflow Might be OK
considered fully developed

697
Boundary conditions and initial conditions
• Domain dimensions (when the dimensions are not known):
• If you do not have any constrain in the domain dimensions, you can use as a general guideline the
dimensions illustrated in the figure below, where L is a reference length (in this case, L is the wing chord).
• The values illustrated in the figure are on the conservative side, nut if you want to play safe, multiply the
values by two or more.
• Always verify that there are no significant gradients normal to any of the boundaries patches. If there are,
you should consider increasing the domain dimensions.

698
Boundary conditions and initial conditions
A few considerations and guidelines
• Boundary conditions and initial conditions need to be physically realistic.
• Poorly defined boundary conditions can have a significant impact on your solution.
• Initial conditions are as important as the boundary conditions.
• A good initial condition can improve the stability and convergence rate.
• On the other hand, unphysical initial conditions can slow down the convergence rate or can cause divergence.
• You need to define boundary conditions and initials conditions for every single variable you are solving.
• Setting the right boundary conditions is extremely important, but you need to understand the physics.
• You need to understand the physics in order to set the right boundary conditions.
• Do not force the flow at the outlet, use a zero normal gradient for all flow variables except pressure. The solver
extrapolates the required information from the interior.
• Be careful with backward flow at the outlets (flow coming back to the domain) and backward flow at inlets
(reflection waves), they required special treatment.
• If possible, select inflow and outflow boundary conditions such that the flow either goes in or out normal to the
boundaries.
• At outlets, use zero gradient boundary conditions only with incompressible flows and when you are sure that the
flow is fully developed.
• Outlets that discharge to the atmosphere can use a static pressure boundary condition. This is interpreted as
the static pressure of the environment into which the flow exhausts.
699
Boundary conditions and initial conditions
A few considerations and guidelines
• Inlets that take flow into the domain from the atmosphere can use a total pressure boundary condition (e.g.
open window).
• Mass flow inlets produce a uniform velocity profile at the inlet.
• Pressure specified boundary conditions allow a natural velocity profile to develop.
• The required values of the boundary conditions and initial conditions depend on the equations you are solving,
and physical models used, e.g.,
• For incompressible and laminar flows you will need to set only the velocity and pressure.
• If you are solving a turbulent compressible flow you will need to set velocity, pressure, temperature and
the turbulent variables.
• For multiphase flows you will need to set the primitives variables for each phase. You will also need to
initialize the phases.
• If you are doing turbulent combustion or chemical reactions, you will need to define the species, reactions
and turbulent variables.
• Minimize grid skewness, non-orthogonality, growth rate, and aspect ratio near the boundaries. You do not want
to introduce diffusion errors early in the simulation, especially close to the inlets.
• Try to avoid large gradients in the direction normal to the boundaries and near inlets and outlets.
• That is to say, put your boundaries far away from where things are happening.

700
Boundary conditions and initial conditions
• OpenFOAM® distinguish between base type boundary conditions and numerical type
boundary conditions.

Base type boundary conditions Numerical type boundary conditions

• Base type boundary conditions are based on geometry • Numerical type boundary condition assigns the value to the
information (surface patches) or on inter-processor field variables in the given surface patch.
communication link (halo boundaries).
• Numerical type boundary conditions are defined in the field
• Base type boundary conditions are defined in the file variables dictionaries located in the directory 0 (e.g. U, p).
boundary located in the directory constant/polyMesh
• When we talk about numerical type boundary conditions, we
• The file boundary is automatically created when you are referring to Dirichlet, Neumann or Robin boundary
generate or convert the mesh. conditions.
• When you convert a mesh to OpenFOAM® format, you • You need to manually create the field variables dictionaries
might need to manually modify the file boundary. This is (e.g. 0/U, 0/p, 0/T, 0/k, 0/omega).
because the conversion utilities do not recognize the
boundary type of the original mesh. • Remember, if you forget to define a numerical boundary
condition, OpenFOAM® will complain and will tell you where
• Remember, if a base type boundary condition is missing, and what is the error.
OpenFOAM® will complain and will tell you where and what
is the error. • Also, if you misspelled something OpenFOAM® will complain
and will tell you where and what is the error.
• Also, if you misspelled something OpenFOAM® will complain
and will tell you where and what is the error

701
Boundary conditions and initial conditions
• The following base type and numerical type boundary conditions are constrained or paired.
• That is, the type needs to be same in the boundary dictionary and field variables dictionaries
(e.g. 0/U, 0/p, 0/T, 0/k, 0/omega).

Base type Numerical type

constant/polyMesh/boundary 0/U - 0/p - 0/T - 0/k - 0/omega (IC/BC)

cyclic cyclic
cyclicAMI cyclicAMI
empty empty
processor processor
symmetry symmetry
symmetryPlane symmetryPlane
wedge wedge

• These are known as constraint patches in OpenFOAM.


• To find a complete list and the source code location of these patches, go to the directory $WM_PROJECT_DIR and type in the
terminal:
• $> find . -type d -iname *constraint* 702
Boundary conditions and initial conditions
• The base type patch can be any of the boundary conditions available in OpenFOAM®.
• Mathematically speaking; they can be Dirichlet, Neumann or Robin boundary conditions.

Base type Numerical type

constant/polyMesh/boundary 0/U - 0/p - 0/T - 0/k - 0/omega (IC/BC)

advective
calculated
codedFixedValue
epsilonWallFunction
fixedValue
inletOutlet
movingWallVelocity
patch
rotatingWallVelocity
slip
supersonicFreeStream
totalPressure
zeroGradient
… and so on
Refer to the doxygen documentation or the source code for a list of all
numerical boundary conditions available.
703
Boundary conditions and initial conditions
• The wall base type boundary condition is defined as follows:

Base type Numerical type

constant/polyMesh/boundary 0/U 0/p

type fixedValue;
wall zeroGradient
value uniform (0 0 0);

• This boundary condition is not contained in the patch base type boundary conditions group,
because specialize modeling options can be used on this boundary condition.
• An example is turbulence modeling, where turbulence can be generated or dissipated at the
walls.

704
Boundary conditions and initial conditions
• To deal with backflow at outlets, you can use the following boundary condition:

Base type Numerical type

constant/polyMesh/boundary 0/U 0/p

type inletOutlet;
type fixedValue;
patch inletValue uniform (0 0 0);
value uniform 0;
value uniform (0 0 0);

• The inletValue keyword is used for the reverse flow.


• In this case, if flow is coming back into the domain it will use the value set using the keyword
inletValue. Otherwise it will use a zeroGradient boundary condition.
• For the turbulent variables (k, omega, epsilon, and so on), you can use inletOutlet type (pay
attention that these quantities are scalars).

705
Boundary conditions and initial conditions
• Typical boundary conditions are as follows (external aerodynamics),

Boundary type description Pressure Velocity Turbulence fields

Inlet face zeroGradient fixedValue fixedValue

Outlet face fixedValue inletOutlet inletOutlet

Wall face zeroGradient fixedValue Wall functions*

Symmetry face symmetry symmetry symmetry

Periodic face cyclic cyclic cyclic

Empty face (2D) empty empty empty

Slip wall slip slip slip

* Wall functions can be: kqWallFunction, omegaWallFunction, nutkWallFunction, and so on (next slide).

706
Boundary conditions and initial conditions
• Typical wall functions boundary conditions are as follows,

Field variable Wall functions – High RE Resolved BL – Low RE

nut nut(–)WallFunction* fixedValue 0 or a small number

k, q, R kqRWallFunction fixedValue 0 or a small number

zeroGradient or fixedValue 0 or
epsilon epsilonWallFunction
a small number

omegaWallFunction or
omega omegaWallFunction
fixedValue with a big number

zeta – fixedValue 0 or a small number

nuTilda – fixedValue 0 or a small number

* nutkAtmRoughWallFunction, nutkRoughWallFunction, nutkWallFunction, nutLowReWallFunction,


nutURoughWallFunction, nutUSpaldingWallFunction, nutUTabulatedWallFunction, nutUWallFunction, nutWallFunction.

707
Boundary conditions and initial conditions
• Finally, remember that the name of the base type boundary condition and the name of the
numerical type boundary condition needs to be the same, if not, OpenFOAM® will complain.
• Pay attention to this, specially if you are converting the mesh from another format.
• Also, do not use spaces of funny characters when assigning the names to the boundary
patches.
• The following names are consistent among all dictionary files,

Base type Numerical type

constant/polyMesh/boundary 0/U 0/p

inlet inlet inlet

top top top

cylinder cylinder cylinder

sym sym sym

708
Boundary conditions and initial conditions
• There is a plethora of boundary conditions implemented in OpenFOAM®.

• You can find the source code of the main numerical boundary conditions in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/fields/

• The wall boundary conditions for the turbulence models (wall functions), are located in the following directory:
• $WM_PROJECT_DIR/src/MomentumTransportModels/momentumTransportModels/derivedF
vPatchFields/wallFunctions

• To find all the boundary conditions implemented in OpenFOAM, go to the directory $WM_PROJECT_DIR and
type in the terminal,
• $> find . -type d -iname *fvPatch*

• $> find . -type d -iname *derivedFv*

• $> find . -type d -iname *pointPatch*

• To get more information about all the boundary conditions available in OpenFOAM® you can read the
Doxygen documentation.

• You can access the documentation online at this link http://cpp.openfoam.org/v8/


709
Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary
• For a generic case, the file boundary is divided as follows

3
(
movingWall

movingWall frontAndBack
{
type patch;
nFaces 20;
startFace 760;
}

fixedWalls

fixedWalls
fixedWalls
{
type wall;
nFaces 60;
startFace 780;
}

frontAndBack
{
type empty;
nFaces 800; frontAndBack
startFace 840;
}
fixedWalls

710
Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary
• For a generic case, the file boundary is divided as follows

3 Number of surface patches


( There must be 3 patches definition.

movingWall Name and type of the surface patches


{
type patch;
nFaces 20; • The name and type of the patch is given by the user.
startFace 760;
} • You can change the name if you do not like it. Do not
use strange symbols or white spaces.
fixedWalls
{ • You can also change the base type. For instance, you
type wall; can change the type of the patch movingWall from
nFaces 60; patch to wall.
startFace 780;
} • When converting the mesh from a third-party format,
OpenFOAM® will try to recover the information from
frontAndBack the original format. But it might happen that it does not
{
type empty;
recognize the base type and name of the original
nFaces 800; format. If that is your case, you will need to modify the
startFace 840; file manually or using any of the mesh manipulation
} utilities distributed with OpenFOAM®.

) nFaces and startFace keywords


• Unless you know what are you doing, you do not
need to change this information.
711
Boundary conditions and initial conditions
The 0/U dictionary
• For a generic case, the numerical type BC are assigned as follows (U),

movingWall
dimensions [0 1 -1 0 0 0 0]; type fixedValue;
value uniform (1 0 0);
internalField uniform (0 0 0);

boundaryField frontAndBack
{ type empty;

value uniform (0 0 0);


movingWall
{

type fixedValue;
type fixedValue;

value uniform (0 0 0);


value uniform (1 0 0);
}

fixedWalls
type fixedValue;
fixedWalls
{
fixedWalls

type fixedValue;
value uniform (0 0 0);
}

frontAndBack
{ frontAndBack
type empty;
type empty;
}
}
fixedWalls
type fixedValue;
value uniform (0 0 0);

712
Boundary conditions and initial conditions
The 0/p dictionary
• For a generic case, the numerical type BC are assigned as follows (p),

dimensions [0 2 -2 0 0 0 0]; movingWall


type zeroGradient;
internalField uniform 0;

boundaryField frontAndBack
{ type empty;

type zeroGradient;
movingWall
{
type zeroGradient;
}

type zeroGradient;

fixedWalls
fixedWalls
{
type zeroGradient; fixedWalls
}

frontAndBack
{
type empty;
} frontAndBack
}
type empty;

fixedWalls
type zeroGradient;

713
Roadmap

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Linear solvers in OpenFOAM®
4. Pressure-Velocity coupling in OpenFOAM®
5. Unsteady and steady simulations
6. Understanding residuals
7. Boundary and initial conditions
8. Numerical playground

714
Numerical playground

Merry-go-round:
Pure convection of a passive scalar in a vector
field – One dimensional tube.

715
Numerical playground
• This is a visual and mental exercise only.

• You will find this case in the directory

$PTOFC/101FVM/pureConvection/orthogonal_1d

• In this directory, you will also find the README.FIRST file with the
instructions of how to run the case.

• Hereafter, we will focus our eyes to train our brain.

716
Numerical playground
Pure convection of a scalar in a vector field – One dimensional tube.

U = zeroGradient
T = zeroGradient

U = (1 0 0) U = zeroGradient
T=1 T = zeroGradient

(0 0 0) (1 0 0)
U = zeroGradient
T = zeroGradient

Initial conditions
U = (1 0 0)
T=0

717
Numerical playground
• This problem has an exact solution in the form of a traveling wave.
• We will use this case to study the different discretization schemes implemented in
OpenFOAM®.
• In the figure, we show the solution for time = 0.5 s

www.wolfdynamics.com/wiki/pureconvection/xani1.gif

www.wolfdynamics.com/wiki/pureconvection/xani2.gif

718
Numerical playground
Comparison of different spatial discretization schemes. Comparison of different spatial discretization schemes.
Euler in time – 100 cells – CFL = 0.1 Euler in time – 100 cells – CFL = 0.1
Linear limiter functions on the Sweby diagram. Non-linear limiter functions on the Sweby diagram.

719
Numerical playground
Comparison of different gradient limiters. Comparison of different gradient limiters.
Linear upwind in space – Euler in time – 100 cells – Linear upwind in space – Euler in time – 100 cells –
CFL 0.1 CFL 0.1

720
Numerical playground
Comparison of different time discretization schemes Comparison of Crank Nicolson blending factor using
and gradient limiters. cellLimited leastSquares 0.5 gradient limiter.
Linear upwind in space – 100 cells – CFL 0.1 Linear upwind in space – 100 cells – CFL 0.1

721
Numerical playground
Comparison of different time-step size (different CFL Comparison of different mesh sizes.
number). Linear upwind in space – Euler in time
Linear upwind in space – Euler in time – 100 cells

722
Numerical playground
• This case was for your eyes and brain only, but we encourage you to reproduce all the previous
results,
• Use all the time discretization schemes.
• Use all the spatial discretization schemes.
• Use all the gradient discretization schemes.
• Use gradient limiters.
• Use different mesh resolution.
• Use different time-steps.

• Sample the solution and compare the results.


• Try to find the best combination of numerical schemes.
• Remember, in the README.FIRST file you will find the instructions of
how to run the case.

723
Numerical playground
Exercises
• Which one of the following schemes is useless: upwind, downwind, or linear
• Compare the solution obtained with the following schemes: upwind, linearUpwind, MUSCL, QUICK, cubic,
UMIST, OSHER, Minmod, vanAlbada. Are all of them bounded? Are they second order accurate?
• Use the linearUpwind method with Gauss linear, Gauss pointLinear and leastSquares for gradient
computations, which method is more accurate?
• Imagine that you are using the linearUpwind method with no gradient limiters. How will you stabilize the
solution if it becomes unbounded?
• When using gradient limiters, what is clipping?
• Use the linearUpwind with different gradient limiters. Which method is more unbounded?
• Use the vanLeer method with a CFL number of 0.1, 0.9 and 2, did all solutions converge? Are both solutions
bounded?
• In the directory tri_mesh, you will find the same case setup using a triangular mesh.
• Run the case and compare the solution with the equivalent setup using the orthogonal mesh.
• Repeat the same experiments as before and draw your conclusions about which method is better
for unstructured meshes.
• With unstructured meshes, is it possible to get the same accuracy level as for orthogonal meshes?

724
Numerical playground
Exercises
• The solver scalarTransportFoam does not report the CFL number on the screen. How will you compute
the CFL number in this case?
(Hint: you can take a look at the post-processing slides or the utilities directory)
• Which one is more diffusive, spatial discretization or time discretization?
• Are all time discretization schemes bounded?
• If you are using the Crank-Nicolson scheme, how will you avoid oscillations?
• Does the solution improve if you reduce the time-step?
• Use the upwind scheme and a really fine mesh. Does the accuracy of the solution improve?
• From a numerical point of view, what is the Peclet number? Can it be compared to the Reynolds number?

• If the Peclet number is more than 2, what will happen with your solution if you were using a linear scheme?
(Hint: to change the Peclet number you will need to change the diffusion coefficient)
• Pure convection problems have analytical solutions. You are asked to design your own tutorial with an
analytical solution in 2D or 3D.
• Try to break the solver using a time step less than 0.005 seconds. You are allowed to modify the original mesh
and use any combination of discretization schemes.
725
Numerical playground

Slide:
2D Laplace equation in a square domain.

726
Numerical playground
• This is a visual and mental exercise only.

• You will find this case in the directory

$PTOFC/101FVM/laplace

• In this directory, you will also find the README.FIRST file with the
instructions of how to run the case.

• Hereafter, we will focus our eyes to train our brain.

727
Numerical playground
2D Laplace equation in a square domain

728
Numerical playground
2D Laplace equation in a square domain
• This case consist of one domain and three different element types.

Domain

Detailed section view

Hexahedral mesh Triangular mesh Polyhedral mesh 729


Numerical playground
2D Laplace equation in a square domain

• We will study the influence of the element type on the gradients computation.
• We will also study the influence of the gradSchemes method and laplacianSchemes
method on the solution.

This problem has the following


analytical solution:

730
Numerical playground
2D Laplace equation in a square domain

A B gradSchemes:
Gauss linear

laplacianSchemes:
Gauss linear orthogonal

A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh

• This is the actual solution.


• Each mesh gives basically the
same solution.
• However, when we look at the
information behind the field T, we
will see a different outcome.
• Precisely, we will take a look at
the gradients.

T field
731
Numerical playground
2D Laplace equation in a square domain

A B gradSchemes:
Gauss linear

laplacianSchemes:
Gauss linear orthogonal

A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh

• This is not the actual solution.


This is the gradient of the field T
used to compute the solution.
• The outcome is different for each
mesh.
• Behind doors, the gradients need
to be computed accurately.
• For the method used in this case,
the gradients on the unstructured
meshes are noisy.
field
732
Numerical playground
2D Laplace equation in a square domain

A B gradSchemes:
Gauss linear

laplacianSchemes:
Gauss linear limited 1

A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh

• This is not the actual solution.


This is the gradient of the field T
used to compute the solution.
• The outcome is different for each
mesh.
• Behind doors, the gradients need
to be computed accurately.
• By adjusting the numerics, we
can smooth the gradients.

field • All meshes show similar


gradients.
733
Numerical playground
2D Laplace equation in a square domain

A B gradSchemes:
Gauss leastSquares

laplacianSchemes:
Gauss linear orthogonal

A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh

• This is not the actual solution.


This is the gradient of the field T
used to compute the solution.
• The outcome is different for each
mesh.
• Behind doors, the gradients need
to be computed accurately.
• For the method used in this case,
the gradients on the unstructured
meshes are noisy.
field
734
Numerical playground
2D Laplace equation in a square domain

A B gradSchemes:
Gauss leastSquares

laplacianSchemes:
Gauss linear limited 1

A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh

• This is not the actual solution.


This is the gradient of the field T
used to compute the solution.
• The outcome is different for each
mesh.
• Behind doors, the gradients need
to be computed accurately.
• By adjusting the numerics, we
can smooth the gradients.

field • All meshes show similar


gradients.
735
Numerical playground
• This case was for your eyes and brain only, but we encourage you to reproduce all the previous
results.
• In the subdirectory c1 you will find the hexahedral mesh, in the subdirectory c2 you will find the
triangular mesh, and in the subdirectory c3 you will find the polyhedral mesh.
• Use the script runallcases.sh to run all the cases automatically.
• When launching paraFoam it will give you a warning, accept the default option (yes).
• In paraFoam, go to the File menu and select Load State. Load the state located in the
directory paraview (state1.pvsm).
• In the window that pops out, give the location of the *.foam files inside each subdirectory
(c1/c1.foam, c2/c2.foam, and c3/c3.foam).
• The file state1.pvsm will load a preconfigured state with all the solutions.
• If you are interested in running the cases individually, enter the subdirectory
and follow the instructions in the README.FIRST file.

736
Numerical playground
Exercises
• Run the case using all gradient discretization schemes available. Which scheme gives the best results?
• According to the previous results, which element type is the best one? Do you think that the choice of the
element type is problem dependent (e.g., direction of the flow)?
• Use the leastSquares method for gradient discretization, and the corrected and uncorrected method for
Laplacian discretization. Do you get the same results in all the meshes? How can you improve the results?
(Hint: look at the corrections)
• Does it make sense to do more non-orthogonal corrections using the uncorrected method?
• Run a case only 1 iteration. Do you get a converged solution? Is there a difference between 1 and 100
iterations? Compare the solutions.
• Use a different interpolation method for the diffusion coefficient. Do you get the same results?
• Try to break the solver (this is a difficult task in this case). You are allowed to modify the original mesh and
use any combination of discretization schemes.

737
Numerical playground

Swing:
Flow in a lid-driven square cavity – Re = 100
Effect of grading and non-orthogonality on the
accuracy of the solution

738
Numerical playground
Flow in a lid-driven square cavity – Re = 100
Non-orthogonal mesh vs. orthogonal mesh

Non-orthogonal mesh Orthogonal mesh


The overall quality of this mesh is good (in This is a perfect mesh
terms of non-orthogonality and skewness),
but by no standard this is a good mesh.

• Often people refer to these non-orthogonal meshes as Kershaw distorted meshes.


• We will use this case to learn how to adjust the numerical schemes according to mesh non-
orthogonality and grading.
739
Numerical playground
LaplacianSchemes orthogonal – Non-orthogonal corrections disabled
Y centerline

• And as CFD is not only about pretty colors, we should also validate
the results
X centerline

High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 740
Numerical playground
LaplacianSchemes orthogonal – Non-orthogonal corrections enabled
Y centerline

• And as CFD is not only about pretty colors, we should also validate
the results
X centerline

High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 741
Numerical playground
How to adjust the numerical method to deal with non-orthogonality
ddtSchemes • In the dictionary fvSchemes we can enable non-
{
default backward; orthogonal corrections.
}
• Non-orthogonal corrections are chosen using the
gradSchemes
{ keywords laplacianSchemes and snGradSchemes.
default Gauss linear;
//default Gauss skewCorrected linear; • These are the laplacianSchemes and
//default cellMDLimited Gauss linear 1;
grad(p) Gauss linear; snGradSchemes schemes that you will use most of the
}
times:
divSchemes
{ • orthogonal: second order accurate, bounded on
default
//div(phi,U)
none;
Gauss linearUpwind default;
perfect meshes, without non-orthogonal
div(phi,U) Gauss linear; corrections.
}
• corrected: second order accurate, bounded
laplacianSchemes
{ depending on the quality of the mesh, with non-
default
//default
Gauss linear orthogonal;
Gauss linear limited 1;
orthogonal corrections.
//default Gauss skewCorrected linear limited 1;
} • limited : second order accurate, bounded
interpolationSchemes
depending on the quality of the mesh, with non-
{ orthogonal corrections.
//default skewCorrected linear;
default linear; • uncorrected: second order accurate, without
}
non-orthogonal corrections. Stable but more
snGradSchemes
{
diffusive than limited and corrected.
default orthogonal;
//default limited 1;
}

742
Numerical playground
How to adjust the numerical method to deal with non-orthogonality
solvers • Additionally, in the dictionary fvSolution we need to
{
p define the number of PISO corrections (nCorrectors) and
{ non-orthogonal corrections (nNonOrthogonalCorrectors).
solver PCG;
preconditioner DIC;
tolerance 1e-06;
• You need to do at least one PISO correction. Increasing the
relTol 0; number of PISO correctors will improve the stability and
}
accuracy of the solution at a higher computational cost.
pFinal
{ • For orthogonal meshes, 1 PISO correction is ok. But as
$p;
relTol 0; most of the time you will deal with non-orthogonal meshes,
} doing 2 PISO corrections is a good choice.
U
{ • If you are using a method with non-orthogonal corrections
solver
smoother
smoothSolver;
symGaussSeidel;
(corrected or limited 1-0.5), you need to define the number
tolerance 1e-08; of non-orthogonal corrections (nNonOrthogonalCorrectors).
relTol 0;

}
}
• If you use 0 nNonOrthogonalCorrectors, you are
computing the initial approximation using central differences
PISO
{ (accurate but unstable), with no explicit correction.
nCorrectors 1;
nNonOrthogonalCorrectors 0; • To take into account the non-orthogonality of the mesh, you
pRefCell 0;
pRefValue 0; will need to increase the number of corrections (you get
} better approximations using the previous correction).
• Usually 2 nNonOrthogonalCorrectors is ok.

743
Numerical playground
• We will now illustrate a few of the discretization schemes available in OpenFOAM®
using a model case.
• We will use the lid-driven square cavity case to study the effect of grading and non-
orthogonality on the accuracy of the solution
• This case is located in the directory:

$PTOFC/101FVM/nonorthoCavity/

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
744
Numerical playground
What are we going to do?
• This is the same case as the one we used during the first tutorial session.
• The only difference is that we have modified the mesh a little bit in order to add grading and non-orthogonality.
• After generating the mesh, we will use the utility checkMesh to control the quality of the mesh. Is it a good
mesh?
• We will use this case to learn how to adjust the numerical schemes according to mesh non-orthogonality and
grading.
• After finding the numerical solution we will do some sampling and plotting.

Running the case


• You will find this tutorial in the directory $PTOFC/101FVM/nonorthoCavity
• In the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh –dict system/blockMeshDict.0
3. $> checkMesh
4. $> pisoFoam | log.solver
5. $> postProcess -func sampleDict -latestTime
6. $> gnuplot gnuplot/gnuplot_script
7. $> paraFoam
745
Numerical playground
To run the case, follow these steps
• First run the case using the original dictionaries. Did it crash right?
• Now change the laplacianSchemes and snGradSchemes to limited 1. It crashed again but
this time it ran a few more time-steps, right?
• Now increase the number of nNonOrthogonalCorrectors to 2. It crashed again but it is running
more time-steps, right?
• Now increase the number of PISO corrections to 2 (nCorrectors). Did it run?
• Basically we enabled non-orthogonal corrections, we computed better approximations of the
gradients, and we increased the number of PISO corrections to get better predictions of the field
variables (U and p).
• Now set the number of nNonOrthogonalCorrectors to 0. Did it crash right? This is telling us
that the mesh is sensitive to the gradients.
• Now change the laplacianSchemes and snGradSchemes to limited 0 (uncorrected). In this
case we are not using non-orthogonal corrections, therefore there is no need to increase the
value of nNonOrthogonalCorrectors.
• We are using a method that uses a wider stencil to compute the Laplacian, this method is more
stable but a little bit more diffusive. Did it run?
• At this point, compare the solution obtained with corrected and uncorrected schemes. Which
one is more diffusive?
746
Numerical playground
• When it comes to laplacianSchemes and snGradSchemes this is how we proceed most of
the times (a robust setup),

laplacianSchemes
{
default Gauss linear limited 1; PISO
} {
nCorrectors 2;
snGradSchemes nNonOrthogonalCorrectors 1;
{ }
default limited 1;
}

• This method works fine for meshes with non-orthogonality less than 75.
• If the non-orthogonality is more than 75, you should consider using limited 0.5, and increasing
nCorrectors and nNonOrthogonalCorrectors.
• When the non-orthogonality is more than 85, the best solution is to redo the mesh.

747
Numerical playground
Exercises
• Using the non-orthogonal mesh and the original dictionaries, try to run the solver reducing the time-step. Do
you get a solution at all?
• Try to get a solution using the method limited 1 and two nNonOrthogonalCorrectors (leave nCorrectors
equal to 1).
(Hint: try to reduce the time-step)
• If you managed to get a solution using the previous numerical scheme. How long did it take to get the
solution? Use the robust setup, clock the time and compare with the previous case. Which one is faster? Do
you get the same solution?
• Instead of using the non-orthogonal mesh, use a mesh with grading toward all edges. How will you stabilize
the solution?
(Hint: take a look at the blockMesh slides in order to add grading to the mesh)
• Try to get a solution using a time-step of 0.05 seconds. Use the original discretization schemes for the gradient
and convective terms.
(Hint: increase nCorrectors and nNonOrthogonalCorrectors)
• Using the uniform orthogonal mesh and a robust numerics, determined the largest CFL you can use. Is the
solution still accurate? What about the clock-speed?
• Try to break the solver and interpret the output screen. You are allowed to modify the original mesh and use
any combination of discretization schemes.

748
Numerical playground

Seesaw:
Sod’s shock tube.

749
Numerical playground
Sod’s shock tube
• This case has an analytical solution and plenty of experimental data.
• This is an extreme test case used to test solvers.
• Every single commercial and open source solver use this case for validation of the numerical
schemes.
• The governing equation of this test case are the Euler equations.

750
Numerical playground
High Purity Photolysis Shock Tube (NASA Tube)

Shock tube. The driver section, including vacuum pumps, controls, and helium driver gas.
Photo credit: Stanford University. http://hanson.stanford.edu/index.php?loc=facilities_nasa
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose. 751
Numerical playground
Sod’s shock tube

All walls are slip

Boundary conditions and initial conditions Analytical solution

752
Numerical playground
Sod’s shock tube

Pressure field Density field

Velocity magnitude field Temperature field


753
Numerical playground

• We will now illustrate a few of the discretization schemes available in OpenFOAM®


using a severe model case.
• We will use the Sod’s shock tube case.
• This case is located in the directory:

$PTOFC/101FVM/shockTube/

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
754
Numerical playground
What are we going to do?
• Now is your turn.
• You are asked to select the best discretization scheme for the physics involve.
• Remember the following concepts: accuracy, stability and boundedness.
• We will compare your numerical solution with the analytical solution.
• At this point, we are very familiar with the numerical schemes. It is up to you to choose the best
setup.
• You can start using the original dictionaries.
• To find the numerical solution we will use the solver rhoPimpleFoam.
• rhoPimpleFoam is a transient solver for laminar or turbulent flow of a compressible gas.
• After finding the numerical solution we will do some sampling.
• At the end, we will do some plotting (using gnuplot or Python) and scientific visualization.

755
Numerical playground
Running the case
• You will find this tutorial in the directory $PTOFC/101FVM/schockTube
• In the terminal window type:

1. $> foamCleanTutorials
2. $> blockMesh
3. $> checkMesh
4. $> rm –rf 0
5. $> cp –r 0_org 0
6. $> setFields
7. $> rhoPimpleFoam | tee log.solver
8. $> postProcess -func sampleDict -latestTime
9. $> paraFoam

• To plot the analytical solution against the numerical solution, go to the directory python and run the Python script.
• In the terminal window type:

1. $> python3 python/sodshocktube.py

• The Python script will save four .png files with the solution. Feel free to explore and adapt the Python script to your needs.
• Python (version 3) must be installed in order to use the script

756
Numerical playground
Running the case
• If you used the values proposed in the dictionaries, the solution diverged, right? Try to get the
case working.
Hint: look at the gradient limiters.
• By adjusting the gradient limiters, the case will run, but the final solution is not very accurate.
How can you increase the accuracy of the solution?
Hint: look at the PIMPLE corrections.

Not so accurate solution Accurate solution

757
Numerical playground
Exercises
• Using the proposed case setup, try to get an accurate solution by reducing the time-step or refining the mesh.
Did you succeed in getting an accurate solution?
• Run the case using different time discretization schemes.
• Run the case using different gradient discretization schemes.
• Run the case using different convective discretization schemes for the term div(phi,U).
• Run the case using different convective discretization schemes for the terms div(phi,e) and div(phi,K). What
are the variables e and K?
• Extend the case to 2D and 3D. Do you get the same solution?
• Try to run a 2D case using a triangular mesh and adjust the numerical scheme to get an accurate and stable
solution.
• Try to run the 1D case using an explicit solver. For the same CFL number, do you have the same time step
size as for the implicit solver?
(Hint: look for the solver with the word Central)
• Try to break the solver (this is extremely easy in this case). You are allowed to modify the original mesh and
use any combination of discretization schemes.

758
Module 7
Highlights – Implementing boundary
conditions and initial conditions using
codeStream

759
Roadmap

1. codeStream – Highlights
2. Implementing boundary conditions using
codeStream
3. Solution initialization using codeStream

760
codeStream – Highlights
codeStream – Boundary conditions
• There are many boundary conditions available in OpenFOAM®.
• But from time to time it may happen that you do not find what you are looking for.
• It is possible to implement your own boundary conditions, so in theory you can do whatever you
want.
• Remember, you have the source code.
• To implement your own boundary conditions, you have three options:
• Use codeStream.
• Use high level programing.
• Use an external library (e.g., swak4foam).
• codeStream is the simplest way to implement boundary conditions, and most of the times you
will be able to code boundary conditions with no problem.
• If you can not implement your boundary conditions using codeStream, you can use high level
programming. However, this requires some knowledge on C++ and OpenFOAM® API.
• Hereafter, we are going to work with codeStream and basic high-level programming.
• We are not going to work with swak4Foam because it is an external library that is not officially
supported by the OpenFOAM® foundation. However, it works very well and is relatively easy to
use. 761
codeStream – Highlights
codeStream – Initial conditions
• When it comes to initial conditions, you can use the utility setFields.
• This utility is very flexible, you can even read STL files and use them to initialize fields.
• But again, it may happen that you can not get the desired results.
• As for boundary conditions, to implement your own initials conditions you have three options:
• Use codeStream.
• Use high level programing.
• Use an external library (e.g., swak4foam).
• codeStream is the simplest way to implement initial conditions, and most of the times you will
be able to code initial conditions with no problem.
• If you can not implement your initial conditions using codeStream, you can use high level
programming. However, this requires some knowledge on C++ and OpenFOAM® API.
• Hereafter, we are going to work only with codeStream.
• Using high level programming is a little bit trickier, and we guarantee you that 99.9% of the times
codeStream will work.
• We are not going to work with swak4Foam because it is an external library that is not officially
supported by the OpenFOAM® foundation. However, it works very well and is relatively easy to
use. 762
codeStream – Highlights
• Hereafter we will work with codeStream, which will let us program directly in the input
dictionaries.
• With codeStream, we will implement our own boundary conditions and initial conditions without
going thru the hustle and bustle of high-level programming.
• If you are interested in high level programming, refer to the supplements.
• In the supplemental slides, we address the following topics:
• Building blocks, implementing boundary conditions using high level programming,
modifying applications, implementing an application from scratch, and adding the
scalar transport equation to icoFoam.
• High level programming requires some knowledge on C++ and OpenFOAM® API library.
• This is the hard part of programming in OpenFOAM®.
• Before doing high level programming, we highly recommend you try with codeStream, most of
the time it will work.
• Also, before modifying solvers or trying to implement your own solvers, understand the theory
behind the FVM.
• Remember, you can access the API documentation in the following link,
https://cpp.openfoam.org/v8

763
Roadmap

1. codeStream – Highlights
2. Implementing boundary conditions using
codeStream
3. Solution initialization using codeStream

764
Implementing boundary conditions using codeStream
• OpenFOAM® includes the capability to compile, load and execute C++ code at run-time.
• This capability is supported via the directive #codeStream, that can be used in any input file for
run-time compilation.
• This directive reads the entries code (compulsory), codeInclude (optional), codeOptions
(optional), and codeLibs (optional), and uses them to generate the dynamic code.
• The source code and binaries are automatically generated and copied in the directory
dynamicCode of the current case.
• The source code is compiled automatically at run-time.
• The use of codeStream is a very good alternative to avoid high level programming of boundary
conditions or the use of external libraries.
• Hereafter we will use codeStream to implement new boundary conditions.
• Have in mind that codeStream can be used in any dictionary.

765
Implementing boundary conditions using codeStream
Body of the codeStream directive for boundary conditions
patch-name Patch name
{
type fixedValue;
value #codeStream
Use codeStream to set the value
{ of the boundary condition
codeInclude
#{
#include "fvCFD.H" Files needed for compilation
#};

codeOptions
#{
-I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
#};

codeLibs Libraries needed for compilation.


#{
-lmeshTools \
Needed if you want to visualize the
-lfiniteVolume output of the boundary condition
#}; at time zero

code
#{ Insert your code here.
At this point, you need to know
#}; how to access mesh information
};
}
766
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream
• Let us implement a parabolic inlet profile.
• The firs step is identifying the patch, its location and the dimensions.
• You can use paraview to get all visual references.

Outlet
pressure-outlet-7

Inlet
velocity-inlet-5

Inlet
velocity-inlet-6 Bounds of velocity-inlet-5 boundary patch
Parabolic inlet profile 767
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream
• We will use the following formula to implement the parabolic inlet profile

• For this specific case c is the patch midpoint in the y direction (8), r is the patch semi-height or
radius (8) and Umax is the maximum velocity.
• We should get a parabolic profile similar to this one,

768
Implementing boundary conditions using codeStream
• The codeStream BC in the body of the file U is as follows,

velocity-inlet-5 Patch name


{
type fixedValue;
value #codeStream
{
codeInclude
#{
#include "fvCFD.H"
#};
Depending of what are you trying
codeOptions to do, you will need to add new
#{ files, options and libraries.
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude For most of the cases, this part is
#};
always the same.
codeLibs
#{
-lmeshTools \
-lfiniteVolume
#};

code
#{ Insert your code here.
At this point, you need to know
#}; how to access mesh information
};
}
769
Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows,

To access boundary mesh information


1 code
2 #{
3 const IOdictionary& d = static_cast<const IOdictionary&>
4 (
5 dict.parent().parent()
6 );
7
8 const fvMesh& mesh = refCast<const fvMesh>(d.db());
9 const label id = mesh.boundary().findPatchID("velocity-inlet-5");
10 const fvPatch& patch = mesh.boundary()[id];
11
12 vectorField U(patch.size(), vector(0, 0, 0));
13
14 ...
15 ... Remember to update this value with the
16 ...
actual name of the patch
17 #};

• Lines 3-11, are always standard, they are used to access boundary mesh information.
• In lines 3-6 we access the current dictionary.
• In line 8 we access the mesh database.
• In line 9 we get the label id (an integer) of the patch velocity-inlet-5 (notice that you need to give the name of
the patch).
• In line 10 using the label id of the patch, we access the boundary mesh information.
• In line 12 we initialize the vector field. The statement patch.size() gets the number of faces in the patch, and
the statement vector(0, 0, 0) initializes a zero-vector field in the patch. 770
Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows,

1 code Index used to access the


2 #{ y coordinate
3 ... 0→x
4 ...
5 ...
1→y
6 const scalar pi = constant::mathematical::pi; 2→z
7 const scalar U_0 = 2.; //maximum velocity
8 const scalar p_ctr = 8.; //patch center
9 const scalar p_r = 8.; //patch radius
10
11 forAll(U, i) //equivalent to for (int i=0; patch.size()<i; i++)
12 {
13 const scalar y = patch.Cf()[i][1];
14 U[i] = vector(U_0*(1-(pow(y - p_ctr,2))/(p_r*p_r)), 0., 0.);
15 }
16 Assign input profile to vector field U (component x)
17 writeEntry(os, "", U);
18 #};

• In lines 6-17 we implement the new boundary condition.


• In lines 6-9 we declare a few constants needed in our implementation.
• In lines 11-15 we use a forAll loop to access the boundary patch face centers and to assign the velocity profile
values. Notice the U was previously initialized.
• In line 13 we get the y coordinates of the patch faces center.
• In line 14 we assign the velocity value to the patch faces center.
• In line 17 we write the U values to the dictionary. 771
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh

3 $> checkMesh
4. $> rm –rf 0
5. $> cp –r 0_org 0
6. $> pisoFoam | tee log.solver
7. $> paraFoam

• The codeStream boundary condition is implemented in the file 0/U.


• FYI, you can run in parallel with no problem.
772
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream
• If everything went fine, you should get something like this,

773
Implementing boundary conditions using codeStream
codeStream works with scalar and vector fields
• We just implemented the input parabolic profile using a vector field.
• You can do the same using a scalar field, just proceed in a similar way.
• Remember, now we need to use scalars instead of vectors.
• And you will also use an input dictionary holding a scalar field.

1 code
2 #{
3 ...
4 ...
5 ...
6 scalarField S(patch.size(), scalar(0) ); Initialize scalar field
7
8 forAll(S, i) Loop using scalar field size
9 {
10 const scalar y = patch.Cf()[i][1];
11 S[i] = scalar( 2.0*sin(3.14159*y/8.) );
Write profile values
12 } in scalar field
13
14 writeEntry(os, "", S);
Write output to input
15 #}; dictionary

Notice that the name of the field does not need to be the same as the name of the input dictionary
774
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• Let us work in a case a little bit more complicated, a paraboloid input profile.
• As usual, the first step is to get all the spatial references.

Inlet
auto3

Bounds of auto3 boundary patch


Paraboloid inlet profile
775
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• We will implement the following equation in the boundary patch auto3.

776
Implementing boundary conditions using codeStream
• The codeStream BC in the body of the file U is as follows,

auto3 Patch name


{
type fixedValue;
value #codeStream
{
codeInclude
#{
#include "fvCFD.H"
#};
For most of the cases, this part is
codeOptions always the same. But depending of
#{
what are you trying to do, you will
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude need to add more files, options and
#}; libraries.

codeLibs
#{
-lmeshTools \
-lfiniteVolume
#};
Insert your code here.
code
#{
We will implement the following
equation
#};
};
}
777
Implementing boundary conditions using codeStream
• Hereafter, we only show the actual implementation of the codeStream boundary condition.
• The rest of the body is a template that you can always reuse. Including the section of how to
access the dictionary and mesh information.
• Remember, is you are working with a vector, you need to use vector fields. Whereas, if you are
working with scalars, you need to use scalars fields.

1 code
2 #{
3 ...
4 ...
5 ...
6 vectorField U(patch.size(), vector(0, 0, 0) );
7
8 const scalar s = 0.5; Initialize vector field
9
10 forAll(U, i) Initialize scalar
11 {
12 const scalar x = patch.Cf()[i][0];
Access faces center
13 const scalar y = patch.Cf()[i][1];
14 const scalar z = patch.Cf()[i][2]; coordinates (x, y, and z)
15
16 U[i] = vector(-1.*(pow(z/s, 2) + pow((y-s)/s,2) - 1.0), 0, 0);
17 }
18
19 writeEntry(os, "", U);
20 #};

778
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/3Delbow_Uparaboloid/
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> gmshToFoam ../../../meshes_and_geometries/gmsh_elbow3d/geo.msh

3. $> autoPatch 75 -overwrite


4. $> createPatch -overwrite
5. $> renumberMesh -overwrite
6. $> rm –rf 0
7. $> cp –r 0_org 0
8. $> pisoFoam | tee log.solver
9. $> paraFoam

• The codeStream boundary condition is implemented in the file 0/U.


• FYI, you can run in parallel with no problem. 779
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• If everything went fine, you should get something like this,

780
Implementing boundary conditions using codeStream
codedFixedValue and codedMixed boundary conditions
• OpenFOAM® also includes the boundary conditions codedFixedValue and codedMixed.
• These boundary conditions are derived from codeStream and work in a similar way.
• They use a friendlier notation and let you access more information of the simulation database
(e.g. time).
• The source code and binaries are automatically generated and copied in the directory
dynamicCode of the current case.
• Another feature of these boundary conditions, is that the code section can be read from an
external dictionary (system/codeDict), which is run-time modifiable.
• The boundary condition codedMixed works in similar way. This boundary condition gives you
access to fixed values (Dirichlet BC) and gradients (Neumann BC).
• Let us implement the parabolic profile using codedFixedValue.

781
Implementing boundary conditions using codeStream
Body of the codedFixedValue boundary conditions
patch-name Patch name
{
type codedFixedValue; Use codedFixedValue and
value uniform (0 0 0); initializations
Unique name of the new boundary
name name_of_BC; condition.
If you have more codedFixedValue
/* BC, the names must be different
codeOptions
#{
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude Optional compilation options.
#}; You do not need to add these options
unless it is required.
codeInclude At the following link, you can find a bug
#{ related to codedFixedValue (SEP2020)
#include "fvCFD.H" https://bugs.openfoam.org/view.php?id=3555
#include <cmath>
#include <iostream>
#};
In this section we do the actual
*/
implementation of the boundary
code condition.
#{ This is the only part of the body
that you will need to change. The
#}; rest of the body is a template that
}
you can always reuse. 782
Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows,

1 code
2 #{
3 const fvPatch& boundaryPatch = patch();
4 const vectorField& Cf = boundaryPatch.Cf();
5 vectorField& field = *this;
6
7 scalar U_0 = 2, p_ctr = 8, p_r = 8;
8
9 forAll(Cf, faceI)
10 {
11 field[faceI] = vector(U_0*(1-(pow(Cf[faceI].y()-p_ctr,2))/(p_r*p_r)),0,0);
12 }
13 #};

• Lines 3-5, are always standard, they give us access to mesh and field information in the patch.
• The coordinates of the faces center are stored in the vector field Cf (line 4).
• In this case, as we are going to implement a vector profile, we initialize a vector field where we are going to
assign the profile (line 5).
• In line 7 we initialize a few constants that will be used in our implementation.
• In lines 9-12 we use a forAll loop to access the boundary patch face centers and to assign the velocity profile
values.
• In line 11 we do the actual implementation of the boundary profile (similar to the codeStream case). The
vector field was initialized in line 5.
783
Implementing boundary conditions using codeStream
codedFixedValue and codedMixed boundary conditions
• As you can see, the syntax and use of the codedFixedValue and codedMixed boundary
conditions is much simpler than codeStream.
• You can use these instructions as a template.
• At the end of the day, you only need to modify the code section.
• Depending of what you want to do, you might need to add new headers and compilation options.
• Remember, is you are working with a vector, you need to use vector fields. Whereas, if you are
working with scalars, you need to use scalars fields.
• One disadvantage of these boundary conditions, is that you can not visualize the fields at time
zero. You will need to run the simulation for at least one iteration.
• On the positive side, accessing time and other values from the simulation database is
straightforward.
• Time can be accessed by adding the following statement,

this->db().time().value()

784
Implementing boundary conditions using codeStream
• Let us add time dependency to the parabolic profile.

1 code
2 #{
3 const fvPatch& boundaryPatch = patch();
4 const vectorField& Cf = boundaryPatch.Cf();
5 vectorField& field = *this;
6
7 scalar U_0 = 2, p_ctr = 8, p_r = 8;
8
9 scalar t = this->db().time().value(); Time
10
11 forAll(Cf, faceI)
12 {
13 field[faceI] = vector(sin(t)*U_0*(1-(pow(Cf[faceI].y()-p_ctr,2))/(p_r*p_r))),0,0);
14 }
15 #};
Time dependency

• This implementation is similar to the previous one, we will only address how to deal with time.
• In line 8 we access simulation time.
• In line 13 we do the actual implementation of the boundary profile (similar to the codeStream
case). The vector field was initialized in line 5 and time is accessed in line 9.
• In this case, we added time dependency by simple multiplying the parabolic profile by the
function sin(t).
785
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet_timeDep
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh

3. $> checkMesh | tee log


4. $> rm –rf 0
5. $> rm –rf 0_org 0
6. $> pisoFoam | tee log.solver
7. $> paraFoam

• The codeStream boundary condition is implemented in the file 0/U.


• FYI, you can run in parallel with no problem.

786
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• If everything went fine, you should get something like this,

www.wolfdynamics.com/wiki/BCIC/elbow_unsBC1.gif

787
Implementing boundary conditions using codeStream
Filling a tank using codedFixedValue
• Let us do a final example.
Water enters here
• We will deal with scalar and vector fields at the same This is a face selection in a single boundary patch
time.
• We will use codedFixedValue.
• For simplicity, we will only show the code section of the
input files.
• Remember, the rest of the body can be used as a
template.
• And depending of what you want to do, you might need
to add new headers, libraries, and compilation options.
• Hereafter we will setup an inlet boundary condition in a
portion of an existing patch.
• By using codedFixedValue BC, we do not need to
modify the actual mesh topology.
• We will assign a velocity field and a scalar field to a set
of faces (dark area in the figure).
• We are going to simulate filling a tank with water.
• We will use the solver interFoam. The tank is initially empty

788
Implementing boundary conditions using codeStream
• Definition of the vector field boundary condition (dictionary file U),

Name of the patch where we want to implement the boundary condition

1 leftWall Use codedFixedValue BC and initialize value.


2 { The initialization is only needed for paraview
3 type codedFixedValue; in order to visualize something at time zero.
4 value uniform (0 0 0);
5 name inletProfile1; Unique name of the BC
6 Do not use the same name in other patches
7 code
8 #{
9 const fvPatch& boundaryPatch = patch(); Access boundary mesh
10 const vectorField& Cf = boundaryPatch.Cf(); information and initialize
11 vectorField& field = *this; vector field field
12
13 scalar minz = 0.4;
14 scalar maxz = 0.6;
15 scalar miny = 0.5; Initialize variables
16 scalar maxy = 0.7;
17
18 scalar t = this->db().time().value(); Access time
...
...
...
40 #};
41 }

789
Implementing boundary conditions using codeStream
• Definition of the vector field boundary condition (dictionary file U),

7 code Code section. The actual implementation of the BC is done in this section
8 #{
...
... Loop using size of boundary patch (Cf) and iterator
... faceI.
19 This is equivalent to:
20 forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
21 {
22
23 if (
24 (Cf[faceI].z() > minz) &&
Use conditional structure to
25 (Cf[faceI].z() < maxz) &&
26 (Cf[faceI].y() > miny) && select faces according to the
27 (Cf[faceI].y() < maxy) variables defined in lines 13-16
28 )
29 {
30 if ( t < 1.)
31 { Use conditional structure to
32 field[faceI] = vector(1,0,0); add time dependency and
33 } assign values to the
34 else
selected faces.
35 {
36 field[faceI] = vector(0,0,0); The variable field was
37 } initialize in line 11.
38 }
39 }
40 #};
41 }
790
Implementing boundary conditions using codeStream
• Definition of the scalar field boundary condition (dictionary file alpha.water),

Name of the patch where we want to implement the boundary condition

1 leftWall Use codedFixedValue BC and initialize value.


2 { The initialization is only needed for paraview
3 type codedFixedValue;
in order to visualize something at time zero.
4 value uniform 0;
5 Name inletProfile2; Unique name of the BC
6 Do not use the same name in other patches
7 code
8 #{
9 const fvPatch& boundaryPatch = patch(); Access boundary mesh
Code section. The actual implementation of

10 const vectorField& Cf = boundaryPatch.Cf(); information and initialize


11 scalarField& field = *this; scalar field field
12
13 field = patchInternalField(); Assign value from the internal field to the patch
14
the BC is done in this section

15 scalar minz = 0.4;


16 scalar maxz = 0.6;
17 scalar miny = 0.5; Initialize variables
18 scalar maxy = 0.7;
20
21 scalar t = this->db().time().value(); Access time
22
...
...
...
42 #};
43 }
791
Implementing boundary conditions using codeStream
• Definition of the scalar field boundary condition (dictionary file alpha.water),

7 code Code section. The actual implementation of the BC is done in this section
8 #{
...
Loop using size of boundary patch (Cf) and iterator
...
... faceI.
22 This is equivalent to:
23 forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
24 {
25 if (
26 (Cf[faceI].z() > minz) && Use conditional structure to
27 (Cf[faceI].z() < maxz) && select faces according to the
28 (Cf[faceI].y() > miny) &&
variables defined in lines 13-16
29 (Cf[faceI].y() < maxy)
30 )
31 {
32 if ( t < 1.)
33 { Use conditional structure to add
34 field[faceI] = 1.; time dependency and assign
35 }
36 else
values to the selected faces.
37 { The variable field was initialize in
38 field[faceI] = 0.; line 11.
39 }
40 }
41 }
42 #};
43 }

792
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/fillBox_BC/
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> decomposePar
6. $> mpirun -np 4 interFoam -parallel | tee log.solver
7. $> reconstructPar
8. $> paraFoam

• As you can see, we can also run in parallel with no problem.


• To visualize the parallel results, you will need to use the wrapper paraFoam with the
option –builtin. 793
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• If everything went fine, you should get something like this

00

00

00

0 02

0 01

0
0 02 0 0 0 1 12 1 1 1 2

Visualization of water phase Volume integral of water entering the


(alpha.water) domain
www.wolfdynamics.com/wiki/BCIC/filltank1.gif
794
Roadmap

1. codeStream – Highlights
2. Implementing boundary conditions using
codeStream
3. Solution initialization using codeStream

795
Solution initialization using codeStream
• When it comes to initial conditions, you can use the utility setFields.
• This utility is very flexible, you can even read STL files and use them to initialize your fields.
• But in case that you can not get the desired results using setFields, you can implement your
own initial conditions using codeStream.
• To implement initial conditions using codeStream, we proceed in a similar way as for boundary
conditions.
• The source code and binaries are automatically generated and copied in the directory
dynamicCode of the current case.
• The source code is compiled automatically at run-time.
• The use of codeStream is a very good alternative to avoid high level programming of initial
conditions or the use of external libraries.
• Hereafter we will use codeStream to implement new initial conditions.

796
Solution initialization using codeStream
Body of the codeStream directive for initial conditions
internalField #codeStream Use codeStream to set the value
{ of the initial conditions
{
codeInclude
#{
#include "fvCFD.H" Files needed for compilation
Initial conditions

#};

codeOptions
#{
-I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
#};

codeLibs
Libraries needed for compilation.
#{
-lmeshTools \ Needed if you want to visualize the
-lfiniteVolume output of the initial conditions at
#}; time zero

code
#{
Insert your code here.
#}; At this point, you need to know
}; how to access internal mesh
} information

797
Solution initialization using codeStream
Implementation of an elliptic initialization using codeStream
• Let us implement an elliptic initialization using codeStream.
• The firs step is to know your domain and identify the region that you want to initialize.
• Then you will need to do a little bit of math to get the expression for the initialization.
• In this example, we are also going to show you how to do the same initialization by reading a
STL file with the utility setFields.

Initialization using STL


Phase 2

Phase 1

Initialization using codeStream Initialization using a STL with setFields

798
Solution initialization using codeStream
• The codeStream IC in the body of the file alpha.phase1 is as follows,

internalField #codeStream Use codeStream to set the value


{ of the initial conditions
{
codeInclude
#{
#include "fvCFD.H"
#};

codeOptions Depending of what are you trying


#{ to do, you will need to add new
-I$(LIB_SRC)/finiteVolume/lnInclude \ files, options and libraries.
-I$(LIB_SRC)/meshTools/lnInclude
#};
For most of the cases, this part is
codeLibs always the same.
#{
-lmeshTools \
-lfiniteVolume
#};

code
#{
Insert your code here.
#}; At this point, you need to know
}; how to access internal mesh
} information

799
Solution initialization using codeStream
• The code section of the codeStream IC in the body of the file alpha.phase1 is as follows,

Access internal mesh information


code
#{
const IOdictionary& d = static_cast<const IOdictionary&>(dict);
const fvMesh& mesh = refCast<const fvMesh>(d.db());

scalarField alpha(mesh.nCells(), 0.); Initialize scalar field to zero


scalar he = 0.5;
Initialize variables
scalar ke = 0.5;
scalar ae = 0.3;
scalar be = 0.15; forAll loop to access cell centers and to assign alpha values.
Notice the alpha was previously initialized.
forAll(alpha, i) The size of the loop is defined by alpha and the iterator is i.
{
const scalar x = mesh.C()[i][0];
const scalar y = mesh.C()[i][1]; Access cell centers coordinates
const scalar z = mesh.C()[i][2];
Assign value to alpha

if ( pow(y-ke,2) <= ((1 - pow(x-he,2)/pow(ae,2) )*pow(be,2)) )

If this condition is true, do the


{
alpha[i] = 1.;
}

following statement
}

writeEntry(os, "", alpha);


#};
Write output to input dictionary

800
Solution initialization using codeStream
Implementation of an elliptic initialization using codeStream
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_INIT/elliptical_IC
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> paraFoam
6. $> interFoam | tee log.solver
7. $> paraFoam

• In step 6, we launch paraFoam to visualize the initialization.


• FYI, you can run in parallel with no problem.

801
Solution initialization using codeStream
Implementation of an elliptic initialization using codeStream

• If everything went fine, you should get something like this,

codeStream initialization setFields initialization


Visualization of volume fraction (alpha.phase1) Visualization of volume fraction (alpha.phase1)
www.wolfdynamics.com/wiki/BCIC/bubble_zeroG.gif www.wolfdynamics.com/wiki/BCIC/bubble_zeroG_SF.gif

Surface tension driven flow - Bubble in a zero gravity flow using interFoam

802
Solution initialization using codeStream
Elliptic initialization using setFields
• Let us do the same initialization using a STL file with setFields.
• First, you will need to create the solid model that encloses the region you want to initialize.
• For this, you can use your favorite CAD/solid modeling software. Remember to save the
geometry is STL format.
• Then you will need to read in the STL file using setFields.
• You will need to modify the setFieldsDict dictionary.

Region defined by
the STL file
Computational domain

803
Solution initialization using codeStream
The setFieldsDict dictionary

defaultFieldValues
(
volScalarFieldValue alpha.phase1 0 Initialize the whole domain to zero
);

regions
setFields method to read STL files.
( If you want to know all the options
available use a word that does not exist
surfaceToCell in the enumerator list (e.g. banana)
{
file "./geo/ellipse.stl"; Location of the STL file to read
outsidePoints ((0.5 0.85 0)); A point located outside the STL

includeInside true; Use what is inside the STL


includeOutside false; Use what is outside the STL
includeCut false; Include cells cut by the STL
fieldValues
(
volScalarFieldValue alpha.phase1 1 Initialize this value.
); In this case the initialization will be inside
the STL
}
);
804
Solution initialization using codeStream
Elliptic initialization using setFields
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_INIT/elliptical_IC
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> setFields
6. $> paraFoam

• At this point, compare this initialization with the previous one.


• Also, feel free to launch the simulation using interFoam.

805
Solution initialization using codeStream
Rayleigh-Taylor instability initialization

• Let us study the Rayleigh-Taylor


instability.
• In this case, we have two phases with
different physical properties (one phase
is heavier).
• To onset this instability, we need to
perturbate somehow the interface
between the two phases.
• We will use codeStream to initialize the
two phases.
• For simplicity, we will only show the
code section of the input files.
• The entries codeInclude, codeOptions,
and codeLibs, are the same most of the
times.

806
Solution initialization using codeStream
• The code section of the codeStream IC in the body of the file alpha.phase1 is as follows,

code Access internal mesh information


#{
const IOdictionary& d = static_cast<const IOdictionary&>(dict);
const fvMesh& mesh = refCast<const fvMesh>(d.db());

scalarField alpha(mesh.nCells(), 0.); Initialize scalar field to zero


forAll(alpha, i)
Assign value to alpha

{
const scalar x = mesh.C()[i][0];
const scalar y = mesh.C()[i][1];
Access cell centers coordinates

if (y >= -0.05*cos(2*constant::mathematical::pi*x))
{
alpha[i] = 1.;
}
}

writeEntry(os, "", alpha);


#}; Write output to input dictionary

• For simplicity, we only show the code section.


• The rest of the body of the codeStream IC is a template.

807
Solution initialization using codeStream
Rayleigh-Taylor instability initialization
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_INIT/rayleigh_taylor
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> interFoam | tee log.solver
6. $> paraFoam

• FYI, you can run in parallel with no problem.

808
Solution initialization using codeStream
Rayleigh-Taylor instability initialization
• If everything went fine, you should get something like this,

Initial conditions Visualization of volume fraction, static pressure and velocity


magnitude
www.wolfdynamics.com/wiki/BCIC/rayleigh_taylor_ins1.gif

809
Solution initialization using codeStream
Filling a tank using codeStream and codedFixedValue
• Let us do a final example.
• We will implement BCs and ICs at the same.
• For simplicity, we will only show the code section of the input files.
• This setup is similar to the last example of the previous section (filling a tank using
codedFixedValue).

Water enters here


This is a single boundary patch

Initial water level

810
Solution initialization using codeStream
• The code section of the codeStream IC in the body of the file alpha.water is as follows,

internalField #codeStream
Use codeStream to set the
{ value of the initial conditions

Access internal mesh information


...
...
...
code
#{
const IOdictionary& d = static_cast<const IOdictionary&>(dict);
const fvMesh& mesh = refCast<const fvMesh>(d.db());

scalarField alpha(mesh.nCells(), 0.); Initialize scalar field to zero


forAll(alpha, i)
{
const scalar x = mesh.C()[i][0];
const scalar y = mesh.C()[i][1]; Access cell centers
const scalar z = mesh.C()[i][2]; coordinates

if (y <= 0.2)
{ Assign value to alpha according to
alpha[i] = 1.; conditional structure
}
}

writeEntry(os, "", alpha); Write output to input dictionary


#};

811
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file U is as follows,

Name of the patch where we want to implement the boundary condition

leftWall Use codedFixedValue BC and initialize value.


{ The initialization is only needed for paraview
type codedFixedValue;
in order to visualize something at time zero.
value uniform (0 0 0);
Unique name of the BC
name inletProfile1;
Do not use the same name in other patches
code Code section. The actual implementation of the BC is done here
#{
const fvPatch& boundaryPatch = patch(); Access boundary mesh
const vectorField& Cf = boundaryPatch.Cf(); information and initialize
vectorField& field = *this; vector field field
scalar min = 0.5;
scalar max = 0.7; Initialize variables

scalar t = this->db().time().value(); Access time


...
...
...
#};
}

812
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file U is as follows,

code Code section. The actual implementation of the BC is done here


#{
...
... Loop using size of boundary patch (Cf) and iterator
... faceI.
This is equivalent to:
forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
{

if (
(Cf[faceI].z() > min) &&
(Cf[faceI].z() < max) && Use conditional structure to
(Cf[faceI].y() > min) && select faces.
(Cf[faceI].y() < max)
)
{
if ( t < 2.)
{
field[faceI] = vector(1,0,0); Use conditional structure to
} add time dependency and
else
assign values to the
{
field[faceI] = vector(0,0,0); selected faces.
}
}
}
#};

813
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file alpha.water is as follows,

Name of the patch where we want to implement the boundary condition

leftWall Use codedFixedValue BC and initialize value.


{ The initialization is only needed for paraview
type codedFixedValue;
in order to visualize something at time zero.
value uniform 0;
Unique name of the BC
name inletProfile2;
Do not use the same name in other patches

code Code section. The actual implementation of the BC is done here


#{
const fvPatch& boundaryPatch = patch(); Access boundary mesh
const vectorField& Cf = boundaryPatch.Cf(); information and initialize
scalarField& field = *this; scalar field field

field = patchInternalField(); Assign value from the internal field to the patch

scalar min = 0.5;


scalar max = 0.7;
Initialize variables

scalar t = this->db().time().value(); Access time


...
...
...
#};
}
814
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file alpha.water is as follows,

code Code section. The actual implementation of the BC is done here


#{
...
Loop using size of boundary patch (Cf) and iterator
...
... faceI.
This is equivalent to:
forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
{
if (
(Cf[faceI].z() > min) &&
(Cf[faceI].z() < max) && Use conditional structure to
(Cf[faceI].y() > min) && select faces
(Cf[faceI].y() < max)
)
{
if ( t < 2.)
{
field[faceI] = 1.;
Use conditional structure to add
}
else time dependency and assign
{ values to the selected faces.
field[faceI] = 0.;
}
}
}
#};

815
Solution initialization using codeStream
Filling a tank using codeStream and codedFixedValue
• If everything went fine, you should get something like this,

02

02

02

0 22

02

01
0 0 1 1 2 2

Visualization of water phase (alpha.water) Volume integral of water entering


www.wolfdynamics.com/wiki/BCIC/filltank2.gif the domain

816
Module 8
Advanced physics
Turbulence modeling – Multiphase flows –
Compressible flows – Moving bodies –
Source terms – Passive scalars

817
• In this module, we will deal with advanced modeling capabilities.
• Advanced modeling capabilities rely a lot in physical models, such as,
turbulence, multiphase flows, porous media, combustion, radiation, heat
transfer, phase change, acoustics, cavitation, and so on.
• Therefore, it is extremely important to get familiar with the theory behind
these models.

“Essentially, all models are wrong,


but some are useful”
G. E. P. Box

George Edward Pelham Box


18 October 1919 – 28 March 2013. Statistician, who
worked in the areas of quality control, time-series
analysis, design of experiments, and Bayesian inference.
He has been called “one of the great statistical minds of
the 20th century”.
818
Roadmap

A crash introduction to:


1. Turbulence modeling in OpenFOAM®
2. Multiphase flows modeling in
OpenFOAM®
3. Compressible flows in OpenFOAM®
4. Moving bodies in OpenFOAM®
5. Source terms in OpenFOAM®
6. Scalar transport pluggable solver

819
A crash introduction to turbulence modeling in OpenFOAM®
What is turbulence?

• For the purpose of this training, let us state the following:


• Turbulence is an unsteady, aperiodic motion in which
all three velocity components fluctuate in space and
time.
• Every transported quantity shows similar fluctuations
(pressure, temperature, species, concentration, and
so on)
• Turbulent flows contains a wide range of eddy sizes
(scales):
• Large eddies derives their energy from the mean
flow. The size and velocity of large eddies are on
the order of the mean flow.
• Large eddies are unstable and they break-up into
smaller eddies.
• The smallest eddies convert kinetic energy into
thermal energy via viscous dissipation.
• The behavior of small eddies is more universal in
nature. Buoyant plume of smoke rising from a stick of incense
Photo credit: https://www.flickr.com/photos/jlhopgood/
This work is licensed under a Creative Commons License
(CC BY-NC-ND 2.0)
820
A crash introduction to turbulence modeling in OpenFOAM®

Wake turbulence behind individual wind turbines Flow visualization over a spinning spheroid
Photo credit: NREL's wind energy research group. Photo credit: Y. Kohama.
Copyright on the images is held by the contributors. Apart from Fair Use, Copyright on the images is held by the contributors. Apart from Fair Use,
permission must be sought for any other purpose. permission must be sought for any other purpose.

Von Karman vortices created when prevailing winds sweeping east across Vortices on a 1/48-scale model of an F/A-18 aircraft inside a Water
the northern Pacific Ocean encountered Alaska's Aleutian Islands Tunnel
Photo credit: USGS EROS Data Center Satellite Systems Branch. Photo credit: NASA Dryden Flow Visualization Facility.
Copyright on the images is held by the contributors. Apart from Fair Use, Copyright on the images is held by the contributors. Apart from Fair Use,
permission must be sought for any other purpose. permission must be sought for any other purpose. 821
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter?

Abstract representation of
the drag decomposition

Flow around two spheres. Left image: smooth sphere. Right image: sphere with rough surface at the nose
Photo credit: http://www.mhhe.com/engcs/civil/finnemore/graphics/photos/AuthorRecommendedImages/index.html
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 822
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter?


Blower simulation using sliding grids

No turbulence model used (laminar, no K-epsilon turbulence model


turbulence modeling, DNS, unresolved http://www.wolfdynamics.com/training/turbulence/image2.gif

DNS, name it as you want)


http://www.wolfdynamics.com/training/turbulence/image1.gif

823
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter?


Vortex shedding past square cylinder

URANS (K-Omega SST with no wall functions) – LES (Smagorinsky) – Vortices visualized by Q-criterion
Vortices visualized by Q-criterion www.wolfdynamics.com/wiki/squarecil/les.gif
www.wolfdynamics.com/wiki/squarecil/urans2.gif

Laminar (no turbulence model) – Vortices DES (SpalartAllmarasDDES) – Vortices visualized by


visualized by Q-criterion Q-criterion
www.wolfdynamics.com/wiki/squarecil/laminar.gif www.wolfdynamics.com/wiki/squarecil/des.gif 824
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter?


Vortex shedding past square cylinder

Turbulence model Drag coefficient Strouhal number Computing time (s)

Laminar 2.81 0.179 93489

LES 2.32 0.124 77465

DES 2.08 0.124 70754

URANS (WF) 2.31 0.130 67830

URANS (No WF) 2.28 0.135 64492

RANS 2.20 - 28246 (10000 iter)

Experimental values 2.05-2.25 0.132 -

Note: all simulations were run using 4 cores.

References:
Lyn, D.A. and Rodi, W., The flapping shear layer formed by flow separation from the forward corner of a square cylinder. J. Fluid Mech., 267, 353, 1994.
Lyn, D.A., Einav, S., Rodi, W. and Park, J.H., A laser-Doppler velocimetry study of ensemble-averaged characteristics of the turbulent near wake of a square
cylinder. Report. SFB 210 /E/100.
825
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter?


Separated flow around a NACA-4412 airfoil

Inflow

Turbulence model 1
Turbulence model 2
Turbulence model 3
Turbulence model 4
Turbulence model 5
Experimental results

Turbulence model 1
Turbulence model 2
Turbulence model 3
Turbulence model 4
Turbulence model 5
Experimental results

• CFD has been around since the late 1970s, and after all these years is not that easy to compute the flow around 2D airfoils.
• In particular, predicting the maximum lift and stall characteristics is not trivial.

References:
F. Menter. “A New Generalized k-omega model. Putting flexibility into Turbulence models (GEKO)”, Ansys Germany
A. J. Wadcock. “Investigation of Low-Speed Turbulent Separated Flow Around Airfoils”, NASA Contractor Report 177450 826
A crash introduction to turbulence modeling in OpenFOAM®
Turbulence modeling in engineering
• Most natural and engineering flows are turbulent, hence the necessity of modeling turbulence.
• The goal of turbulence modeling is to develop equations that predict the time averaged velocity, pressure,
temperature fields without calculating the complete turbulent flow pattern as a function of time.
• There is no universal turbulence model, hence you need to know the capabilities and limitations of the
turbulence models.
• Simulating turbulent flows in any general CFD solver requires selecting a turbulence model, providing initial
conditions and boundary conditions for the closure equations of the turbulent model, selecting a near-wall
modeling, and choosing runtime parameters and numerics.

Why modeling turbulent flows is challenging?


• Unsteady aperiodic motion.
• All fluid properties and transported quantities exhibit random spatial and temporal variations.
• They are intrinsically three-dimensional due to vortex stretching.
• Strong dependence from initial conditions.
• Contains a wide range of scales (eddies).
• Therefore, in order to accurately model/resolve turbulent flows, the simulations must be three-dimensional,
time-accurate, and with fine enough meshes such that all spatial scales are resolved.

827
A crash introduction to turbulence modeling in OpenFOAM®

Reynolds number and Rayleigh number


• It is well known that the Reynolds number characterizes if the flow is laminar or turbulent.
• So before doing a simulation or experiment, check if the flow is turbulent.
• The Reynolds number is defined as follows,

Convective effects
where
Viscous effects

• Where U and L are representative velocity and length scales.


• If you are dealing with natural convection, you can use the Rayleigh number, Grashof number, and Prandtl
number to characterize the flow.
Specific heat Thermal expansion coefficient

Buoyancy effects

Viscous effects Thermal conductivity

Momentum diffusivity

Thermal diffusivity 828


A crash introduction to turbulence modeling in OpenFOAM®

Reynolds number and Rayleigh number


• Turbulent flow occurs at large Reynolds number.
• For external flows,

Around slender/streamlined bodies (surfaces)

Around an obstacle (bluff body)

• For internal flows,

• Notice that other factors such as free-stream turbulence, surface conditions, blowing, suction,
roughness and other disturbances, may cause transition to turbulence at lower Reynolds
number.
• If you are dealing with natural convection and buoyancy, turbulent flows occurs when

829
A crash introduction to turbulence modeling in OpenFOAM®

What happens when we increase the Reynolds number?

Creeping flow (no s eparation)


S teady flow Re < 5
• Easy to simulate
A pair of s table vortices
• Steady
in the wake
S teady flow
5 < Re < 40 - 46
• Relatively easy to
simulate.
Laminar vortex s treet
(Von Karman s treet)
Uns teady flow
40 - 46 < Re < 150 • It becomes more
challenging when
the boundary layer
Laminar boundary layer up to
the s eparation point, turbulent
150 < Re < 300 transition to
Trans ition to turbulence
wake
Uns teady flow 300 < Re < 3 x 10 5 turbulent
• Unsteady
Boundary layer trans ition to 5 6
turbulent 3 x 10 < Re < 3 x 10
Uns teady flow • Challenging to
simulate
Turbulent vortex s treet, but the
6 • Unsteady
wake is narrower than in the
laminar cas e 3 x 10 > Re
Uns teady flow

Vortex shedding behind a cylinder and Reynolds number


830
A crash introduction to turbulence modeling in OpenFOAM®

What happens when we increase the Reynolds number?

Drag coefficient as a function of Reynolds number for Strouhal number for a smooth cylinder [2]
a smooth cylinder [1]

References:

1. Fox, Robert W., et al. Introduction to Fluid Mechanics. Hoboken, NJ, Wiley, 2010
2. Sumer, B. Mutlu, et al. Hydrodynamics Around Cylindrical Structures. Singapore, World Scientic, 2006
831
A crash introduction to turbulence modeling in OpenFOAM®

Vorticity does not always mean turbulence

Instantaneous vorticity magnitude field


www.wolfdynamics.com/wiki/cylinder_vortex_shedding/movvort.gif

• The Reynold number in this case is 100, for these conditions the flow still is laminar.
• We are in the presence of the Von Karman vortex street, which is the periodic shedding of vortices caused by
the unsteady separation of the fluid around blunt bodies.
• Vorticity is not a direct indication of turbulence.
• However turbulent flows are rotational, they exhibit vortical structures. 832
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling – Fluctuations of transported quantities

In RANS
• The overbar denotes the mean value.
• The prime denotes the fluctuating value.

In LES
• The overbar denotes the filtered value.
• The prime denotes the modeled value or
residual.

• We have defined turbulence as an unsteady, aperiodic motion in which velocity components and every
transported quantity fluctuate in space and time.
• For most engineering application it is impractical to account for all these instantaneous fluctuations.
• Therefore, we need to somehow remove those small scales by using models.
• To remove of filter the instantaneous fluctuations or small scales, two methods can be used: Reynolds
averaging and Filtering
• Both methods introduce additional terms that must be modeled for closure.
• We are going to talk about closure methods later. 833
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling – Velocity profile

Laminar flow profile Averaged turbulent flow profile Instantaneous turbulent flow profile

• In the laminar flow case, the velocity gradients close to the walls are low and the velocity profile is parabolic.
• Turbulence has a direct effect on the velocity profiles and mixing of transported quantities.
• The turbulent case shows two regions. One thin region close to the walls with very large velocity gradients,
and a region far from the wall where the velocity profile is nearly uniform.
• The thin region close to the walls is laminar.
• Far from the flows, the flow becomes turbulent.
834
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling – Mixing of transported quantities

Flow in a pipe. (a) Laminar, (b) Transitional, (c) Turbulent

• Turbulence has a direct effect on the velocity profiles and mixing of transported quantities.
• Case (a) correspond to a laminar flow, where the dye can mix with the main flow only via molecular diffusion,
this kind of mixing can take very long times.
• Case (b) shows a transitional state where the dye streak becomes wavy, but the main flow still is laminar.
• Case (c) shows the turbulent state, where the dye streak changes direction erratically, and the dye has mixed
significantly with the main flow due to the velocity fluctuations. 835
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence near the wall – Boundary layer


Note: The scales are
Laminar boundary Transition Turbulent boundary exaggerated for clarity
layer region layer

oundary layer t ickness


u 0.

Logarit mic layer

uffer layer
iscous sublayer

Critical lengt

Actual profile - Physical velocity profile

• Near walls, in the boundary layer, the velocity changes rapidly.


• A laminar boundary layer starts to form at the leading edge. As the flow proceeds further downstream, large shear stresses and
velocity gradient develop within the boundary layer. At one point, the flow becomes turbulent.
• In CFD, we try to avoid the transition region and the buffer layer. What is happening in this region is not well understood. The
flow can become laminar again or can become turbulent.
• The velocity profiles in the laminar and turbulent regions are different.
• Turbulence models require different considerations depending on whether you solve the viscous sublayer, model the log-law
layer, or solve the whole boundary layer. 836
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence near the wall - Law of the wall

integral scales

inertial scales

dissipation scales

Non-dimensional profile Actual profile - Physical velocity profile

• The use of the non-dimensional velocity u+ and non-dimensional distance from the wall y+, results in a
predictable boundary layer profile for a wide range of flows.
• Turbulence models require different considerations depending on whether you solve the viscous sublayer of
model the log-law layer. 837
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence near the wall - Definition of y+ and u+

Where y is the distance normal to the


wall, U is the shear velocity, and
relates the mean velocity to the shear
velocity

• y+ or wall distance units is a very


important concept when dealing
with turbulence modeling.
• Remember this definition as we
are going to use it a lot.
838
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence near the wall - Relations according to y+ value

Buffer layer
Viscous sublayer
Logarithmic layer (log-law)
Note 1: the range of y+ values might change from reference to reference but roughly speaking
they are all close to these values.
Note 2: the y+ upper limit of the buffer layer depends on the Reynolds number. Large Re will
have higher y+ upper limit 839
A crash introduction to turbulence modeling in OpenFOAM®

Near-wall treatment and wall functions


• When dealing with wall turbulence, we need to choose a near-wall treatment.

Wall resolving approach


• If you want to resolve the boundary layer up to the viscous sub-layer you need very fine meshes
close to the wall.
• In terms of y+, you need to cluster at least 8-10 layers at y+ < 6-10.
• But for good accuracy, usually you will use 15 to 30 layers, with a low growth rate.
• You need to properly resolve the velocity profile.
• This is the most accurate approach, but it is computationally expensive.

Wall resolving approach


• If you are not interested in resolving boundary layer up to the viscous sub-layer, you can use wall
functions.
• In terms of y+, wall functions will model everything for y+ < 30.
• You will need to cluster at least 5 to 10 layers to resolve the profiles (U and k).
• This approach use coarser meshes, but you should be aware of the limitations of the wall functions.

y+ insensitive
• You can also use the y+ insensitive wall treatment (sometimes known as continuous wall functions or scalable wall functions).
• This near-wall treatment is valid in the whole boundary layer.
• In terms of y+, you can use this approach for values between 1 < y+ < 300.
• This approach is very flexible as it is independent of the y+ value but is not available in all turbulence models.
• You should also be aware of its limitations. 840
A crash introduction to turbulence modeling in OpenFOAM®
Turbulence modeling – Grid scales

Cell size
This cell is resolving the eddies

To resolve the boundary layer


you need very fine meshes
Cell size
This cell is not resolving the eddies Cell size
This cell may be resolving the eddies

• Turbulence modelling aims at predicting velocity and transported quantities fluctuations without
calculating the complete turbulent flow pattern as a function of time.
• Everything below grid scales or sub-grid scales (SGS) is modelled or filtered.
• Therefore, if we want to capture all scales we need very fine meshes in the whole domain.

Bullet at Mach 1.5


Photo credit: Andrew Davidhazy. Rochester Institute of Technology.
841
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose.
A crash introduction to turbulence modeling in OpenFOAM®

Overview of turbulence modeling approaches

MODELING APPROACH

Increasing modelling and mathematical


RANS

Increasing computational cost


Reynolds-Averaged Navier-Stokes equations

URANS
Unsteady Reynolds-Averaged Navier-Stokes equations

complexity
• Many more acronyms that fit between RANS/URANS
and SRS.
• Some of the acronyms are used only to differentiate
approaches used in commercial solvers.
PANS, SAS, RSM, EARSM, PITM, SBES, ELES
Scale-Resolving Simulations

DES
SRS

Detached Eddy Simulations

LES
Large Eddy Simulations

DNS
Direct Numerical Simulations
842
A crash introduction to turbulence modeling in OpenFOAM®

Overview of turbulence modeling approaches

RANS LES (Instantaneous field)

RANS/URANS DES/LES DNS


• Solve the time-average NSE. • Solve the filtered unsteady NSE. • Solves the unsteady laminar NSE.
• All turbulent spatial scales are • Sub-grid scales (SGS) are filtered, • Solves all spatial and temporal
modeled. grid scales (GS) are resolved. scales; hence, requires extremely
fine meshes and small time-steps.
• Many models are available. One • Aim at resolving the temporal scales,
equation models, two equation hence requires small time-steps. • No modeling is required.
models, Reynolds stress models,
• For most industrial applications, it is • It is extremely computational
transition models, and so on.
computational expensive. However, expensive.
• This is the most widely approach for thanks to the current advances in
• Not practical for industrial flows.
industrial flows. parallel and scientific computing it is
becoming affordable. • It is intrinsically 3D and asymmetric.
• Unsteady RANS (URANS), use the
same equations as the RANS but • Many models are available.
with the transient term retained.
• It is intrinsically 3D and asymmetric.
• It can be used in 2D and 3D cases. 843
A crash introduction to turbulence modeling in OpenFOAM®

Short description of some RANS turbulence models

Model Short description


Suitable for external aerodynamics, tubomachinery and high-speed flows. Good for mildly
complex external/internal flows and boundary layer flows under pressure gradient (e.g. airfoils,
Spalart-Allmaras wings, airplane fuselages, ship hulls). Performs poorly for free shear flows and flows with strong
separation.

Robust. Widely used despite the known limitations of the model. Performs poorly for complex
Standard k–epsilon flows involving severe pressure gradient, separation, strong streamline curvature. Suitable for
initial iterations, initial screening of alternative designs, and parametric studies.

Suitable for complex shear flows involving rapid strain, moderate swirl, vortices, and locally
transitional flows (e.g. boundary layer separation, massive separation, and vortex shedding
Realizable k–epsilon behind bluff bodies, stall in wide-angle diffusers, room ventilation). It overcome the limitations of
the standard k-epsilon model.

Superior performance for wall-bounded boundary layer, free shear, and low Reynolds number
Standard k–omega flows compared to models from the k-epsilon family. Suitable for complex boundary layer flows
under adverse pressure gradient and separation (external aerodynamics and turbomachinery).

Offers similar benefits as standard k–omega. Not overly sensitive to inlet boundary conditions
SST k–omega like the standard k–omega. Provides more accurate prediction of flow separation than other
RANS models. Probably the most widely used RANS model.

844
A crash introduction to turbulence modeling in OpenFOAM®
Turbulence modeling – Starting equations

NSE

Additional equations to close the system (thermodynamic variables)


Additionally, relationships to relate the transport properties
Additional closure equations for the turbulence models

• Turbulence models equations cannot be derived from fundamental principles.


• All turbulence models contain some sort of empiricism.
• Some calibration to observed physical solutions is contained in the turbulence models.
• Also, some intelligent guessing is used.
• A lot of uncertainty is involved! 845
A crash introduction to turbulence modeling in OpenFOAM®

Incompressible RANS equations


• The RANS equations are very similar to the starting equations.

If we retain this term, we talk about URANS equations and if we drop it we talk about RANS equations

RANS/URANS equations NSE with no turbulence models (DNS)

• The differences are that all quantities have been averaged (the overbar over the primitive variables).
• And the appearance of the Reynolds stress tensor .
• Notice that the Reynolds stress tensor is not actually a stress, it must be multiplied by density in order to have
dimensions corresponding to stresses,

• To derive the RANS equations we used Reynolds decomposition and a few averaging rules (a lot of algebra is
involved),

Reynolds decomposition
846
A crash introduction to turbulence modeling in OpenFOAM®

Incompressible RANS equations


• The RANS approach to turbulence modeling requires the Reynolds stresses to be appropriately modeled.

• The Reynolds stress tensor can be modeled using the Boussinesq hypothesis, Reynolds stress models, non-
linear eddy viscosity models or algebraic models.
• Let us address the Boussinesq hypothesis which is the most widely used approach to model the Reynolds
stress tensor.
• By using this hypothesis we can relate the Reynolds stress tensor to the mean velocity gradient such that,

• In the previous equation, denotes the strain-rate tensor.


• is the identity matrix.
• is the turbulent eddy viscosity.
• is the turbulent eddy viscosity.
• At the end of the day we want to determine the turbulent eddy viscosity.
• The turbulent eddy viscosity is not a fluid property, it is a property needed by the turbulence model.
• Each turbulence model will compute the turbulent eddy viscosity in a different way. 847
A crash introduction to turbulence modeling in OpenFOAM®

Incompressible RANS equations


• After introducing the Boussinesq approximation and doing some algebra, we obtain the following form of the
governing equations,

Effective viscosity

Turbulent viscosity

Normal stresses arising from the


Boussinesq approximation

• Notice that by introducing the Boussinesq approximation the fluctuating quantities (the prime in the equations)
do not appear in the final equations.
• The new equations are expressed entirely n terms of mean values (overbar), which can be computed.
• The problem now reduces to computing the turbulent eddy viscosity in the momentum equation.
• This is done by adding closure models (one-equation, two-equations, algebraic, transition, Reynolds stress,
and so on).
848
A crash introduction to turbulence modeling in OpenFOAM®

Additional remarks
• We just outlined the incompressible RANS.
• The compressible RANS equations are similar, but when we derive them, we use Favre average
(which can be seen as a mass-weighted averaging), instead of Reynolds average.
• Besides RANS, there is also LES and DES turbulence models.
• The idea behind LES/DES models is very similar to RANS, but instead of using averaging we
filter the equations in space, and we solve the temporal scales
• At the end of the day, in LES/DES it is also required to model a stress tensor, usually called the
SGS stress tensor.
• This stress tensor is related to the scales that cannot be resolved with the mesh; therefore, need
to be modelled.
• LES/DES models are intrinsically unsteady and three-dimensional.
• Let us take a look at the governing equations of the RANS model (Wilcox 1998
revision).
• Remember, the main goal of the RANS turbulence models is to model the Reynolds stress
tensor by computing the turbulent eddy viscosity.

849
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence model overview (Wilcox 1998 revision)


• It is called because it solves two additional equations for modeling the turbulent eddy viscosity,
namely, the turbulent kinetic energy and the specific kinetic energy .

• These are the closure equations of the turbulence problem using the RANS model.
• These are not physical quantities. They kind of represent the generation and destruction of turbulence.
• In the model, the turbulent eddy viscosity can be computed as follows,

• The model has many closure coefficient that we do not show here. These coefficients are calibrated using
experimental data, DNS simulations, analytical solutions, or empirical data.
• Note that all quantities are computed in function of mean values. The Reynolds stresses are modeled using
the Boussinesq hypothesis. By proceeding in this way, we remove any dependence on the fluctuations.
• It is worth mentioning that different turbulence models will have different ways of computing the turbulent eddy
viscosity. 850
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence model free stream initial conditions


• The initial value for the turbulent kinetic energy can be computed as follows,

• The initial value for the specific kinetic energy can be computed as follows,

• Where is the viscosity ratio and is the turbulence intensity.

• If you are totally lost, you can use these reference values. They work most of the times, but it is
a good idea to have some experimental data or a better initial estimate.

Low Medium High

I 1.0 % 5.0 % 10.0 %

1 10 100

• By the way, use these guidelines for external aerodynamics only. 851
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence model boundary conditions at the walls


• Follow these guidelines to find the boundary conditions for the near-wall treatment.
• We highly recommend you to read the source code and find the references used to implement
the model.
• As for the free-stream boundary conditions, you need to give the boundary conditions for the
near-wall treatment.
• When it comes to near-wall treatment, you have three options:
• Use wall functions:

• y+ insensitive wall functions, this only applies to the family of model:

• Resolve the boundary layer (no wall functions):

852
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence model boundary conditions at the walls


• Remember, you can only use wall functions if the primitive patch (the patch type defined in the
boundary dictionary), is of type wall.

Field Wall functions – High RE Resolved BL – Low RE

nut(–)WallFunction* or nutUSpaldingWallFunction** or
nut nutUSpaldingWallFunction** nutLowReWallFunction or fixedValue
(with 0 or a small number) (with 0 or a small number)

kqRWallFunction kqRWallFunction or kLowReWallFunction


k, q, R
or or

epsilonWallFunction (with inlet value) epsilonWallFunction (with inlet value) or


epsilon zeroGradient or fixedValue (with 0 or a small
number)

omegaWallFunction omegaWallFunction** or fixedValue


omega

nuTilda – fixedValue (with 0 or a small number)

* $WM_PROJECT_DIR/src/TurbulenceModels/turbulenceModels/derivedFvPatchFields/wallFunctions/nutWallFunctions
** For y+ insensitive wall functions (continuous wall functions) 853
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence models available in OpenFOAM®


• There are many turbulence models implemented in OpenFOAM®, from RANS to LES.
• You can also implement yours!
• You can find the turbulence models in the following directories:
• $WM_PROJECT_DIR/src/MomentumTransferModels
• The wall functions are in the following directories:
• $WM_PROJECT_DIR/src/MomentumTransferModels/momentumTransferModels/d
erivedFvPatchFields
• If you have absolutely no idea of what model to use, we highly recommend you the k-omega
family models or the realizable k-epsilon model.
• Remember, when a turbulent flow enters a domain, turbulent boundary conditions and initial
conditions must be specified.
• Also, if you are dealing with wall bounded turbulence you will need to choose the near-wall
treatment.
• You can choose to solve the viscous sub-layer (low-Re approach) or use wall functions
(high-Re approach).
• You will need to give the appropriate boundary conditions to the near-wall treatment.
• Our task is to choose the less wrong model ! 854
A crash introduction to turbulence modeling in OpenFOAM®

y+ wall distance units normal to the wall


• We never know a priori the y+ value (because we do not know the friction velocity).
• What we usually do is to run the simulation for a few time-steps or iterations, and then we get an
estimate of the y+ value.
• After determining where we are in the boundary layer (viscous sub-layer, buffer layer or log-law
layer), we take the mesh as a good one or we modify it if is deemed necessary.
• It is an iterative process and it can be very time consuming, as it might require remeshing and
rerunning the simulation.
• Have in mind that it is quite difficult to get a uniform y+ value at the walls.
• Try to get a y+ mean value as close as possible to your target.
• Also, check that you do not get very high maximum values of y+ (more than a 1000)
• Values up to 300 are fine. Values larger that 300 and up to a 1000 are acceptable is they do not
covert a large surface (no more than 10% of the total wall area), or they are not located in critical
zones.
• Remember, the upper limit of y+ also depends on the Reynolds number.
• Use common sense when accessing y+ value.

855
A crash introduction to turbulence modeling in OpenFOAM®

Estimating normal wall distance

• To get an initial estimate of the distance from the wall to the first cell center y+, without recurring
to a precursor simulation, you can proceed as follows,

1.
(Skin friction coefficient of a flat plate, there are
2. similar correlations for pipes)

3.

4.
Your desired value
5.

• You will find a simple calculator for the wall distance estimation in the following link:
http://www.wolfdynamics.com/tools.html?id=2
856
A crash introduction to turbulence modeling in OpenFOAM®

Wall distance units x+ – y+ – z+


• Similar to , the wall distance units can be
computed in the stream-wise ( ) and
span-wise ( ) directions.
• The wall distance units in the stream-wise
and span-wise directions can be computed
as follows:

• And recall that is computed at the cell


center, therefore:

where
Viscous length 857
A crash introduction to turbulence modeling in OpenFOAM®

Wall distance units and some rough estimates

• Similar to y+, the wall distance units can be computed in the stream-wise ( ) and
span-wise ( ) directions.
• DES and RANS simulations do not have stream-wise and span-wise wall distance units
requirements as in LES simulations. Therefore, they are more affordable.
• Typical requirements for LES are (these are approximations based on different references):

for Wall resolving

for Wall modeling


858
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling guidelines and tips

• Compute Reynolds number and determine whether the flow is turbulent.


• Try to avoid the use of turbulent models with laminar flows.
• Choose the near-wall treatment and estimate y before generating the mesh.
• Run the simulation for a few time steps and get a better prediction of y and correct your initial
prediction of y+.
• The realizable or models are good choices for general applications.
• The standard model is very reliable, you can use it to get initial values. Have in mind
that this model use wall functions.
• If you are interested in resolving the large eddies and modeling the smallest eddies, DES or LES
are the right choice.
• If you do not have any restriction in the near wall treatment method, use wall functions (even
with LES/DES models).
• Be aware of the limitations of the turbulence model chosen, find and read the original references
used to implement the model in OpenFOAM®.
• Set reasonable boundary and initial conditions for the turbulence model variables.

859
A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling guidelines and tips

• Always monitor the turbulent variables, some of them are positive bounded.
• Avoid strong oscillations of the turbulent variables.
• If you are doing LES, remember that these models are intrinsically 3D and unsteady. You should
choose your time-step in such a way to get a CFL of less than 1 and preferably of about 0.5.
• If you are doing RANS with wall functions, it is perfectly fine to use upwind to discretize the
turbulence closure equations. After all, turbulence is a dissipative process. However, some
authors may disagree with this, make your own conclusions.
• On the other hand, if you are using a wall resolved approach, it is better to use a high-order
discretization scheme to discretize the turbulence closure equations.
• If you are doing unsteady simulations, always remember to compute the average values
(ensemble average).
• If you are dealing with external aerodynamics and detached flows, DES simulations are really
affordable.
• The work-horse of turbulence modeling in CFD, RANS

860
Turbulence modeling hands-on tutorials

• Laminar-Turbulent flat plate


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/turbulence/flatPlate

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
861
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate

• The best way to understand the near the wall treatment and the effect of turbulence near the
walls, is by reproducing the law of the wall.
• By plotting the velocity in terms of the non-dimensional variables u+ and y+, we can compare
the profiles obtained from the simulations with the theoretical profiles. 862
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate
• In the directory python of each case, you will find a jupyter notebook (a python script), that you
can use to plot the non-dimensional u+ and y+ profiles.
• The notebook uses some precomputed results, but you can adjust it to any case.
• Remember, the u+ vs. y+ plot is kind of a universal plot.
• It does not matter your geometry or flow conditions, if you are resolving well the turbulent flow,
you should be able to recover this profile.
• To compute this plot, you must sample the wall shear stresses and the velocity along a line
normal to the wall.
• Then, you can compute the shear velocity, friction coefficient, and u+ and y+ values.

863
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate
• We are going to use the following solver: simpleFoam (for RANS).
• This case is rather simple, but we will use it to explain many features used in OpenFOAM®
when dealing with turbulence, especially when dealing with near the wall treatment.
• We will also show you how to do the post-processing in order to reproduce the law of the wall.
For this, we will use a jupyter notebook (a python script).
• Remember, as we are introducing new closure equations for the turbulence problem, we need to
define initial and boundary conditions for the new variables.
• We also need to define the discretization schemes and linear solvers to use to solve the new
variables.
• It is also a good idea to setup a few functionObjects, such as: y+, minimum and maximum
values, forces, time average, and online sampling.
• You will find the instructions of how to run this case in the file README.FIRST located in the
case directory.

864
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate
• We select the turbulence model in the momentumTransport dictionary file.
• This dictionary file is located in the directory constant.
• To select the K-Omega SST turbulence model,

17 simulationType RAS; RANS type simulation


18
19 RAS RANS sub-dictionary
20 {
21 RASModel kOmegaSST; RANS model to use

22 turbulence on; Turn on/off turbulence. Runtime modifiable

23 printCoeffs on; Print coefficients at the beginning


24 }

• Remember, you need to assign boundary and initial conditions to the new variables (k, omega,
and nut).

865
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• To define the wall functions, follow this table,

Field Wall functions – High RE Resolved BL – Low RE

nut nutUSpaldingWallFunction fixedValue 0 or a small number

k kqRWallFunction fixedValue 0 or a small number

omegaWallFunction omegaWallFunction
omega

• Run using high-RE and low-RE approaches.


• Compute the initial values of the turbulent quantities using a turbulent intensity value equal to
1% and an eddy viscosity ratio equal to 1.
• After computing the solution with model, try to setup the case using the standard
model and the realizable . 866
Turbulence modeling hands-on tutorials

• Vortex shedding past square cylinder


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/turbulence/squarecil

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
867
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder

Physical and numerical side of the


problem:
• The governing equations of the problem are the
incompressible Navier-Stokes equations.
• To model the turbulence, we will use two approaches,
LES and RANS.
• We are going to work in a 3D domain with periodic
boundary conditions.
• This problem has plenty of experimental data for
validation.

Working fluid: Water

868
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder

Turbulence model Drag coefficient Strouhal number Computing time (s)

Laminar 2.81 0.179 93489

LES 2.36 0.124 77465

DES 2.08 0.124 70754

SAS 2.40 0.164 57690

URANS (WF) 2.31 0.130 67830

URANS (No WF) 2.29 0.135 64492

RANS 2.30 - 28246 (10000 iter)

Experimental values 2.05-2.25 0.132 -

References:
Lyn, D.A. and Rodi, W., The flapping shear layer formed by flow separation from the forward corner of a square cylinder. J. Fluid Mech., 267, 353, 1994.
Lyn, D.A., Einav, S., Rodi, W. and Park, J.H., A laser-Doppler velocimetry study of ensemble-averaged characteristics of the turbulent near wake of a square
cylinder. Report. SFB 210 /E/100.
869
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• We will use this case to learn how to setup a turbulent case (RANS and LES).
• To run this case we will use the solvers simpleFoam (steady solver) and pimpleFoam
(unsteady solver).
• To get fast outcomes, we will use a coarse mesh. But feel free to refine the mesh, especially
close to the walls.
• Remember, as we are introducing new closure equations for the turbulence problem, we need to
define initial and boundary conditions for the new variables.
• We will use a few functionObjects to compute some additional quantities, such as, Q criterion,
y+, minimum and maximum values, forces, time average, and online sampling.
• After finding the solution, we will visualize the results.
• We will also compare the numerical solution with the experimental results.
• At the end, we will do some plotting and advanced post-processing using gnuplot and Python.
• Have in mind that the unsteady case will generate a lot of data.
• You will find the instructions of how to run this case in the file README.FIRST located in the
case directory.

870
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• We select the turbulence model in the momentumTransport dictionary file.
• This dictionary file is located in the directory constant.
• To select the LES (Smagorinsky) turbulence model,

17 simulationType LES; LES type simulation


18
19 LES LES sub-dictionary
20 {
21 LESModel Smagorinsky; LES model to use

24 turbulence on; Turn on/off turbulence. Runtime modifiable

25 printCoeffs on; Print coefficients at the beginning

27 delta cubeRootVol;
31 cubeRootVolCoeffs
LES filter
32 {
33 deltaCoeff 1;
34 }
100 }

• Remember, you need to assign boundary and initial conditions to the new variables (nut).
871
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• To define the wall functions, follow this table,

Field Wall functions – High RE Resolved BL – Low RE

nut nutUSpaldingWallFunction fixedValue 0 or a small number

k kqRWallFunction fixedValue 0 or a small number

omegaWallFunction omegaWallFunction
omega

• Run using the following combinations of wall functions and compare the outcome.
• Use High RE for RANS.
• Use High RE and Low RE for URANS.
• Use High RE and Low RE for LES.
872
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• The initial value for the turbulent kinetic energy can be found as follows,

• The initial value for the specific kinetic energy can be found as follows,

• Use the following initial estimates, and

• At this point, we are ready to run. But before running, remember to setup the right numerics in
the dictionary files fvSolution and fvSchemes.

• For the LES simulation, try to keep the CFL number below 0.9. For the URANS simulation, you
can go as high as 10.
• Finally, do not forget to setup the functionObjects to compute the forces, average values, do
the sampling, and compute y+ on-the-fly.
873
Roadmap

A crash introduction to:


1. Turbulence modeling in OpenFOAM®
2. Multiphase flows modeling in
OpenFOAM®
3. Compressible flows in OpenFOAM®
4. Moving bodies in OpenFOAM®
5. Source terms in OpenFOAM®
6. Scalar transport pluggable solver

874
A crash introduction to multiphase flows modeling OpenFOAM®

What is a multiphase flow?


• A multiphase flow is a fluid flow consisting of more than one phase component and have some
level of phase separation above molecular level.
• Multiphase flows exist in many different forms. For example, two phase flows can be classified
according to the state of the different phases:
• Gas-Liquid mixture.
• Gas-Solid mixture.
• Liquid-Solid mixture.
• Immiscible liquid-liquid.
• Multiphase flows are present in many industrial processes and natural systems.
• Hence the importance of understanding, modeling, and simulating multiphase flows.

875
A crash introduction to multiphase flows modeling OpenFOAM®

Examples of multiphase flows

Municipal and industrial water treatment Cargo ship wake


http://www.asiapacific.basf.com/apex/AP/en/upload/Press2010/BASF-Water-Chem-2010-Paper- http://developeconomies.com/development-economics/how-to-get-america-back-on-track-free-trade-edition/
Chem-2010-Intex-Shanghai

Propeller cavitation
http://www.veempropellers.com/features/cavitationresistance
Siltation & Sedimentation
http://blackwarriorriver.org/siltation-sedimentation/

876
A crash introduction to multiphase flows modeling OpenFOAM®

Examples of multiphase flows

Cooling Towers Volcano eruption


https://whatiswatertreatment.wordpress.com/what-are-the-systems-associated-with-water-
http://americanpreppersnetwork.com/2014/08/preparing-volcano-eruption.html
treatment-and-how-are-they-treated/103-2/

Fermentation of beer and spirits Chemical reactor for the pharmaceutical and
http://www.distillingliquor.com/2015/02/05/how-to-make-alcohol-and-spirits/ biotechnology industry
http://www.total-mechanical.com/Industrial/CaseStudies.aspx
877
A crash introduction to multiphase flows modeling OpenFOAM®

Why simulating multiphase flows is challenging?


• Simulating multiphase flows is not an easy task.
• The complex nature of multiphase flows is due to:
• More than one working fluid.
• The transient nature of the flows.
• The existence of dynamically changing interfaces.
• Significant discontinuities (fluid properties and fluid separation).
• Complicated flow field near the interface.
• Interaction of small-scale structures (bubbles and particles).
• Different spatial-temporal scales.
• Dispersed phases and particle-particle interactions.
• Mass transfer and phase change.
• Turbulence.
• Many models involved (drag, lift, heat transfer, turbulence dispersion, frictional
stresses, collisions, kinetic theory, and so on).

878
A crash introduction to multiphase flows modeling OpenFOAM®

Classifying multiphase flows according to phase morphology

• Disperse system: the phase is dispersed as non-contiguous isolated regions within the other
phase (the continuous phase) . When we work with a disperse phase, we say that the system is
dispersed: disperse-continuous flow.
• Separated system: the phase is contiguous throughout the domain and there is one well
defined interphase with the other phase. When we work with continuous phases, we say that the
system is separated: continuous-continuous flow.

Dispersed system Separated system

879
A crash introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in multiphase flows

Increase

Modeling requirements
• Fully resolved: solves complete physics. All spatial and temporal scales
are resolved. Equivalent to DNS in turbulence modelling.

• Eulerian-Lagrangian: solves idealized isolated particles that are

Computational power
transported with the flow. One- or two-way coupling is possible. It can
account for turbulence, momentum transfer, and mass transfer.

• Eulerian-eulerians: solves two or more co-existing fluids. The system can


be dispersed or separated, and can account for turbulence, momentum
transfer, and mass transfer.
Increase

880
A crash introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in multiphase flows

VOF ≈ 0.5
Average phase
properties

• Dispersed phase in a continuous phase.


• In this case, the VOF method is not able to handle
bubbles smaller than grid scales.
• Multi-fluid and mixture models are able to model • Multi-fluid and mixture approaches can model
bubbles smaller than grid scales by averaging the bubble coalescence, bubble break-up and
phase properties in the discrete domain. wake entrainment in dispersed systems.

In theory, the VOF method can resolve the smallest bubbles/droplets but the mesh requirements are
too prohibitive (equivalent to DNS). In multiphase flows, this is called fully resolved approach.
881
A crash introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in multiphase flows

• When using multi-fluid and mixture


approaches, interfacial momentum
transfer models must be taken into
account in order to model mass
transfer and phases interaction.

• As for turbulence modeling, there is


no universal model.

• It is up to you to choose the model


that best fit the problem you are
solving.

• Depending on the physics involved,


you will find different models and
formulations

• You need to know the applicability and


limitations of each model, for this,
refer to the literature.

882
A crash introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in multiphase flows

The particles position is


tracked by solving an ODE
for each particle
The continuous phase is
solved in the mesh

• In the Eulerian-Lagrangian framework, the continuous phase is solved in an Eulerian reference


system and the particles or dispersed phase is solved in a Lagrangian reference system.
• The particles can be smaller or larger than the grid size.
• The particles can be transported passively, or they can be coupled with the fluid governing
equations.
• It accounts for particle interaction and mass transfer.
• The particles can interact with the boundaries and have a fate. 883
A crash introduction to multiphase flows modeling OpenFOAM®

Multiphase flows – Grid scales


Free surface (system scale)
• Applicability of the VOF method to separated
systems (non-interpenetrating continua).
• In the figure, the free surface and large
bubbles can be track/resolve by the mesh.
• The smaller the features we want to
track/resolve, the smaller the cells should be.
• Bubbles, droplets and/or particles larger than
Medium bubbles Large bubbles grid scales (GS), can be resolved using VOF.
(system-scales) (system scale)
• To resolve a bubble you will need at least two
cells in every direction
• Bubbles, droplets and/or particles smaller
than grid scales (sub-grid scales or SGS), can
not be resolve using the VOF method.
Bubble break-up • In such a case, we need to use models.
and coalescence
Small bubbles interaction and (meso-scales) • Also, bubble break-up, coalescence and
motion of small particles entrainment must be modeled, unless the
(micro-scales) mesh is fine enough so it captures the
dynamics and solves the smallest scales.

Multiphase flows are


transient and multiscale
884
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose.
A crash introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows

Eulerian-Eulerian Eulerian-Eulerian
Eulerian-Lagrangian
(VOF) (Dispersed systems)

• Non-interpenetrating continua. • Interpenetrating continua. • Continuous phase: Eulerian.


• Continuous phases: Eulerian. • Continuous phase: Eulerian. • Dispersed phase: Lagrangian.
• Fluid properties are written on • Dispersed phase: Eulerian. • Solves ODEs for particle
either side of the interface (no tracking (for every single
• Phase-weighted averages.
averaging). particle).
• Solves PDEs for all phases
• Solves one single set of PDEs: • Solves a set of PDEs for the
(including interphase transfer
mass, momentum, energy. continuous phase: mass,
terms): mass, momentum,
momentum, energy.
energy.
• Phase interaction terms
• It can deal with gas-liquid, gas-
(including interphase transfer
solid, and liquid-solid
terms).
interactions.

885
A crash introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows

www.wolfdynamics.com/training/mphase/image10.gif http://www.wolfdynamics.com/training/mphase/image16.gif

• Simulations showing free surface tracking using the VOF approach


• The left image corresponds to a simulation with rigid body motion and accurate surface tracking using the VOF
method.
886
A crash introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows

http://www.wolfdynamics.com/training/mphase/image2.gif http://www.wolfdynamics.com/training/mphase/image3.gif

• Simulation showing free surface tracking, bubble tracking, bubble coalescence, bubble break-up and wake
entrainment using the VOF method.
• In this simulation the free surface and bubbles are capture by using AMR.
• However, the smallest bubble that can be resolved is at the smallest grid size. 887
A crash introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows

http://www.wolfdynamics.com/training/mphase/image18.gif

• Eulerian-Eulerian simulation (gas-liquid).


• The bubbles are not being solved, instead, the interaction between phase is being averaged.

References:
[1] Vivek V. Buwa, Vivek V. Ranade, Dynamics of gas–liquid flow in a rectangular bubble column: experiments and single/multi-group CFD simulations.
Chemical Engineering Science 57 (2002) 4715 – 4736 888
A crash introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows

twoPhaseEulerFoam twoPhaseEulerFoam
Air volume fraction Air volume fraction
Turbulent case Laminar case
http://www.wolfdynamics.com/training/mphase/image42.gif http://www.wolfdynamics.com/training/mphase/image41.gif

• Eulerian-Eulerian simulations using the Eulerian-Granular KTGF approach (solid-gas).


• The granular phase is simulated as continuous phase.
• In these simulations we can observe the influence of turbulence modeling in the solution. 889
A crash introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows

DPMFoam twoPhaseEulerFoam
Particle-particle interactions colored by velocity Air volume fraction
magnitude (particles not to scale) Turbulent case
http://www.wolfdynamics.com/training/mphase/image43.gif http://www.wolfdynamics.com/training/mphase/image42.gif

• Comparison of an Eulerian-Lagrangian simulation and an Eulerian-Eulerian simulation (gas-solid).


• In the Eulerian-Lagrangian approach we track the position of every single particle. We also solve the fate and
interaction of all particles.
• In the Eulerian-Eulerian approach we solve the granular phase as a continuous phase.
• The computational requirements of the Eulerian-Eulerian simulation are much lower than those for the
Eulerian-Lagrangian simulation. 890
A crash introduction to multiphase flows modeling OpenFOAM®

Volume-of-Fluid (VOF) governing equations for separated systems


• The incompressible, isothermal governing equations can be written as follows,

Source terms:
• Porous media
• Coriolis forces
• Centrifugal forces
Surface tension - Continuum surface force (CSF) • Mass transfer
• and so on …

Phase transport equation and interface


tracking with surface compression

Volume fraction (bounded quantity)

• You can see the volume fraction as a pointer that indicates what phase (with the
corresponding physical properties), is inside each cell of the computational domain. 891
A crash introduction to multiphase flows modeling OpenFOAM®

Volume-of-Fluid (VOF) governing equations for separated systems

• For example, in the case of two phases where


phase 1 is represented by and phase 2 is 0 0 0 0.1 0.3
represented by ; a volume fraction value of
1 indicates that the cell is fill with phase 1; a volume
fraction of 0.8 indicates that the cell contains 80%
0 0 0.3 0.8 1
of a phase 1; and a volume fraction of 0, indicates
that the cell is fill with phase 2. 0 0.1 0.8 1 1
• The values between 0 and 1 can be seen as the
interface between the phases. 0 0.4 1 1 1
Interface

• The fluid properties can be written on either side of the interface as follows,

892
A crash introduction to multiphase flows modeling OpenFOAM®

Eulerian-Eulerian governing equations for dispersed systems


• The Eulerian-Eulerian approach solves the governing equations for each phase, it treats the
phases as interpenetrating continua.
• The incompressible, isothermal governing equations with interface tracking can be written as
follows,
Surface tension - Continuum surface force (CSF)

Interface forces or momentum transfer.


Bubbles interaction models

Source terms:
• Porous media
• Coriolis forces
• Centrifugal forces
• Mass transfer
• and so on …

893
A crash introduction to multiphase flows modeling OpenFOAM®

Eulerian-Lagrangian governing equations


• In the Eulerian-Lagrangian framework, the continuous phase is solved in an Eulerian reference
system and the particles or dispersed phase is solved in a Lagrangian reference system.
• The particles can be transported passively, or they can be coupled with the fluid governing
equations (they can modify the fluid field).
• The particles motion is calculated by solving an ODE for every single particle (Newton-Euler
equation of motion).
• The particles can interact with the boundaries, they can escape, bounce, stick, or form a wall
film.
• This formulation accounts for particle interaction and mass transfer.
• The governing equations can be written as follows,

Any of the Eulerian formulations (single or multi-phase)


894
A crash introduction to multiphase flows modeling OpenFOAM®

Multiphase solvers in OpenFOAM®


• In OpenFOAM®, there are many interfacial momentum transfer models implemented.
• There are also many models for Eulerian-Lagrangian methods.
• No need to say that turbulence also applies to multiphase flows.
• There is no universal model, it is up to you to choose the model that best fit the problem you are
solving.
• You need to know the applicability and limitations of each model, for this, refer to the literature.
• When dealing with multiphase flows in OpenFOAM®, you can use VOF, Eulerian-Eulerian,
Eulerian-Eulerian with VOF, and Eulerian-Lagrangian methods.
• The solution methods can account for turbulence models, interface momentum transfer models,
mass transfer models, particle interaction models and so on.
• It is also possible to add source terms, deal with moving bodies or use adaptive mesh
refinement.
• You will find the source code of all the multiphase solvers in the directory:
• OpenFOAM-8/applications/solvers/multiphase
• You will find the source code all the particle tracking solvers in the directory:
• OpenFOAM-8/applications/solvers/lagrangian
895
A crash introduction to multiphase flows modeling OpenFOAM®

Multiphase solvers in OpenFOAM®


• These are the multiphase solvers that you will use most of the time in OpenFOAM®.

• The VOF approach:


• interFoam family solvers

• The Eulerian-Eulerian approach:


• twoPhaseEulerFoam, multiphaseEulerFoam

• The Eulerian-Granular KTGF (kinetic theory of granular flows) approach.


• twoPhaseEulerFoam

• The Eulerian-Lagrangian framework,


• DPMFoam, MPPICFoam

896
Multiphase flows hands-on tutorials

• Free surface – Ship resistance simulation


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/multiphase/wigleyHull

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
897
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation

Free surface colored by height


http://www.wolfdynamics.com/training/mphase/image45.gif 898
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
Water level – Height (m)

Drag coefficient

Hull position Time (s)

Comparison of water level on hull surface


Drag coefficient monitor

899
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• We are going to use the following solver: interFoam
• The first step is to set the physical properties. In the dictionary
constant/transportProperties we defined the phases.
• Go to the directory constant and open the dictionary transportProperties.
The first phase is always considered the primary phase

Phases naming convention.


The name of the phases is chosen by phases (water air);
the user.

water properties water


{
transportModel Newtonian;
nu nu [ 0 2 -1 0 0 0 0 ] 1.09e-06;
rho rho [ 1 -3 0 0 0 0 0 ] 998.8;
}

air properties air


{
transportModel Newtonian;
nu nu [ 0 2 -1 0 0 0 0 ] 1.48e-05;
rho rho [ 1 -3 0 0 0 0 0 ] 1;
}

Surface tension between phase1 sigma sigma [ 1 0 -2 0 0 0 0 ] 0.07;


and phase2

900
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• The next step is to set the boundary conditions and initial conditions.
• Therefore, in the directory 0 we define the dictionary alpha.water that will take the values of
the phase water.
• In this case, you will find the directory 0_org, here is where we keep a backup of the original
files as we are doing field initialization using setFields.
• In the directory 0, you will find the dictionary p_rgh, in this dictionary we set the boundary and
initial conditions for the pressure field, and the dimensions are in Pascals.
• The turbulence variables values were calculated using an eddy viscosity ratio equal to 1,
turbulence intensity equal 5%, and the water properties.
• If you are simulating numerical towing tanks, the setup of the boundary conditions is always the
same.
• Feel free to reuse this setup.
• The dictionaries used in this case are standard for the VOF solvers (interFoam family solvers).
• If you are using a different solver (e.g., twoPhaseEulerFoam), you will need to use additional
dictionaries where you define the interfacial models and so on.
• Remember, you should always conduct production runs using a second order discretization
scheme
901
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
Opening
Air phase Wall

Inlet outlet

Water phase Slip

Note:
Phases must be initialized
on the internal cells and
boundary faces

Symmetry
Physical domain and boundary patches 902
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation

Patch name Pressure Velocity Turbulence fields alpha.water

fixedValue
inflow fixedFluxPressure fixedValue fixedValue
calculated (nut)

inletOutlet
outflow inletOutlet or zeroGradient outletPhaseMeanVelocity variableHeightFlowRate
calculated (nut)

bottom symmetry symmetry symmetry symmetry

midplane symmetry symmetry symmetry symmetry

side symmetry symmetry symmetry symmetry

inletOutlet
top totalPressure pressureInletOutletVelocity inletOutlet
calculated (nut)

kqRWallFunction (k)
ship fixedFluxPressure fixedValue omegaFunction (omega) zeroGradient
nutkWallFunction (nut)

Typical setup of boundary conditions for numerical towing tank simulations 903
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• OpenFOAM® solves the following modified volume fraction convective equation to track the
interface between the phases,

(phi, alpha) (phirb, alpha)


Use a TVD scheme with gradient limiters. Use a high order scheme. The use of linear
Good choice is the vanLeer scheme. interpolation is fine for this term.

• Where a value of (cAlpha), is recommended to accurately resolve the sharp interface.


• To solve this equation, OpenFOAM® uses the semi-implicit MULES method.
• The MULES options can be controlled in the fvSolution dictionary.

904
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• MULES options in the fvSolution dictionary.
• The semi-implicit MULES offers significant speed-up and stability over the explicit MULES.

“alpha.*”
{
MULESCorr yes; Turn on/off semi-implicit MULES
nAlphaSubCycles 1; For semi-implicit MULES use 1. Use 2 or more for
explicit MULES.
nAlphaCorr 3; Number of corrections.
Use 2-3 for slowly varying flows.
Use 3 or more for highly transient, high Reynolds,
high CFL number flows.

nLimiterIter 10; Number of iterations to calculate the MULES


limiter. Use 3-5 if CFL number is less than 3. Use
5-10 if CFL number is more than 3.

alphaApplyPrevCorr yes; Use previous time corrector as initial estimate.


… Set to yes for slowly varying flows. Set to no for
highly transient flows.
}
905
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• Additional notes on the fvSolution dictionary.

Set to yes for high Reynolds flows, where


momentumPredictor yes; convection dominates
Recommended value is 1 (equivalent to PISO).
nOuterCorrectors 1; Increase to improve the stability of second
order time discretization schemes (LES
simulations).
Increase for highly coupled problems.
Recommended to use at least 2 correctors.
nCorrector 3; It improves accuracy and stability.

nNonOrthogonalCorrectors 2; Recommend to use at least 1 corrector.


Increase the value for bad quality meshes.

• If you are planning to use large time-steps (CFL number larger than 1), it is recommended to do
at least 3 nCorrector, otherwise you can use 2.

906
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• Finally, we need to set the discretization schemes
• This is done in the dictionary fvSchemes.
• In this dictionary we set the discretization method for every term appearing in the governing
equations.
• Convective terms discretization is set as follows:

divSchemes
{
This term is related to the
volume fraction equation

div(rhoPhi,U) Gauss linearUpwind grad(U);

div(phi,alpha) Gauss interfaceCompression vanLeer 1;

div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear;


}

• Notice that we are using a high-resolution scheme for the surface tracking (div(phi,alpha)).

907
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• For time discretization we can use an unsteady formulation (Euler in this case).
• This scheme requires setting the time-step, and it should be choosing in such a way that it
resolves the mean physics.
• Remember, as the free surface is a strong discontinuity, for stability and good resolution we
need to use a CFL less than one for the interface courant.

ddtSchemes
{
default Euler;
}

• Hereafter, we are using what is know as global time stepping, that is, the CFL number is limited
by the smallest cell.
• The simulation is time-accurate, but it requires a lot of CPU time to reach a steady state (if it
reaches one).
908
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• A way to accelerate the convergence to steady state, is by using local time stepping (LTS).
• In LTS, the time-step is manipulated for each individual cell in the mesh, making it as high as
possible to enable the simulation to reach steady-state quickly.
• When we use LTS, the transient solution is no longer time accurate.
• The stability and accuracy of the method are driven by the local CFL number of each cell.
• To avoid instabilities caused by sudden changes in the time-step of each cell, the local time-
step can be smoothed and damped across the domain.
• Try to avoid having local time-steps that differ by several order of magnitudes.
• To enable LTS, we use the localEuler method.

ddtSchemes
{
default localEuler;
}

• LTS in OpenFOAM® can be used with any solver that supports the PISO or PIMPLE loop
(PISO ITA). 909
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• In the LTS method, the maximum flow CFL number, maximum interface CFL number, and the
smoothing and damping of the solution across the cells, can be controlled in the dictionary
fvSolution, in the sub-dictionary PIMPLE.

PIMPLE
{
momentumPredictor yes;

nOuterCorrectors 2;
nCorrector 3;
nNonOrthogonalCorrectors 2;

maxCo 10; Maximum flow Courant


Maximum interface maxAlphaCo 1;
Courant
rDeltaTSmoothingCoeff 0.05; Local time step
Local time step rDeltaTDampingCoeff 0.5; smoothing
damping
Limit the maximum
maxDeltaT 1;
time-step size
}

910
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• At this point, we are ready to run the simulation.
• Remember to adjust the numerics according to your physics.
• You can choose between running using global time stepping or unsteady (directory uns) or local
time stepping (directory LTS).
• You will find the instructions of how to run the cases in the file README.FIRST located in the
case directory.

911
Roadmap

A crash introduction to:


1. Turbulence modeling in OpenFOAM®
2. Multiphase flows modeling in
OpenFOAM®
3. Compressible flows in OpenFOAM®
4. Moving bodies in OpenFOAM®
5. Source terms in OpenFOAM®
6. Scalar transport pluggable solver

912
A crash introduction to compressible flows modeling OpenFOAM®

What are compressible flows?


• In few words, compressible flows are flows where the density change.
• The changes in density can be due to velocity, pressure, or temperature variations.
• Compressible flows can happen at low speed (subsonic) or high speed (transonic, supersonic,
hypersonic and so on).
• Buoyancy-driven flows are also considered compressible flows. After all, the buoyancy is due to
temperature gradients.
• In compressible flows, the viscosity also changes with temperature.
• The thermodynamical variables are related via an equation of state (e.g., ideal gas law).
• In principle, all flows are compressible.
• Usually, compressibility effects start to become significant when the Mach number is
higher than 0.3.

913
A crash introduction to compressible flows modeling OpenFOAM®

A few compressible flows applications


• The following applications fall within the compressible flows classification:
• External and internal aerodynamics (high speed).
• Heat transfer and conjugate heat transfer.
• Fire dynamics.
• Buoyancy driven flows
• Heating, ventilation, and air conditioning (HVAC).
• Thermal comfort.
• Turbomachinery.
• Combustion.
• Chemical reactions.
• Condensation, evaporation, and melting.
• Cavitation.
• And many more.

• As you can see, the range of applicability is very wide.


914
A crash introduction to compressible flows modeling OpenFOAM®

Large Natural Convection Plume, as effect of combustion of excess Rayleigh–Bénard convection cells
non-useable gases behind oilfield. https://en.wikipedia.org/wiki/File:B%C3%A9nard_cells_convection.ogv
https://en.wikipedia.org/wiki/Plume_(fluid_dynamics)#/media/File:Naturalc
onvectionplume.JPG

Iron melting Airplane thermal image


https://commons.wikimedia.org/wiki/File:Iron_-melting.JPG http://www.blackroc.com/wp-content/uploads/2016/03/thermal-image.jpg

Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 915
A crash introduction to compressible flows modeling OpenFOAM®

Shadowgraph Images of Re-entry Vehicles


Photo credit: NASA on the Commons.
https://www.flickr.com/photos/nasacommons/

Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 916
A crash introduction to compressible flows modeling OpenFOAM®

Compressible flows – Starting equations

NSE

Equation of state and thermodynamics relations (thermophysical models)

Additional closure equations for turbulence models, multiphase models, combustion, particles,
source terms, and so on
917
A crash introduction to compressible flows modeling OpenFOAM®

Compressible flows – Boundary layer

Thermal boundary layer vs. Viscous boundary layer Thermal boundary layer in function of Prandtl number (Pr)
Forced convection

Momentum and thermal boundary layer

• Just as there is a viscous (or momentum) boundary layer in the velocity distribution, there is also a thermal
boundary layer.
• Thermal boundary layer thickness is different from the thickness of the viscous sublayer (or momentum), and
is fluid dependent.
• The thickness of the thermal sublayer for a high Prandtl number fluid (e.g. water) is much less than the
momentum sublayer thickness.
• For fluids of low Prandtl numbers (e.g., air), it is much larger than the momentum sublayer thickness.
• For Prandtl number equal 1, the thermal boundary layer is equal to the momentum boundary layer. 918
A crash introduction to compressible flows modeling OpenFOAM®

Compressible flows – Boundary layer

Horizontal heated plate immersed in a quiescent fluid. Vertical heated plate immersed in a quiescent fluid.
Natural convection Natural convection.

Natural convection in a heated plate

• As the fluid is warmed by the plate, its density decreases, and a buoyant force arises which induces flow
motion in the vertical or horizontal direction.
• The force is proportional to , therefore gravity must be considered. 919
A crash introduction to compressible flows modeling OpenFOAM®

Compressible solvers in OpenFOAM®


• Dealing with compressible flows in OpenFOAM® is not so different from what we have
done so far.
• The new steps are:
• Define the thermophysical variables.
• Define the boundary conditions and initial conditions for temperature.
• If you are dealing with turbulence (most of the times), you will need to define the boundary
conditions and initial conditions for the turbulent thermal diffusivity.
• Do not forget to choose the near-wall treatment.
• Depending on the thermophysical model and physics involved, you will need to define
discretization schemes and linear solvers for the new variables and equations, that is, T, h,
e and so on.
• Define solver parameters for the new variables, that is, under-relaxation factors,
SIMPLE/PISO/PIMPLE corrections, maximum and minimum allowable pressure or density
values, high-speed corrections, and so on.
• Remember, as for pressure, mesh non-orthogonality and skewness also introduces
secondary gradients in the energy equation, .

920
A crash introduction to compressible flows modeling OpenFOAM®

Compressible solvers in OpenFOAM®


• Additionally, the numerics of compressible solvers is a little bit more delicate.
• Temperature is a bounded quantity, so we need to use accurate and stable methods
(preferably TVD).
• If you are in the presence of shock waves, you need to use TVD methods and gradient
limiters.
• The solvers are very sensitive to overshoots and undershoots in the gradients, so you need
to use aggressive limiters.
• If you are dealing with chemicals reactions or combustion, you need to use accurate and
stable methods (preferably TVD).
• TVD methods requires good meshes and CFL number below 1 for good accuracy and
stability.
• Using steady solvers requires tuning of the under-relaxation factors. Usually, the default
values do not work well.
• The use of local time stepping to reach steady state can improve the convergence rate.
• FYI, we have found that it is tricky to achieve good convergence using a low-RE approach with
steady solvers in high-speed compressible flows.

921
A crash introduction to compressible flows modeling OpenFOAM®

Compressible solvers in OpenFOAM®


• OpenFOAM® comes with many solvers and models that can address a wide physics.
• Compressibility can be introduced in all the modeling capabilities we have seen so far
(turbulence modeling and multiphase flows).
• It is also possible to add source terms, deal with moving bodies, or use adaptive mesh
refinement.
• You will find the source code of all the compressible solvers in the directories:
• OpenFOAM-8/applications/solvers/compressible
• OpenFOAM-8/applications/solvers/combustion
• OpenFOAM-8/applications/solvers/heatTransfer
• OpenFOAM-8/applications/solvers/lagrangian
• OpenFOAM-8/applications/solvers/multiphases
• You will find the source code of the thermophysical models in the directory:
• OpenFOAM-8/src/thermophysicalModels
• OpenFOAM-8/src/ThermophysicalTransportModels

922
A crash introduction to compressible flows modeling OpenFOAM®

Compressible solvers in OpenFOAM®


• These are the compressible solvers that you will use most of the time in OpenFOAM®.

• HVAC and low-speed aerodynamics:


• rhoSimpleFoam, rhoPimpleFoam

• High-speed aerodynamics:
• rhoSimpleFoam, rhoPimpleFoam, rhoCentralFoam

• Buoyancy driven flows (including Boussinesq approximation):


• buoyantSimpleFoam, buoyantPimpleFoam

• Conjugate heat transfer


• chtMultiRegionFoam

923
A crash introduction to compressible flows modeling OpenFOAM®

Selecting thermophysical properties

• The thermophysical properties are set in the dictionary


1 thermoType thermophysicalProperties.
2 {
3 type hePsiThermo; • This dictionary file is located in the directory constant.
4 mixture pureMixture;
5 transport const; • Thermophysical models are concerned with energy, heat
6 thermo hConst;
7 equationOfState perfectGas;
and physical properties.
8 specie specie;
• In the sub-dictionary thermoType (lines 1-10), we define
9 energy sensibleEnthalpy;
10 } the thermophysical models.
11
12 mixture • The entries in lines 3-4, are determined by the choice of
13 { the solver (they are hardwired to the solver).
14 specie
15 { • The transport keyword (line 5). concerns evaluating
16 nMoles 1; dynamic viscosity. In this case the viscosity is constant.
17 molWeight 28.9;
18 } • The thermodynamic models (thermo keyword) are
19 thermodynamics
20 {
concerned with evaluating the specific heat Cp (line 6). In
21 Cp 1005; this case Cp is constant.
22 Hf 0;
23 } • The equationOfState keyword (line 7) concerns to the
24 transport equation of state of the working fluid. In this case,
25 {
26 mu 0;
27 Pr 0.713;
28 }
29 }
• Line 8 is a fixed option (hardwired to the solver). 924
A crash introduction to compressible flows modeling OpenFOAM®

Selecting thermophysical properties

• The form of the energy equation to be used is specified


1 thermoType in line 9 (energy).
2 {
3 type hePsiThermo; • In this case we are using enthalpy formulation
4 mixture pureMixture;
5 transport const;
(sensibleEnthalpy).
6 thermo hConst;
7 equationOfState perfectGas;
• In this formulation, the following equation is solved,
8 specie specie;
9 energy sensibleEnthalpy;
10 }
11
12 mixture
13 { • Alternatively, we can use the sensibleInternalEnergy
14 specie formulation, where the following equation is solved for
15 { the internal energy,
16 nMoles 1;
17 molWeight 28.9;
18 }
19 thermodynamics
20 {
21 Cp 1005; • In the previous equations, the effective thermal diffusivity
22 Hf 0;
23 }
is equal to,
24 transport
25 {
26 mu 1.84e-05;
27 Pr 0.713;
28 }
29 } • And is the kinetic energy per unit mass.
925
A crash introduction to compressible flows modeling OpenFOAM®

Selecting thermophysical properties

• In the sub-dictionary mixture (lines 12-29), we define the


1 thermoType
2 {
thermophysical properties of the working fluid.
3 type hePsiThermo; • In line 17, we define the molecular weight.
4 mixture pureMixture;
5 transport const; • In line 21, we define the specific heat.
6 thermo hConst;
7 equationOfState perfectGas; • The heat of formation is defined in line 22 (not used in
8 specie specie;
9 energy sensibleEnthalpy;
this case).
10 }
11
• In this case, we are defining the properties for air at 20°
12 mixture Celsius and at a sea level.
13 {
14 specie • As we are using the transport model const (line 5), we
15 { need to define the dynamic viscosity and Prandtl number
16 nMoles 1; (lines 26 and 27).
17 molWeight 28.9;
18 } • If you set the viscosity to zero, you solve the Euler
19 thermodynamics
20 {
equations.
21 Cp 1005;
22 Hf 0;
• Remember, transport modeling (line 5), concerns
23 } evaluating dynamic viscosity, thermal conductivity and
24 transport thermal diffusivity.
25 {
26 mu 1.84e-05;
27 Pr 0.713;
28 }
29 }

926
A crash introduction to compressible flows modeling OpenFOAM®

Selecting thermophysical properties

• If you use the transport model sutherland (line 5), you


1 thermoType
2 {
will need to define the coefficients of the Sutherland
3 type hePsiThermo; model.
4 mixture pureMixture;
5 transport sutherland; • The Sutherland model is defined as follows
6 thermo hConst; (OpenFOAM® uses the 2 coefficients formulation):
7 equationOfState perfectGas;
8 specie specie;
9 energy sensibleEnthalpy;
10 }
11
12 mixture
13 {
14 specie
15 {
16 nMoles 1; • The Sutherland coefficients are defined in lines 26-27.
17 molWeight 28.9;
18 }
19 thermodynamics
20 {
21 Cp 1005;
22 Hf 0;
23 }
24 transport
25 {
26 As 1.4792e-06; • Remember, you can use the banana method
27 Ts 116; to know all the options available.
28 }
29 }

927
A crash introduction to compressible flows modeling OpenFOAM®

Adjusting the numerical method


• If you choose the sensibleEnthalpy formulation, you need to define the convective
discretization schemes and linear solvers of the energy equation (enthalpy formulation).
fvSchemes fvSolution

divSchemes “( | )”
{ {
div(phi,K) Gauss linear; solver PBiCGStab;
div(phi,h) Gauss linear; preconditioner DILU;
div(phid,p) Gauss linear; tolerance 1e-8;
… relTol 0.01;
… }
… …
} …

• Remember, temperature is a bounded quantity, so you need to use non-oscillatory methods.


• For low speed flows, the kinetic energy K and the enthalpy h can be discretized using the linear
method. For high speed flows, is better to use bounded methods.
• Remember to use gradient limiters.
• If you are using a steady solver, remember to set the under-relaxation factors for h and rho. 928
A crash introduction to compressible flows modeling OpenFOAM®

Adjusting the numerical method


• If you choose the sensibleInternalEnergy formulation, you need to define the convective
discretization schemes and linear solvers of the energy equation (internal energy formulation).
fvSchemes fvSolution

divSchemes “( | )”
{ {
div(phi,K) Gauss linear; solver PBiCGStab;
div(phi,e) Gauss linear; preconditioner DILU;
div(phiv,p) Gauss linear; tolerance 1e-8;
… relTol 0.01;
… }
… …
} …

• Remember, temperature is a bounded quantity, so you need to use non-oscillatory methods.


• For low speed flows, the kinetic energy K and the internal energy e can be discretized using the
linear method. For high speed flows, is better to use bounded methods.
• Remember to use gradient limiters.
• If you are using a steady solver, remember to set the under-relaxation factors for e and rho. 929
A crash introduction to compressible flows modeling OpenFOAM®

Final remarks
• When solving the enthalpy formulation of the energy equation,

the pressure work term can be excluded from the solution.

• This has a stabilizing effect on the solution, specially if you are using steady solvers.
• To turn off the pressure work term , set the option dpdt to no ( dpdt no; ) in the
thermophysicalProperties dictionary.

• Finally, when you work with compressible solvers you use absolute pressure
and the working units are in Pascals.

930
Compressible flows hands-on tutorials

• 2D supersonic cylinder – Shock waves


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/compressible/supersonic_cyl

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
931
Compressible flows hands-on tutorials
2D supersonic cylinder – Shock waves

Shock wave visualization using numerical Schlieren (density gradient)

• Shock waves are strong discontinuities that need to be treated using high resolution schemes.
• Additionally, the non-orthogonality add extra complications to this problem.

932
Compressible flows hands-on tutorials
2D supersonic cylinder – Shock waves

Mach number contours Schlieren contours


http://www.wolfdynamics.com/training/compressible/image3.gif http://www.wolfdynamics.com/training/compressible/image4.gif

933
Compressible flows hands-on tutorials
2D supersonic cylinder – Shock waves
• In this case we will use the solver rhoPimpleFoam with transonic corrections.
• By enabling transonic correction we can use this solver to tackle trans-sonic/supersonic flows.
• Transonic corrections are enabled in the PIMPLE block of the dictionary fvSolution,
• transonic yes;
• rhoPimpleFoam is an unsteady solver, but if you are interested in a steady solution you can
use local time stepping.
• As the flow is compressible, we need to define the thermodynamical properties of the working
fluid.
• This is done in the dictionary constant/thermophysicalProperties.
• We also need to define the boundary conditions and initial conditions for the temperature field.
• Additionally, if you are using a turbulence model, you will need to define wall functions for the
thermal diffusivity.
• The rest of the turbulent variables are defined as in incompressible flows.
• Finally, adjust the numerics according to your physics.
• You will find the instructions of how to run the cases in the file README.FIRST located in the
case directory.
934
Roadmap

A crash introduction to:


1. Turbulence modeling in OpenFOAM®
2. Multiphase flows modeling in
OpenFOAM®
3. Compressible flows in OpenFOAM®
4. Moving bodies in OpenFOAM®
5. Source terms in OpenFOAM®
6. Scalar transport pluggable solver

935
A crash introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM® – A few examples

Sloshing tank Oscillating cylinder (prescribed motion)


http://www.wolfdynamics.com/training/dynamicMeshes/sloshing1.gif http://www.wolfdynamics.com/training/dynamicMeshes/meshMotion1

Prescribed motion with multiple bodies Layering with mesh zones interface
http://www.wolfdynamics.com/training/dynamicMeshes/meshMotion1 http://www.wolfdynamics.com/training/dynamicMeshes/layeringMesh.gif936
A crash introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM® – A few examples

Sea keeping Continuous stirring tank reactor (CSTR)


http://www.wolfdynamics.com/training/dynamicMeshes/seakeeping.gif http://www.wolfdynamics.com/training/movingbodies/image13.gif

Falling body (6 DoF) VOF with sliding meshes


http://www.wolfdynamics.com/training/movingbodies/image5.gif http://www.wolfdynamics.com/training/mphase/image33.gif 937
A crash introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM®


• OpenFOAM® comes with many solvers and models that can address a wide physics.
• Moving bodies can be added to all the modeling capabilities we have seen so far (turbulence
modeling, multiphase flows, and compressible flows).
• Several class of motions can be simulated in OpenFOAM®:
• Prescribed motion.
• Rigid body motion.
• Sliding meshes.
• MRF.

• Setting moving bodies simulations is not so different from what we have done so far.
• The main difference is that we must assign a motion type to a surface patch, a cell region, or the
whole domain.

938
A crash introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM®


• The mesh motion solver is selected in the dictionary constant/dynamicMeshDict.
• In the case of prescribed motion of a boundary patch, the motion is assigned in the dictionary
0/pointDisplacement.
• Also, the boundary type of the moving walls must be movingWallVelocity, this is set in the
dictionary 0/U.
• And as usual, you will need to adjust the numerics according to your physics.
• To use the moving bodies capabilities, you will need to use solvers able to deal with dynamic
meshes.
• To find which solvers work with dynamic meshes, go to the solvers directory by typing sol in the
command line interface. Then type in the terminal:
• $> grep -r dynamicFvMesh.H
• The solvers containing this header file support dynamic meshes.
• A few solvers that work with dynamic meshes: interFoam, pimpleFoam, rhoPimpleFoam,
buoyantPimpleFoam.

939
A crash introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM®


• You will find the source code of all the mesh motion libraries in the directories:
• OpenFOAM-8/src/dynamicFvMesh
• OpenFOAM-8/src/dynamicMesh
• OpenFOAM-8/src/fvMotionSolver
• OpenFOAM-8/src/rigidBodyDynamics
• OpenFOAM-8/src/rigidBodyMeshMotion
• OpenFOAM-8/src/rigidBodyState
• OpenFOAM-8/src/sixDoFRigidBodyMotion
• OpenFOAM-8/src/sixDoFRigidBodyState
• You will find the source code of the prescribed patch motion in the directory:
• OpenFOAM-8/src/fvMotionSolver/pointPatchFields/derived
• You will find the source code of the restraints/constraints of rigid body motion solvers in the
directory:
• OpenFOAM-8/src/rigidBodyDynamics/joints
• OpenFOAM-8/src/sixDoFRigidBodyMotion/sixDoFRigidBodyMotion
940
Moving bodies hands-on tutorials

• Continuous stirring tank reactor – Sliding meshes and


MRF
• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/sliding_meshes_MRF/CSTR

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
941
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF

Sliding grids – Unsteady solver MRF – Steady solver


http://www.wolfdynamics.com/training/movingbodies/image13.gif http://www.wolfdynamics.com/training/movingbodies/image14.gif

942
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• We already created this mesh during the meshing module.
• We will only address the differences in meshing for an MRF simulation and a sliding mesh
simulation.
• In this case, at the end of the meshing stage we obtained a faceZone and a cellZone.
• This is a conforming mesh, that is, the cells in the interface of the inner and outer regions are
perfectly matching.
• For MRF simulations, the cellZone can be used to assign the MRF properties to the rotating
zone.
• For sliding meshes or non-conforming meshes, there is an extra step where we need to split the
mesh in two regions and create the interface patches between the fix zone and the rotating
zone (the solution will be interpolated in these patches).

Cell region 2
(fix region)s

Face region between fix and


rotating regions Cell region 1
(face_inner_volume) (cell_inner_volume)

943
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• In the MRF approach, the governing equations are solved in a relative rotating frame in the
selected rotating zone.
• Additional source terms that model the rotation effect are taken into account.
• You select the rotating zone and set the rotation properties in the dictionary
constant/MRFProperties.
• In this case, the mesh is conforming.

Shaft
type rotatingWallVelocity;
origin (0 0 0);
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);

Impeller
type movingWallVelocity;
value uniform (0 0 0); Inner region generated during
meshing - MRFProperties

944
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• In the sliding meshes approach, the selected rotating region is physically rotating.
• As the meshes are non-conforming, the solution between the rotating region and the fix region
must be interpolated using arbitrary mesh interface.
• In the sliding meshes approach, is not enough to only identify the rotating region.
• We also need to create the interface patches between the fix zone and the rotating zone.

Shaft
type rotatingWallVelocity;
origin (0 0 0);
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);

Impeller
type movingWallVelocity;
value uniform (0 0 0); Inner region – dynamicMeshDict

Arbitrary mesh interface –


createBafflesDicts

945
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
Shaft
type rotatingWallVelocity;
origin (0 0 0);
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);

Impeller
type movingWallVelocity;
value uniform (0 0 0); Inner region and arbitrary mesh
interface

constant/dynamicMeshDict – For sliding meshes constant/MRFProperties – For MRF approach

cellZone cell_inner_volume;
dynamicFvMesh dynamicMotionSolverFvMesh; active yes;
motionSolverLibs ( "libfvMotionSolvers.so" );
solver solidBody; // Fixed patches (by default they move’ with the MRF zone)
cellZone cell_inner_volume; nonRotatingPatches ();
solidBodyMotionFunction rotatingMotion;
origin (0 0 0); origin (0 0 0);
axis (0 0 1); axis (0 0 1);
omega constant 12.566370; omega constant 12.566370;
946
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• For siding meshes, we need to create separated regions.
• In this case, to create the two regions we proceed as follows,

1. $> createBaffles –overwrite


2. $> mergeOrSplitBaffles –split –overwrite

• In step 1, we split the mesh in regions using the baffles (faceZone), created during the meshing
stage.
• We also create the cyclicAMI patches AMI1 and AMI2.
• At this point we have two regions and one zone. However, the two regions are stich together
via the patches AMI1 and AMI2.
• In step 2, we topologically split the patches AMI1 and AMI2. As we removed the link between
AMI1 and AMI2, the regions are free to move.

947
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• The utility createBaffles, reads the dictionary createBafflesDict.
• With this utility we create the interface patches between the fix zone and the rotating zone.

baffles
{
rotating Name of the baffle group
{
type faceZone; Use faceZone
zoneName face_inner_volume; Face to use to construct the AMI patches.
The name was defined in snappyHexMeshDict
patches
{
master Parameters for the master patch
{
name AMI1; Name of the master patch (user defined)
Boundary condition type cyclicAMI;
for sliding grids matchTolerance 0.0001;
neighbourPatch AMI2; Neighbour patch (slave patch or AMI2)
transform none;
}
slave Parameters for the slave patch
{
Boundary condition name AMI2; Name of the slave patch (user defined)
type cyclicAMI;
for sliding grids matchTolerance 0.0001;
neighbourPatch AMI1; Neighbour patch (master patch or AMI1)
transform none;
}
}
}
} Initially, the master and slave patches
share a common face

948
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• In sliding mesh simulations, the solution is interpolated back-and-forth between the regions.
• The interpolation is done at the arbitrary mesh interface patches (AMI) .
• To reduce interpolation errors at the AMI patches, the meshes should be similar in the master
and slave patches.

AMI interface Fix domain

http://www.wolfdynamics.com/training/movingbodies/image8.gif

Rotating domain Rotating patch Fix patch


Master patch Slave patch

949
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• At this point, the mesh is ready to use.
• You can visualize the mesh using paraFoam.
• If you use checkMesh, it will report that there are two regions.
• In the dictionary constant/dynamicsMeshDict we set which region will move and the
rotation parameters.
• To preview the region motion, in the terminal type:
• $> moveDynamicMesh

• To preview the region motion and check the quality of the AMI interfaces, in the terminal type:
• $> moveDynamicMesh -checkAMI -noFunctionObjects

• In our YouTube channel you can find a step-by-step video explaining this case.

950
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF

• The command moveDynamicMesh –checkAMI


will print on screen the quality of the AMI interfaces
for every time step.
• Ideally, you should get the AMI patches weights as
close as possible to one.
• Weight values close to one will guarantee a good
interpolation between the AMI patches.
http://www.wolfdynamics.com/training/movingbodies/image9.gif

… Name of the AMI patch Name of the AMI patch



Calculating AMI weights between owner patch: AMI1 and neighbour patch: AMI2
Number of faces in
AMI: Creating addressing and weights between 2476 source faces and 2476 target faces the AMI patches

AMI: Patch source sum(weights) min/max/average = 0.94746705, 1.0067199, 0.99994232 AMI1 patch weights

AMI: Patch target sum(weights) min/max/average = 0.94746692, 1.0004497, 0.99980782 AMI2 patch weights




951
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• At this point, we are ready to run the simulation.
• You can choose between running using sliding meshes (directory sliding_piso) or MRF
(directory MRF_simple).
• You can use the solver pimpleFoam for sliding meshes and the solver simpleFoam for MRF.
• You can also use pimpleFoam (unsteady solution) for the MRF. However, it is not
computationally efficient, the idea of MRF is to reach a steady solution fast.
• You can also try pimpleFoam (with local time stepping (LTS).
• You will find the instructions of how to run the cases in the file README.FIRST located in the
case directory.

952
Moving bodies hands-on tutorials

• Oscillating cylinder – Prescribed motion


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/prescribed_motion/oscillatingCylinder

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
953
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion

Moving boundary

http://www.wolfdynamics.com/training/movingbodies/image10.gif

Cylinder prescribed motion – Oscillating motion

954
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
• In the dictionary constant/dynamicMeshDict we select the mesh morphing method and the
boundary patch that it is moving (lines 21 and 25, respectively).
• There are many mesh morphing methods implemented in OpenFOAM®.
• Mesh morphing is based in diffusing or propagating the mesh deformation all over the domain.
• You will need to find the best method for your case.
• The setup used in this case works fine most of the times.

17 dynamicFvMesh dynamicMotionSolverFvMesh; Mesh motion library for


boundary patches
18
19 motionSolverLibs ("libfvMotionSolvers.so"); Motion library
20
Method coefficients

21 solver displacementLaplacian; Solver for mesh motion


22 method
23 displacementLaplacianCoeffs
24 {
25 diffusivity inverseDistance (cylinder);
26 }

Mesh diffusion method Patch name 955


Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
• In the dictionary 0/pointDisplacement we select the prescribed body motion.
• In this case we are using oscillatingDisplacement (line 44) for the cylinder patch.
• Each method has different input values. In this case it is required to define the amplitude (line
45) and the angular velocity (line 46) in rad/s.
• If the patch is not moving, we assign to it a fixedValue boundary conditions (lines 37-41).

37 in
38 {
39 type fixedValue;
40 value uniform (0 0 0);
41 }
42 cylinder
43 {
44 type oscillatingDisplacement;
45 amplitude ( 0 1 0 );
46 omega 6.28318;
47 value uniform ( 0 0 0 ); Dummy value for paraview
48 }
956
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
• You must assign the boundary condition movingWallVelocity to all patches that are moving.
• This is done in the dictionary 0/U.

41 cylinder
42 {
43 type movingWallVelocity;
44 value uniform (0 0 0);
45 }

• And as usual, you will need to adjust the numerics according to your physics.
• In this case we need to solve the new fields cellDisplacement and diffusivity, which are
related to the mesh motion and morphing.
• In the dictionary fvSolution, you will need to add a linear solver for the field
cellDisplacement.
• In the dictionary fvSchemes, you will need to add the discretization schemes related to the
mesh morphing diffusion method, laplacian(diffusivity, cellDisplacement).
• If you are dealing with turbulence modeling the treatment of the wall functions is the same as if
you were working with fixed meshes. 957
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
• At this point, we are ready to run the simulation.
• You will find the instructions of how to run the cases in the file README.FIRST located in the
case directory.
• Before running the simulation, you can check the mesh motion.
• During this check, you can use large time-steps as we re not computing the solution, we are
only interested in checking the motion.
• To check the mesh motion, type in the terminal:

1. $> moveDynamicMesh -noFunctionObjects

958
Moving bodies hands-on tutorials

• Floating body – Rigid body motion


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/rigid_body_motion/floatingObject

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
959
Moving bodies hands-on tutorials
Floating body – Rigid body motion

ente of av ity position


position
c

ime/ s

http://www.wolfdynamics.com/training/movingbodies/image11.gif
t v s o ientation u (acos( ) /pi/ )
position
c

ime/ s

http://www.wolfdynamics.com/training/movingbodies/image12.gif

Floating body simulation with VOF and turbulence modeling. 960


Moving bodies hands-on tutorials
Floating body – Rigid body motion
• As for prescribed motion, in rigid body motion the mesh morphing is based in diffusing or
propagating the mesh deformation all over the domain.
• In the dictionary constant/dynamicMeshDict we select the mesh morphing library and rigid
body motion library (lines 17-21).
• The rigid motion solver will compute the response of the body to external forces.
• In lines 23-77, we define all the inputs required by the rigid motion solver.

17 dynamicFvMesh dynamicMotionSolverFvMesh; Mesh motion library for


boundary patches
18
19 motionSolverLibs ("libsixDoFRigidBodyMotion.so"); Motion library
20
Method coefficients

21 solver sixDoFRigidBodyMotion; Solver for mesh motion


22 method
23 sixDoFRigidBodyMotionCoeffs
24 {



77 }
961
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• The dictionary constant/dynamicMeshDict (continuation).

23 sixDoFRigidBodyMotionCoeffs
24 {
25 patches (floatingObject); Moving patch
26
Mesh deformation limits.
27 innerDistance 0.1;
The mesh will not be deformed in the fringe located within
28 outerDistance 0.4;
innerDistance and outerDistance (distance normal to the wall)
33 centreOfMass (0.5 0.5 0.5);
34 mass 5; Physical properties of the body
35 momentOfInertia (0.08 0.08 0.1);

37 report on; Report on screen position of the body


38
outerDistance
45 solver
46 {
47 type Newmark; Rigid body motion solver
48 }

Body patch

innerDistance
Set it to zero if you do not want to apply mesh morphing to the inner region 962
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• The dictionary constant/dynamicMeshDict (continuation).

50 constraints
51 {
55 fixedAxis
56 {
57 sixDoFRigidBodyMotionConstraint axis;
58 axis (0 1 0);
59 } Motion constraints
If you do not give any
63 fixedLine constraint, the body is free
64 { to move in all directions.
65 sixDoFRigidBodyMotionConstraint line;
66 centreOfRotation (0.5 0.5 0.5);
67 direction (0 0 1);
68 }

70 }
Body restraints
72 restraints
Restraints can be used to
73 {
damp the acceleration of the
body.
75 }
In this case, we are not
using restraints
77 }

963
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• In the dictionary 0/pointDisplacement we select the body motion.
• For rigid body motion, the body motion is computed by the solver, therefore, we use the
boundary condition calculated.

33 floatingObject
34 {
35 type calculated;
36 value uniform (0 0 0);
37 }

• You must assign the boundary condition movingWallVelocity to all patches that are moving.
This is done in the dictionary 0/U.

33 floatingObject
34 {
35 type movingWallVelocity;
36 value uniform (0 0 0);
37 }

• If you are dealing with turbulence modeling the treatment of the wall functions is the same as if
you were working with fixed meshes. 964
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• And as usual, you will need to adjust the numerics according to your physics.
• In the case directory, you will find the script extractData.
• This script can be used to extract the position of the body during the simulation.
• In order to use the extractData script, you will need to save the log file of the simulation.
• At this point, we are ready to run the simulation.
• We will use the solver interFoam.
• You will find the instructions of how to run the cases in the file README.FIRST located in the
case directory.

965
Roadmap

A crash introduction to:


1. Turbulence modeling in OpenFOAM®
2. Multiphase flows modeling in
OpenFOAM®
3. Compressible flows in OpenFOAM®
4. Moving bodies in OpenFOAM®
5. Source terms in OpenFOAM®
6. Scalar transport pluggable solver

966
A crash introduction to source terms OpenFOAM®

Source terms in OpenFOAM®


• In addition to all modeling capabilities we have seen so far, you can also add source terms to
the governing equations without the need of modifying the original source code.
• This functionality is provided via the dictionary fvOptions, which is located in the directory
system.
• There are many source terms implemented in OpenFOAM®, you can even use codeStream to
program your own source term without the need of recurring to high level programming.
• The fvOptions functionality work with most of the solvers that deal with advanced modeling
capabilities.
• Remember, the solver icoFoam is very basic with no modeling capabilities. Therefore, you can
not use the fvOptions functionality and many other modeling and postprocessing capabilities
with it.
• You will find the source code of the source terms in the directory:
• OpenFOAM-8/src/fvOptions

967
A crash introduction to source terms OpenFOAM®

Source terms in OpenFOAM®


• To use source terms, you must first select where you want to apply it
• You can apply a source term in the whole domain, a set of cells, a cell zone, or a point (or group
of points).
• You can create the set of cells at meshing time or you can use the utility topoSet to select a
group of cells.
• By the way, boundary conditions are source terms added at the boundary patches, and MRF are
source terms added to a cell selection.

Set of cell

Point selection

968
A crash introduction to source terms OpenFOAM®

Source terms in OpenFOAM®

• The source terms can be selected in the dictionary


1 user_defined_name fvOptions, and they can be modified on-the-fly.
2 {
3 type name_of_source_term; • This dictionary file is located in the directory system.
4
5 active true; • Hereafter we show a generic fvOptions dictionary.
6
7 input_coefficients • According to the source term you selected, you will need
8 {
to give different input parameters in the input coefficients
9 timeStart 0.5;
10 duration 2.0; section (lines 7-23).
11
12 selectionMode points; • The input parameters indicated with an arrow can be
13 points used with any source term. Most of then are self
14 ( explanatory.
15 (3 0 0)
16 ); • The volumeMode keyword (line 21) let you choose
17
18 //selectionMode cellZone;
between absolute and specific.
19 //cellZone filter;
20
• absolute: input values are given as
21 volumeMode absolute; quantity/volume.
22
... • specific: input values are given as quantity.
...
...

23 }
• Remember, you can use the banana method to know all
24 } source terms and options available.
• You can also read the source code.
969
Source terms hands-on tutorials

• Filter source term


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/source_terms/filter/porous_source

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
970
Source terms hands-on tutorials
Filter source term
• In this case we are going to use the source term explicitPorositySource.
• Using this source term we can apply a porous region (e.g., Darcy-Forchheimer) in the cell
selection.
• The source term is activated after 2 seconds of simulation time.

Set of cell
(filter)

http://www.wolfdynamics.com/training/sourceterms/image1.gif 971
Source terms hands-on tutorials
Filter source term
system/fvOptions
• The source terms can be selected in the
17
18
filter1
{
dictionary fvOptions, and they can be modified
19 type explicitPorositySource; on-the-fly.
20 active yes;
22 explicitPorositySourceCoeffs • In this case we are using the source term
23 {
25 timeStart 2; explicitPorositySource (line 19).
26 duration 5;
28 selectionMode cellZone; • Using this source term we can apply a porous
29 cellZone filter; region (of the type Darcy-Forchheimer) in the cell
31 type DarcyForchheimer;
selection (line 28).
38 DarcyForchheimerCoeffs
39 { • The source term is used in a cellZone (line 28)
41
44
d
f
(5000000 5000000 5000000);
(0 0 0);
named filter (line 29), this zone must be created
46 coordinateSystem at meshing time or using the utility topoSet.
47 {
49 type cartesian; • In lines 38-60, we define the input parameters of
50 origin (0 0 0);
52 coordinateRotation
the model.
53 {
54 type axesRotation;
• In this case, the coefficients f and d are
55 e1 (1 0 0); resistance/impermiability coefficients, and e1 and
56 e2 (0 1 0);
57 }
e2 are the vectors that are used to specify the
59 } porosity.
60 }
61 }
62 }
972
Source terms hands-on tutorials
Filter source term
system/topoSetDict
• To create the cellZone used in fvOptions, we
first create a cellSet.
• The set of cells (cellSet) is constructed using the
utility topoSet.
• This utility reads the dictionary topoSetDict,
which is located in the directory system.

actions • Hereafter we show the dictionary inputs used to


( create the cellSet named filter.
// filter
{
name filter; Name of the selection
type cellSet; Select a set of cells
action new; Create a new selection
source boxToCell;
sourceInfo
{ Use a box to select the set of cells
box (1.5 -10 -10) (2 10 10);
}
}
...
...
...
)
973
Source terms hands-on tutorials
Filter source term
system/topoSetDict
• To create the cellZone used in fvOptions, we
first create a cellSet.
• Now that we have the cellSet filter, we can
convert it to a cellZoneSet that can be used by
fvOptions.
• The name of the new cellZoneSet is filter.

actions • Remember, you can apply the source terms in a


( cellSet or in a cellZone.
...
...
...
{
name filter; Name of the selection
type cellZoneSet; Select a zone set (cellZoneSet)
action new; Create a new selection
source setToCellZone;
sourceInfo
{
Convert the cellSet filter to a cellZoneSet
set filter; named filter
}
}
)

974
Source terms hands-on tutorials
Filter source term

• At this point, we are ready to run the simulation.


• We will use the solver pimpleFoam, which can use source terms.
• Before running the simulation, remember to use the utility topoSet to create the filter
region used by the source term.
• You can visualize the region using paraview.
• Finally, remember to adjust the numerics according to your physics.
• You will find the instructions of how to run the cases in the file README.FIRST
located in the case directory.

975
Roadmap

A crash introduction to:


1. Turbulence modeling in OpenFOAM®
2. Multiphase flows modeling in
OpenFOAM®
3. Compressible flows in OpenFOAM®
4. Moving bodies in OpenFOAM®
5. Source terms in OpenFOAM®
6. Scalar transport pluggable solver

976
Scalar transport pluggable solver

The functionObject scalarTransport


• In addition to all modeling capabilities we have seen so far, you can also add scalar transport
equations (or convection-diffusion equation), without the need of modifying the original source
code.
• This functionality is provided via functionObjects, and it can be seen as a solver that can be
plug into another one.
• To setup the scalar transport equation you need to:
• Define the functionObject in the dictionary controlDict.
• Add the discretization schemes and linear solvers for the new equations.
• Define the boundary conditions and initial conditions of the transported scalars.
• You will find the source code of the scalar transport pluggable solver in the directory:
• OpenFOAM-8/src/functionObjects/solvers

977
Scalar transport pluggable solver

The functionObject scalarTransport


• The scalar transport functionObject is defined in
the dictionary controlDict.
• Remember, the input parameters can be modified
scalar1 on-the-fly.
{
type scalarTransport;
functionObjectLibs ("libsolverFunctionObjects.so"); Select scalarTransport functionObject

enabled true;

writeControl outputTime;
Number of corrector iterations.
log yes; It is recommended to do t least one iteration.

nCorr 1;
Diffusion coefficient.
D 0; If turbulent modeling is in use, you can define the
//alphaD 0; laminar diffusion coefficient alphaD and the turbulent
//alphaDt 0; diffusion coefficient alphaDt

Name of the new field. You will need to select the


discretization schemes and linear solvers for this field.
You will also need to define the boundary conditions
field s1; and initial conditions for this field.

//schemesField U; Option to use the same numerical scheme as the one


} used for the filed U
978
Scalar transport pluggable solver

Boundary conditions

0/s1
• Assuming that you named the new scalar s1, you
dimensions [0 0 0 0 0 0 0]; will need to define the boundary conditions and
initial conditions for the field s1.
internalField uniform 0;
• This is done in the dictionary 0/s1.
boundaryField
{ • In this case, the scalar is entering in the patch
walls
{ inlet with a value of 1 (this is a concentration
type zeroGradient; therefore it has no dimensions).
}

inlet
• The initial concentration of the scalar is zero.
{
type fixedValue;
value uniform 1;
}

outlet
{
type inletOutlet;
inletValue uniform 0;
value uniform 0;
}
}

979
Scalar transport pluggable solver

Discretization schemes and linear solvers


• Finally, and assuming that you named the new scalar s1, you need to define the discretization
schemes and linear solvers of the new equations.
• Remember, this is a bounded quantity, so it is a good idea to use TVD schemes and gradient
limiters.

system/fvSchemes system/fvSolution

gradSchemes s1
{ {
default Gauss linear; solver smoothSolver;
grad(s1) cellLimited Gauss linear 1; smoother symGaussSeidel;
} tolerance 1e-08;
relTol 0;
}
divSchemes
{
default none;
div(phi,U) Gauss linearUpwindV default;
div(phi,s1) Gauss vanLeer;
}

980
Scalar transport pluggable solver hands-on tutorials

• Scalar transport in an elbow – Internal geometry


• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/source_terms/2Delbow_passive_scalar

• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
981
Scalar transport pluggable solver hands-on tutorials
Scalar transport in an elbow – Internal geometry
• Notice that we are adding two scalars, s1 and s2.

S1
U → (2 0 0)

http://www.wolfdynamics.com/training/sourceterms/image2.gif
S2
U → (0 3 0)

http://www.wolfdynamics.com/training/sourceterms/image3.gif 982
Scalar transport pluggable solver hands-on tutorials
Scalar transport in an elbow – Internal geometry
• At this point, we are ready to run the simulation.
• We will use the solver pisoFoam.
• Remember to adjust the numerics according to your physics.
• Do not forget to create the boundary conditions and initial conditions of the new field variables.
• You will find the instructions of how to run the cases in the file README.FIRST located in the
case directory.

983
This is the end

• Some kind of conclusion,

• Good mesh – good results.


• Start robustly and end with accuracy.
• Stability, accuracy and boundedness,
play by these terms and you will succeed.
• Do not sacrifice accuracy and stability over
computing speed.
• Select wisely the boundary conditions.
This is the end

That was only the tip of the iceberg

Now the rest is on you


This is the end
• We hope you have found this training useful and we hope to see you in one of our advanced
training sessions:
• OpenFOAM® – Multiphase flows
• OpenFOAM® – Naval applications
• OpenFOAM® – Turbulence Modeling
• OpenFOAM® – Compressible flows, heat transfer, and conjugate heat transfer
• OpenFOAM® – Advanced meshing
• DAKOTA – Optimization methods and code coupling
• Python – Programming, data visualization, and exploratory data analysis
• Python and R – Data science and big data
• ParaView – Advanced scientific visualization and python scripting
• And many more available on request
• Besides consulting services, we also offer ‘Mentoring Days’ which are days of one-on-one
coaching and mentoring on your specific problem.
• For more information, ask your trainer, or visit our website
http://www.wolfdynamics.com/
This is the end

TGIF & TGIO


Enjoy OpenFOAM®
guerrero@wolfdynamics.com
Let’s connect www.wolfdynamics.com

You might also like