You are on page 1of 321

University of Genoa, DICCA

Dipartimento di Ingegneria Civile, Chimica e Ambientale

This work is licensed under a Creative Commons


Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0)

Introductory OpenFOAM® Course To view a copy of this license, visit


http://creativecommons.org/licenses/by-sa/4.0/
From 16th to 20th July, 2018

• 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 Acknowledgements

This offering is not approved or endorsed by OpenCFD Limited, the This training material and tutorials are based upon personal experience, OpenFOAM® source
code, OpenFOAM® user guide, OpenFOAM® programmer’s guide, and presentations from
producer of the OpenFOAM software and owner of the OPENFOAM® and
previous OpenFOAM® training sessions and OpenFOAM® workshops.
OpenCFD® trade marks.
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.


Wolf Dynamics makes no warranty, express or implied, about the • Hrvoje Jasak and Henrik Rusche. Wikki Ltd.
completeness, accuracy, reliability, suitability, or usefulness of the • Eugene de Villiers, Paolo Geremia, and Dan Combest. Engys.
information disclosed in this training material. This training material is • Hakan Nilsson. Chalmers University of Technology.
intended to provide general information only. Any reliance the final user • Eric Paterson. Pennsylvania State University.
place on this training material is therefore strictly at his/her own risk. Under • Gavin Tabor. University of Exeter.
no circumstances and under no legal theory shall Wolf Dynamics be liable • Fumiya Nozaki. Yokohama, Japan.
for any loss, damage or injury, arising directly or indirectly from the use or • Marwan Darwish. American University of Beirut.
misuse of the information contained in this training material. • Kevin Maki. University of Michigan.

Revision 1-2018
On the training material On the training material
The following typographical conventions are used in this The following typographical conventions are used in this
training material training material

• Courier new • Large code listing, ascii files listing, and screen outputs can be written in
a square box, as follows:
Indicates Linux commands that should be typed literally by the
user in the terminal
1 #include <iostream>
• Courier new bold 2 using namespace std;
3
Indicates directories 4 // main() is where program execution begins. It is the main function.
• Courier new italic 5 // Every program in c++ must have this main function declared
6
Indicates human readable files or ascii files 7 int main ()
8 {
• Arial bold 9 cout << "Hello world"; //prints Hello world
Indicates program elements such as variables, function names, 10 return 0; //returns nothing
11 }
classes, databases, data types, environment variables,
statements and keywords. They also highlight important
information • To improve readability, the text might be colored.
• Arial underline in blue • The font can be Courier new or Arial bold.
Indicates URLs and email addresses • And when required, the line number will be shown.

On the training material On the training material


The following typographical conventions are used in this 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).

This icon indicates a warning or a caution • You can extract the training material wherever you want. However, we highly recommend you to extract all the
training material in your OpenFOAM® user directory. From now on, this directory will become,
• $PTOFC
This icon indicates a tip, suggestion, or a general note (abbreviation of Path To OpenFOAM® Course)

This icon indicates that more information is available in the • From now on and whenever you read $PTOFC, it is referring to the location where you extracted the training
material.
referred location
• You can add an alias to $PTOFC in your .bashrc file by adding the following line (remember to source again
This icon indicates a folder or directory the .bashrc file or to open a new terminal after modifying the file),
• alias PTOFC=‘cd PATH_TO_TUTORIALS’
This icon indicates a human readable file (ascii file)
• To uncompress the tutorials go to the directory where you copied the training material and then type in the
terminal,
This symbol indicates that a Linux command should be typed
$> literally by the user in the terminal
• $> tar –zxvf file_name.tar.gz

• 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.
This icon indicates that the figure is an animation (animated gif)
Training agenda Training agenda
Module 0. Module 3. Module 6. Module 8.
• Training agenda • Meshing preliminaries • The finite volume method. A crash • Advanced modeling capabilities:
• On the training material • Mesh quality assessment introduction • Turbulence modeling
• Housekeeping issues • Meshing in OpenFOAM® – blockMesh and • On the CFL number • Multiphase flows
• Additional information snappyHexMesh • Boundary conditions and initial conditions • Compressible flows
• Mesh conversion and manipulation • Unsteady and steady simulations • Moving reference frames and sliding
Module 1. • Assessing convergence grids
• Introduction to OpenFOAM® Module 4. • Velocity pressure-coupling • Moving bodies and rigid body motion
• A few OpenFOAM® simulations • Running in parallel • Linear solvers • Source terms and passive scalars
• Library organization • Running in the cloud – Amazon EC2
• OpenFOAM® 101 – My first tutorial Module 7. Module 9.
Module 5. • Programming in OpenFOAM® • Conclusions and wrap-up session
Module 2. • Scientific visualization with • Building blocks
ParaView/paraFoam • Implementing/modifying applications
• CFD workflow
• Data conversion • Implementing boundary conditions, initial
• Solid modeling using open source tools • Sampling and plotting conditions and utilities
• Co-processing • codeStream

Training agenda
Provisional timetable

Module 1
OpenFOAM® overview – First tutorial –
Working our way in OpenFOAM®

The above outline is a guide only and every attempt will be made to fulfill the program
1
Roadmap OpenFOAM® brief overview
General description:
1. OpenFOAM® brief overview • OpenFOAM® stands for Open Source Field Operation and Manipulation.
2. OpenFOAM® directory organization • OpenFOAM® is first and foremost a C++ library used to solve partial
differential equations (PDEs), and ordinary differential equations (ODEs).
3. Directory structure of an application/utility
• It comes with several ready-to-use or out-of-the-box solvers, pre-processing
4. Applications/utilities in OpenFOAM® utilities, and post-processing utilities.
5. Directory structure of an OpenFOAM® case • It is licensed under the GNU General Public License (GPL). That means it is
6. Running my first OpenFOAM® case setup blindfold freely available and distributed with the source code.

7. A deeper view to my first OpenFOAM® case setup • It can be used in massively parallel computers. No need to pay for separate
licenses.
8. 3D Dam break – Free surface flow
• It is under active development.
9. Flow past a cylinder – From laminar to turbulent flow
• It counts with a wide-spread community around the world (industry,
academia and research labs).

2 3

OpenFOAM® brief overview OpenFOAM® brief overview


Multi-physics simulation capabilities: Physical modeling library:
• OpenFOAM® has extensive multi-physics simulation capabilities, among • OpenFOAM® comes with many physical models, among others:
others:
• Extensive turbulence modeling capabilities (RANS, DES and LES).
• Computational fluid dynamics (incompressible and compressible flows).
• Transport/rheology models. Newtonian and non-Newtonian viscosity
• Computational heat transfer and conjugate heat transfer. models.
• Combustion and chemical reactions. • Thermophysical models and physical properties for liquids and gases.
• Multiphase flows and mass transfer. • Source terms models.
• Particle methods (DEM, DSMC, MD) and lagrangian particles tracking. • Lagrangian particle models.
• Stress analysis and fluid-structure interaction. • Interphase momentum transfer models for multiphase flows.
• Rotating frames of reference, arbitrary mesh interface, dynamic mesh • Combustion, flame speed, chemical reactions, porous media, radiation,
handling, and adaptive mesh refinement. phase change.
• 6 DOF solvers, ODE solvers, computational aero-acoustics,
computational electromagnetics, computational solid mechanics, MHD.

4 5
OpenFOAM® brief overview OpenFOAM® brief overview
Under the hood you will find the following: OpenFOAM® vs. Commercial CFD applications:
• Finite Volume Method (FVM) based solver. • OpenFOAM® capabilities mirror those of commercial CFD applications.
• Collocated polyhedral unstructured meshes. • The main differences with commercial CFD applications are:
• Second order accuracy in space and time. Many discretization schemes • There is no native GUI.
available (including high order methods).
• It is not a single executable. Depending of what you are looking for,
• Steady and transient solvers available. you will need to execute a specific application from the command
• Pressure-velocity coupling via segregated methods (SIMPLE and PISO). line interface (CLI).
• But coupled solvers are under active development. • It is not well documented, but the source code is available.
• Massive parallelism through domain decomposition. • Access to complete source = no black magic. But to understand the
source code you need to know object oriented programming and
• It comes with it own mesh generation tools.
C++.
• It also comes with many mesh manipulation and conversion utilities.
• Solvers can be tailored for a specific need, therefore OpenFOAM®
• It comes with many post-processing utilities. is ideal for research and development.
• All components implemented in library form for easy re-use. • It is free.
6 7

OpenFOAM® brief overview OpenFOAM® brief overview


Developing new solvers (in case you need it):
• As the user has complete access to the source code, he/she 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.: OpenFOAM® is an excellent piece of C++
and software engineering. Decent piece of
solve
( CFD code.
fvm::ddt(rho,U)
+ fvm::div(phi,U) H. Jasak
- fvm::laplacian(mu,U)
==
- fvc::grad(p)
);

Correspondence between the implementation and the original equation is clear.

8 9
Roadmap OpenFOAM® directory organization
$WM_PROJECT_DIR If you installed OpenFOAM® in the default location, the
1. OpenFOAM® brief overview ├── Allwmake directory the environment variable $WM_PROJECT_DIR
├── applications should point to the following directory (depending on the
2. OpenFOAM® directory organization ├── bin installed version):

3. Directory structure of an application/utility ├── COPYING


├── doc $HOME/OpenFOAM/OpenFOAM-5.1
4. Applications/utilities in OpenFOAM® ├── etc or

5. Directory structure of an OpenFOAM® case ├── platforms $HOME/OpenFOAM/OpenFOAM-5.x


├── README.org
6. Running my first OpenFOAM® case setup blindfold ├── src In this directory you will find all the directories containing
├── tutorials
7. A deeper view to my first OpenFOAM® case setup OpenFOAM® installation.
└── wmake
8. 3D Dam break – Free surface flow In this directory you will also find additional files (such as
9. Flow past a cylinder – From laminar to turbulent flow README.org, COPYING, etc.), but the most important
one is Allwmake, which compiles OpenFOAM®.

10 11

OpenFOAM® directory organization OpenFOAM® directory organization


$WM_PROJECT_DIR OpenFOAM® environment variables $WM_PROJECT_DIR OpenFOAM® aliases
├── Allwmake ├── Allwmake
├── applications The entries starting with the symbol $ are environment
├── applications
You can go to any of these directories by using the
├── bin variables. You can find out the value of an environment ├── bin predefined aliases set by OpenFOAM® (see
├── COPYING variable by echoing its value, for example: ├── COPYING $WM_PROJECT_DIR/etc/config/alias.sh). Just to
├── doc $> echo $WM_PROJECT_DIR ├── doc name a few of the aliases defined:
├── etc ├── etc alias foam=‘cd $WM_PROJECT_DIR’
├── platforms ├── platforms alias app=‘cd $FOAM_APP’
will give you the following output on the terminal
├── README.org ├── README.org alias src=‘cd $FOAM_SRC’
$HOME/OpenFOAM/OpenFOAM-5.x
├── src ├── src alias tut=‘cd $FOAM_TUTORIALS’
├── tutorials ├── tutorials
└── wmake To list all the environment variables type in the terminal └── wmake
window env For a complete list type alias in the terminal.

To list all the environment variables related to To list all the aliases related to OpenFOAM®, type in the
OpenFOAM®, type in the terminal: terminal:
$> env | grep “OpenFOAM” $> alias | grep “FOAM”

12 13
OpenFOAM® directory organization OpenFOAM® directory organization
$WM_PROJECT_DIR The applications directory
├── Allwmake Let us study each directory inside $WM_PROJECT_DIR/applications
├── applications ├── Allwmake
├── bin $WM_PROJECT_DIR
├── solvers
├── COPYING ├── test
├── doc └── utilities
├── etc
├── platforms
├── README.org • Any modification you add to the source code in Let us visit the applications directory. Type in the terminal app or
├── src WM_PROJECT_DIR will affect the whole library. $> cd $WM_PROJECT_DIR/applications. You will find the following sub-directories:
├── tutorials • Unless you know what are you doing, do not • solvers, which contains the source code for the distributed solvers.
└── wmake modify anything in the original installation
• test, which contains the source code of several test cases that show the usage of
($WM_PROJECT_DIR), except for updates!
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.

14 15

OpenFOAM® directory organization OpenFOAM® directory organization


The bin directory The doc directory
$WM_PROJECT_DIR/bin/ Let us visit the bin directory: $WM_PROJECT_DIR/doc/ Let us visit the doc directory:
├── foamCleanPolyMesh ├── Allwmake
• The bin directory contains many shell • The doc directory contains the documentation
├── foamCleanTutorials scripts, such as foamNew, foamLog,
├── codingStyleGuide.org
of OpenFOAM®, namely; user guide,
├── foamCloneCase foamJob, foamNewApp, etc. ├── Doxygen programmer’s guide and Doxygen generated
├── foamJob ├── Guides documentation in html format.
├── foamLog • This directory also contains the script └── tools
paraFoam that will launch paraView. • The Doxygen documentation needs to be
├── foamMonitor
compiled by typing Allwmake doc in
├── foamNew $WM_PROJECT_DIR.
├── foamNewApp
├── foamNewBC • You can access the Doxygen documentation
├── foamNewFunctionObject online, http://cpp.openfoam.org/v5
├── paraFoam
├── ...
└── tools

The directory tree is not complete


16 17
OpenFOAM® directory organization OpenFOAM® directory organization
The etc directory The platforms directory
$WM_PROJECT_DIR/etc/ Let us visit the etc directory: $WM_PROJECT_DIR/platforms/
├── bashrc ├── linux64GccDPInt32Opt
• The etc directory contains the environment
├── caseDicts │ ├── applications
files, global OpenFOAM® instructions,
├── cellModels templates, and the default thermochemical │ ├── bin
├── codeTemplates database thermoData/thermoData │ ├── lib
├── config.csh │ └── src
├── config.sh • It also contains the super dictionary └── linux64GccDPInt32OptSYSTEMOPENMPI
controlDict, where you can set several
├── controlDict debug flags and the defaults units. └── src
├── cshrc
├── README.org Let us visit the platforms directory.
├── templates • This directory contains the binaries generated when compiling the applications
directory and the libraries generated by compiling the source code in the src directory.
└── thermoData
• 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
18 19

OpenFOAM® directory organization OpenFOAM® directory organization


The src directory The src directory
$WM_PROJECT_DIR/src Let us visit the src directory. Type in the terminal $WM_PROJECT_DIR/src A few interesting directories are:
├── Allwmake src or $> cd $WM_PROJECT_DIR/src ├── Allwmake • finiteVolume. This library provides all the
├── combustionModels ├── combustionModels classes needed for the finite volume
├── finiteVolume • This directory contains the source code for all ├── finiteVolume discretization, such as mesh handling, finite
├── fvOptions the foundation libraries, this is the core of ├── fvOptions volume discretization operators (divergence,
laplacian, gradient, fvc/fvm and so on), and
├── lagrangian OpenFOAM®. ├── lagrangian boundary conditions. In the directory
├── ... • It is divided in different subdirectories and each ├── ... finiteVolume/lnInclude you also find the
├── OpenFOAM of them can contain several libraries. ├── OpenFOAM very important file fvCFD.H, which is included
├── parallel ├── parallel in most applications.
├── sampling A few interesting directories are: ├── sampling • sixDoFRigidBodyMotion. This core library
├── sixDoFRigidBodyMotion ├── sixDoFRigidBodyMotion contains the solver for rigid body motion.
• OpenFOAM. This core library includes the
├── thermophysicalModels definitions of the containers used for the ├── thermophysicalModels • transportModels. This core library contains
├── transportModels operations, the field definitions, the declaration ├── transportModels many transport models.
├── TurbulenceModels of the mesh and mesh features such as zones ├── TurbulenceModels • TurbulenceModels, which contains many
and sets. turbulence models.
└── waves └── waves

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

OpenFOAM® directory organization OpenFOAM® directory organization


OpenFOAM® user directory Looking for information in OpenFOAM® source code
$HOME/OpenFOAM/ • To locate files you can use the find command.

├── $WM_PROJECT_USER_DIR • If you want to locate a directory inside $WM_PROJECT_DIR that contains the string fvPatch in
its name, you can proceed as follows,
└── $WM_PROJECT_DIR • $> find $WM_PROJECT_DIR –type d -name “*fvPatch*”

Where to look for Look for Case Look for this


• Let us now study OpenFOAM® user directory $WM_PROJECT_USER_DIR directories sensitive (using wildcards)

• When working with OpenFOAM®, you can put your files wherever you want. • If you want to locate a file inside $WM_PROJECT_DIR that contains the string fvPatch in its
• To keep things in order, it is recommended to put your cases in your name, you can proceed as follows,
OpenFOAM® user directory or $WM_PROJECT_USER_DIR. • $> find $WM_PROJECT_DIR –type f -name “*fvPatch*”
• It is also recommended to put your modified solvers, utilities, and libraries in Where to look for Look for Case Look for this
your OpenFOAM® user directory or $WM_PROJECT_USER_DIR. This is done so files sensitive (using wildcards)

you do not modify anything in the original installation. • If you want to find a string inside a file, you can use the grep command.
• If you followed the standard installation instructions, the variable • For example, if you want to find the string LES inside all the files within the directory
$WM_PROJECT_USER_DIR should point to the directory $FOAM_SOLVERS, you can proceed as follows,
$HOME/OpenFOAM/USER_NAME-5.x, where USER_NAME is the name of the • $> grep -r -n “LES” $FOAM_SOLVERS
user (e.g., johnDoe).
The argument -r means recursive and -n will output the line number.
24 25
OpenFOAM® directory organization OpenFOAM® directory organization
Looking for information in OpenFOAM® source code Looking for information in OpenFOAM® source code
• Dictionaries are input files required by OpenFOAM®. • A few more advanced commands to find information in your OpenFOAM® installation.
• As you can imagine, there are many dictionaries in OpenFOAM®. The easiest way to find all of • To find which tutorial files use the boundary condition slip:
them is to do a local search in the installation directory as follows, • $> find $FOAM_TUTORIALS -type f | xargs grep -sl ‘ slip’
• For instance, if you are interested in finding all the files that end with the Dict word in the This command will look for all files inside the directory $FOAM_TUTORIALS, then the
tutorials directory, in the terminal type:
output is used by grep to search for the string slip.
• $> find $FOAM_TUTORIALS -name “*Dict”
(Case sensitive search)
• To find where the source code for the boundary condition slip is located:
• $> find $FOAM_TUTORIALS –iname ‘*dict’
(Non-case sensitive search) • $> find $FOAM_SRC -name “*slip*”

• When given the search string, you can use single quotes ‘ ’ or double-quotes “ ” (do not mixed • To find what applications do not run in parallel:
them). • $> find $WM_PROJECT_DIR -type f | xargs grep -sl ‘noParallel’
• We recommend to use single quotes, but it is up to you.
• OpenFOAM® understands REGEX syntax.

26 27

OpenFOAM® directory organization Roadmap


Environment variables
• Remember, OpenFOAM® uses its own environment variables. 1. OpenFOAM® brief overview
• OpenFOAM® environment settings are contained in the OpenFOAM-5.x/etc directory.
2. OpenFOAM® directory organization
• If you installed OpenFOAM® in the default location, they should be in:
• $HOME/OpenFOAM/OpenFOAM-5.x/etc 3. Directory structure of an application/utility
• If you are running bash or ksh (if in doubt type in the terminal echo $SHELL), you sourced the 4. Applications/utilities in OpenFOAM®
$WM_PROJECT_DIR/etc/bashrc file by adding the following line to your $HOME/.bashrc
file: 5. Directory structure of an OpenFOAM® case
• source $HOME/OpenFOAM/OpenFOAM-5.x/etc/bashrc
6. Running my first OpenFOAM® case setup blindfold
• By sourcing the file $WM_PROJECT_DIR/etc/bashrc, we start to use OpenFOAM® 7. A deeper view to my first OpenFOAM® case setup
environment variables.
8. 3D Dam break – Free surface flow
• 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 9. Flow past a cylinder – From laminar to turbulent flow
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 29
Directory structure of an OpenFOAM® application/utility Directory structure of an OpenFOAM® application/utility

Directory structure of a general solver Directory structure of a general utility


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

The $WM_PROJECT_DIR/applications/solvers/solverName/ directory contains the The $WM_PROJECT_DIR/utilities/utilityName/ directory contains the source code of
source code of the solver. the utility.
• solverName/appName.C: is the actual source code of the solver. • utilityName/utilityName.C: is the actual source code of the application.
• solverName/createFields.H: declares all the field variables and initializes the solution. • utilityName/header_files.H: header files required to compile the application.
• The Make directory contains compilation instructions. • utilityName/utility_dictionary: application’s master dictionary.
• Make/files: names all the source files (.C), it specifies the solverName name and • The Make directory contains compilation instructions.
location of the output file. • Make/files: names all the source files (.C), it specifies the utilityName name
• Make/options: specifies directories to search for include files and libraries to link the and location of the output file.
solver against. • Make/options: specifies directories to search for include files and libraries to link the
30 solver against. 31

Directory structure of an OpenFOAM® application/utility Roadmap


• 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 1. OpenFOAM® brief overview
$WM_PROJECT_DIR/utilities/. 2. OpenFOAM® directory organization
• Also, you will need to modify the files Make/files and Make/options to
3. Directory structure of an application/utility
point to the new name and location of the compiled binaries and libraries to
link the solver against. 4. Applications/utilities in OpenFOAM®
• You can do anything you want to your own copies, so you do not risk 5. Directory structure of an OpenFOAM® case
messing things up.
6. Running my first OpenFOAM® case setup blindfold
• This is done so you do not modify anything in the original installation, except
for updates! 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

32 33
Applications/utilities in OpenFOAM® Applications/utilities in OpenFOAM®
• OpenFOAM® is not a single executable. • You will find all the applications in the directory $FOAM_SOLVERS (use alias sol to
• Depending of what you want to do, you will need to use a specific application and go there).
there are many of them. • You will find all the utilities in the directory $FOAM_UTILITIES (use alias util to go
• If you are interested in knowing all the solvers, utilities, and libraries that come with there).
your OpenFOAM® distribution, read the applications and libraries section in the user • For example, in the directory $FOAM_SOLVERS, you will find the directories containing
guide (chapter 3). In the directory $WM_PROJECT_DIR/doc you will find the the source code for the solvers available in the OpenFOAM® installation (version
documentation in pdf format. 5.x):
• You can also access the online user guide. Go to the link
http://cfd.direct/openfoam/user-guide/#contents, then go to chapter 3 • basic • financial
(applications and libraries). • combustion • heatTransfer
• If you want to get help on how to run an application, type in terminal • compressible • incompressible
• discreteMethods • lagrangian
1. $> application_name -help • DNS • multiphase
• electromagnetics • stressAnalysis
• The option –help will not run the application, it will only show all the options
available. • The solvers are subdivide according to the physics they address.
• You can also get all the help you want from the source code. • The utilities are also subdivided in a similar way.
34 35

Applications/utilities in OpenFOAM® Applications/utilities in OpenFOAM®


• For example, in the sub-directory incompressible you will find several sub- • Remember, OpenFOAM® is not a single executable.
directories containing the source code of the following solvers:
• You need to find the solver or utility that best fit what you want
• adjointShapeOptimizationFoam • pimpleFoam to do.
• boundaryFoam • pisoFoam • Take your time and explore the source code.
• icoFoam • shallowWaterFoam
• But be careful not to add unwanted modifications in the original
• nonNewtonianIcoFoam • simpleFoam
installation.
• 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 37
Roadmap Directory structure of an OpenFOAM® case
Directory structure of a general case
1. OpenFOAM® brief overview case_name • OpenFOAM® uses a very particular directory
├── 0 structure for running cases.
2. OpenFOAM® directory organization
│ ├── p • You should always follow the directory structure,
3. Directory structure of an application/utility │ └── U otherwise, OpenFOAM® will complain.
├── constant • To keep everything in order, the case directory is
4. Applications/utilities in OpenFOAM® │ ├── polyMesh often located in the path
$WM_PROJECT_USER_DIR/run.
│ │ ├── boundary
5. Directory structure of an OpenFOAM® case │ │ ├── faces • This is not compulsory but highly advisable. You can
copy the case files anywhere you want.
6. Running my first OpenFOAM® case setup blindfold │ │ ├── neighbour
• The name of the case is given by the user (do not
│ │ ├── owner use white spaces or strange symbols).
7. A deeper view to my first OpenFOAM® case setup │ │ └── points
• Depending of the solver or application you would like
│ └── transportProperties
8. 3D Dam break – Free surface flow ├── system
to use, you will need different files in each sub-
directory.
9. Flow past a cylinder – From laminar to turbulent flow │ ├── 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.

38 39

Directory structure of an OpenFOAM® case Let us run our first case


Directory structure of a general case At this point we are ready to run our first case.
case_name case_name: the name of the case is given by the user
So buckle up and enjoy the ride.
├── 0 (do not use white spaces or strange symbols). You
run the applications in this directory. • In the USB key you will find many tutorials (which are different from those that come with the OpenFOAM®
│ ├── p installation). During this training we will work with these tutorials to understand and get functional using
│ └── U system: contains run-time control and solver OpenFOAM®.
numerics.
├── constant • You can extract the tutorials wherever you want. However, we highly recommend you to extract them in your
│ ├── polyMesh constant: contains physical properties, OpenFOAM® user directory or in $WM_PROJECT_USER_DIR/run. From now on, this directory will become,
turbulence modeling properties, advanced physics
│ │ ├── boundary and so on. • $PTOFC
│ │ ├── faces (abbreviation of Path To OpenFOAM® Course)
constant/polyMesh: contains the
│ │ ├── neighbour • From now on and whenever you read $PTOFC, it is referring to the location where you extracted the training
polyhedral mesh information.
material.
│ │ ├── owner 0: contains boundary conditions (BC) and initial • You can add an alias to $PTOFC in your .bashrc file by adding the following line (remember to source again
│ │ └── points conditions (IC). the .bashrc file or to open a new terminal after modifying the file),
│ └── transportProperties time_directories: contains the solution and • alias PTOFC=‘cd PATH_TO_TUTORIALS’
├── system derived fields. These directories are created by the
• To uncompress the tutorials go to the directory where you copied the training material and type in the terminal,
│ ├── controlDict solver automatically and according to the preset
saving frequency, e.g., 1, 2, 3, 4, … , 100. • $> tar –zxvf file_name.tar.gz
│ ├── fvSchemes
│ └── fvSolution • On the other side, if you want to compress a directory you can proceed as follows,
└── time_directories • $> tar –zcvf file_name.tar.gz directory_name

40 41
Roadmap Running my first OpenFOAM® case setup blindfold
Before we start – Simulation workflow – Generic global view
1. OpenFOAM® brief overview
GEOMETRY
2. OpenFOAM® directory organization
3. Directory structure of an application/utility
4. Applications/utilities in OpenFOAM®
MESH
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
SOLVER CO-PROCESSING
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow

POST-PROCESSING

42 43

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Before we start – Always remember the directory structure Before we start – Setting OpenFOAM® cases
case_name
• As you will see, it is quite difficult to remember all the dictionary files needed to run
├── 0
each application.
├── constant
│ └── polyMesh • It is even more difficult to recall the compulsory and optional entries of each input file.
├── system • When setting a case from scratch in OpenFOAM®, what you need to do is find a
└── time_directories tutorial or a case that close enough does what you want to do and then you can adapt
it to your physics.
• 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 • Having this in mind, you have two sources of information:
the case in any directory of your preference. • $WM_PROJECT_DIR/tutorials
• The name of the case directory if given by the user (do not use white spaces). (The tutorials distributed with OpenFOAM®)

• You run the applications and utilities in the top level of this directory. • $PTOFC
(The tutorials used during this training)
• The directory system contains run-time control and solver numerics.
• The directory constant contains physical properties, turbulence modeling properties,
• If you use a GUI, things are much easier. However, OpenFOAM® does not come
advanced physics and so on. with a native GUI interface.
• The directory constant/polyMesh contains the polyhedral mesh information. • We are going to do things in the hard way (and maybe the smart way), we are going
• The directory 0 contains boundary conditions (BC) and initial conditions (IC). to use the Linux terminal
44 45
Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Flow in a lid-driven square cavity – Re = 100 Workflow of the case
Incompressible flow

Physical and numerical side of the


problem: blockMesh
• 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 extended to 3D easily.
icoFoam functionObjects
• 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).
sampling paraview
• For convenience, when dealing with
incompressible flows we will use relative pressure.
• All the dictionaries files have been already preset.

46 47

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
At the end of the day, you should get something like this 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

Mesh (very coarse and 2D)

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

• If you are using our virtual machine or using the lab workstations, you will need to
source OpenFOAM® (load OpenFOAM® environment).
• Let us run our first case. Go to the directory:
• To source OpenFOAM®, type in the terminal:
• $> of5x

$PTOFC/101OF/cavity2D
• To use PyFoam you will need to source it. Type in the terminal:
• $> anaconda2 or $> anaconda3

• From this point on, please follow me. • Remember, every time you open a new terminal window you need to source
OpenFOAM® and PyFoam.
• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you • By default, when installing OpenFOAM® and PyFoam you do not need to do this.
unpacked the tutorials. This is our choice as we have many things installed and we want to avoid conflicts
between applications.
50 51

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
What are we going to do? Running the case blindfold
• We will use the lid-driven square cavity tutorial as a general example to show you • Let us run this case blindfold.
how to set up and run solvers and utilities in OpenFOAM®. • Later we will study in details each file and directory.
• In this tutorial we are going to generate the mesh using blockMesh. • Remember, the variable $PTOFC is pointing to the path where you unpacked the
• After generating the mesh, we will look for topological errors and assess the mesh tutorials.
quality. For this we use the utility checkMesh. Later on, we are going to talk about • You can create this environment variable or write down the path to the directory.
what is a good mesh. • In the terminal window type:
• Then, we will find the numerical solution using icoFoam, which is a transient solver
1. $> cd $PTOFC/101OF/cavity
for incompressible, laminar flow of Newtonian fluids. By the way, we hope you did not
forget where to look for this information. 2. $> ls –l
• And we will finish with some cool visualization and post-processing using paraFoam. 3. $> blockMesh
• While we run this case, we are going to see a lot of information on the screen 4. $> checkMesh
(standard output stream or stdout), but it will not be saved. This information is mainly $> icoFoam
5.
related to convergence of the simulation, we will talk about this later on.
6. $> postProcess -func sampleDict -latestTime
7. $> gnuplot gnuplot/gnuplot_script
8. $> paraFoam
52 53
Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Running the case blindfold Crash introduction to paraFoam
• In step 1 we go to the case directory. Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
Menu Bar
• In step 2 we just list the directory structure. Does it look familiar to you? In the directory 0 you
Toolbars
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
Pipeline Browser
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 Properties panel
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. Apply button
Press this button to
This utility will read the dictionary file named sampleDict located in the directory system.
load the case or to
• In step 7 we use a gnuplot script to plot the sampled values. Feel free to take a look and reuse apply a filter
this script.
• Finally, in step 8 we visualize the solution using paraFoam. In the next slides we are going to
briefly explore this application.
3D View/Canvas
Advanced Toggle
54 55

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Toolbars Crash introduction to paraFoam – Mesh visualization
Select Surface With Edges in the Representation Toolbar Fit to screen Select the -Z view
• Main Controls
Select Solid Color in the
Active Variable Controls
• VCR Controls (animation controls)

• Current Time Controls Click on the eyeball in


the Pipeline Browser to
hide/unhide the object
• Active Variable Controls

• Representation Toolbar

Select mesh parts to visualize.


• Camera Controls (view orientation) By default it will automatically
select internalMesh

• Center Axes Controls

• Common Filters Select the volume fields to


visualize. By default it will select
U and p

• Data Analysis Toolbar


56 57
Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – 3D View and mouse interaction Crash introduction to paraFoam – Fields visualization
Select Last Frame in the VCR Controls Current Time Controls
Select view orientation in the Camera Controls

Mouse interaction in the Select U in Active Variable Controls


3D view

Turn on/off color bar

Rotate
Select Surface in the
Representation Toolbar

Select Magnitude in the


Zoom drop down menu

Pan

Zoom
Select volume fields to visualize.
By default it will select U and p.

3D View/Canvas

58 59

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters 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
Filters are attached
to the input data

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

• 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.

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

If you want to erase a filter,


right click on it and select Notice that the filter
Delete Glyph was applied on
the Slice1 filter.

4. Press Apply 3. Press Apply

3. Optional - Turn off the


option Show Plane
2. Filter options

Notice that the vectors are plotted in the


cell vertices. To plot the vectors at the
2. Select the direction Z Normal. cell centers, use the filter cell
Additionally you can choose the centers and replot the vectors.
origin of the plane (by default is the
mid section)

62 63

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Plot Over Line filter Crash introduction to paraFoam – Filters
4. Optional – Use the VCR Control to change the frame.
1.a. Select the Plot Over Line The line chart view will be updated automatically
filter.

1.b. Alternative, you can select Plot


Over Line filter from the Data
Analysis Toolbar

(0.5, 1, 1) 3. Optional - To save the


sampled data in CSV
format, click on the filter.
Then click on the File
Notice that we are using the filter in menu and select the
a clean Pipeline option Save Data

3. Press Apply

2. Select the variables to


plot in the line chart view
(0.5, 0, 1)
2. Enter the coordinates of the line

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

64 65
Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files Running the case blindfold with log files
• In the previous case, we ran the simulation but we did not save the standard output • There are many ways to save the log files.
stream (stdout) in a log file. • From now on, we will use the Linux tee command to save log files.
• We just saw the information on-the-fly. • To save a log file of the simulation, you can proceed as follows:

• Our advice is to always save the standard output stream (stdout) in a log file. $> foamCleanTutorials
1.
• It is of interest to always save the log as if something goes wrong and you would like 2. $> foamCleanPolyMesh
to do troubleshooting, you will need this information. 3. $> blockMesh
• Also, if you are interested in plotting the residuals you will need the log file. 4. $> checkMesh
5. $> icoFoam | tee log.icoFoam
• By the way, if at any point you ask us what went wrong with your simulation, we will
ask you for this file.

• We might also ask for the standard error stream (stderr). Vertical bar or pipelining operator, used to
concatenate commands

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

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files Running the case blindfold with log files
• In steps 1 and 2 we erase the mesh and all the folders, except for 0, constant and • To plot the information extracted with foamLog using gnuplot, we can proceed as
system. These scripts come with your OpenFOAM® installation. follows (remember, at this point we are using the gnuplot prompt):
• In step 3, we generate the mesh using the meshing tool blockMesh. 1. gnuplot> set logscale y
Set log scale in the y axis
• In step 4 we check the mesh quality.
2. gnuplot> plot ‘logs/p_0’ using 1:2 with lines
• In step 5 we run the simulation. Hereafter, we redirect the standard output to an ascii 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.
file with the name log.icoFoam (it can be any name). The tee command will
3. gnuplot> plot ‘logs/p_0’ using 1:2 with lines, ‘logs/pFinalRes_0’ using 1:2 with lines
redirect the screen output to the file log.icoFoam and at the same time will show Here we are plotting to different files. You can concatenate files using comma (,)

you the information on the screen. gnuplot> reset


4.
• To postprocess the information contained in the file log.icoFoam, we can use the To reset the scales

utility foamLog. Type in the terminal: 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
• $> foamLog log.icoFoam
6. gnuplot> set logscale y
• The utility foamLog will extract the information inside the file log.icoFoam. This
information is saved in an editable/plottable format in the directory logs. 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
• At this point we can use gnuplot to plot the residuals. Type in the terminal:
8. gnuplot> exit
• $> gnuplot To exit gnuplot

68 69
Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files Running the case blindfold with log files and plotting the residuals
• The output of step 3 is the following: • 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 our virtual machine or using the lab workstations, you will need to
source PyFoam.

• To source PyFoam, type in the terminal:


• $> anaconda2 or $> anaconda3

• If you need help or want to know all the options available,


• $> pyFoamPlotRunner.py –-help
• 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 71

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files and plotting the residuals Running the case blindfold with log files and plotting the residuals
• To run this case with pyFoamPlotRunner.py, in the terminal type: • This is a screenshot on my computer. In this case, pyFoamPlotRunner is plotting
• $> pyFoamPlotRunner.py icoFoam the initial residuals and continuity errors on the fly.

• 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.

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

Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Stopping the simulation Stopping the simulation
• The previous modifications can be done on-the-fly, but you will need to set the • 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
keyword runTimeModifiable to true in the controlDict dictionary.
be careful.
• By setting the keyword runTimeModifiable to true, you will be able to modify most of • If you launched the solver in background, just identify the process id using top or htop (or any other process
the dictionaries on-the-fly. 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.
1 /*--------------------------------*- C++ -*----------------------------------*\
2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 5.x | /*---------------------------------------------------------------------------*\
5 | \\ / A nd | Web: www.OpenFOAM.org |
6 | \\/ M anipulation | |
| ========= | |
7 \*---------------------------------------------------------------------------*/ | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
8 FoamFile | \\ / O peration | Version: 5.x |
9 { | \\ / A nd | Web: www.OpenFOAM.org |
10 version 2.0; | \\/ M anipulation | |
11 format ascii;
12 class dictionary;
\*---------------------------------------------------------------------------*/
13 object controlDict; Build : 4.x-e964d879e2b3
14 } Exec : icoFoam
Date : Mar 11 2017
44 Time : 23:21:50
45 runTimeModifiable true; Host : "linux-ifxc"
46
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 77
Running my first OpenFOAM® case setup blindfold Running my first OpenFOAM® case setup blindfold
Stopping the simulation Cleaning the case folder
• When working locally, we usually proceed in this way: • If you want to erase the mesh and the solution in the current case folder, you can type in the
terminal,

• $> icoFoam | tee log.icofoam $> foamCleanTutorials

This will run the solver icoFoam (by the way, this works for any solver or utility), it will save the If you are running in parallel, this will also erase the processorN directories. We will talk about
standard output stream in the file log.icofoam and will show the solver output on the fly. running in parallel later.

• If you are looking to only erase the mesh, you can type in the terminal,
• 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. $> foamCleanPolyMesh

• If we are interested in saving the last time step, we modify the controlDict dictionary and • If you are only interested in erasing the saved solutions, in the terminal type,
add the following keyword $> foamListTimes -rm
stopAt writeNow;

• If you are running in parallel and you want to erase the solution saved in the processorN
• Remember, this modification can be done on the fly. However, you will need to set the keyword directories, type in the terminal,
runTimeModifiable to yes in the controlDict dictionary. $> foamListTimes –rm -processor
78 79

Roadmap 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
1. OpenFOAM® brief overview system. After running icoFoam it also contains the time step directories 1, 2, 3,
2. OpenFOAM® directory organization ..., 48, 49, 50, the post-processing directory postProcessing, and the
log.icoFoam file (if you chose to redirect the standard output stream).
3. Directory structure of an application/utility
• The time step directories contain the values of all the variables at those time
4. Applications/utilities in OpenFOAM® steps (the solution). The 0 directory is thus the initial condition and boundary
conditions.
5. Directory structure of an OpenFOAM® case
• The constant directory contains the mesh and dictionaries for thermophysical,
6. Running my first OpenFOAM® case setup blindfold turbulence models and advanced physical models.
7. A deeper view to my first OpenFOAM® case setup • The system directory contains settings for the run, discretization schemes and
solution procedures.
8. 3D Dam break – Free surface flow
• The postProcessing directory contains the information related to the
9. Flow past a cylinder – From laminar to turbulent flow functionObjects (we are going to address functionObjects later).
• The icoFoam solver reads these files and runs the case according to those
settings.

80 81
A deeper view to my first OpenFOAM® case setup 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.
Let us explore the case directory
1 /*--------------------------------*- C++ -*----------------------------------*\
2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 5.x |
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 }

82 83

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

No. Property Unit Symbol


• In this directory you will find the sub-directory polyMesh and the dictionary file
transportProperties. 1 Mass Kilogram kg

• The transportProperties file is a dictionary for the dimensioned scalar nu, or the 2 Length meters m
kinematic viscosity.
3 Time second s

17 nu nu [ 0 2 -1 0 0 0 0 ] 0.01; //Re 100 4 Temperature Kelvin K


18 //nu nu [ 0 2 -1 0 0 0 0 ] 0.001; //Re 1000
5 Quantity moles mol

• Notice that line 18 is commented. 6 Current ampere A

• The values between square bracket are the units. 7 Luminuous intensity candela cd

• OpenFOAM® is fully dimensional. You need to define the dimensions for


each field dictionary and physical properties defined. [ 1 (kg), 2 (m), 3 (s), 4 (K), 5 (mol), 6 (A), 7 (cd)]
• Your dimensions shall be consistent.
84 85
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The constant directory The constant directory
(and by the way, open each file and go thru its content) (and by the way, open each file and go thru its content)

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

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

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

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

Which is equivalent to
• You can also change the free stream velocity U or the reference length L.
86 87

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The constant directory The constant/polyMesh directory
(and by the way, open each file and go thru its content) (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 • In this case, the polyMesh directory is initially empty. After generating the mesh, it
variables in the dictionary transportProperties. will contain the mesh in OpenFOAM® format.
• For instance, for a multiphase case you will need to define the density rho and • To generate the mesh in this case, we use the utility blockMesh. This utility reads
kinematic viscosity nu for each single phase. You will also need to define the surface the dictionary blockMeshDict located in the system folder.
tension .
• We will now take a quick look at the blockMeshDict dictionary in order to
• Also, depending of your physical model, you will find more dictionaries in the constant understand what we have done. Do not worry, we are going to revisit this dictionary
directory. during the meshing session.
• For example, if you need to set gravity, you will need to create the dictionary g. • Go to the directory system and open blockMeshDict dictionary with your favorite
text editor, we will use gedit.
• 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.

88 89
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary The system/blockMeshDict dictionary
• The blockMeshDict dictionary first defines a list with a number of vertices: • The blockMeshDict dictionary then defines a block from the 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 60 blocks
21 ymin 0; the geometry. In this case, there are eight vertices defining the geometry. 61 (
22 ymax 1;
23 zmin 0;
OpenFOAM® always uses 3D meshes, even if the simulation is 2D. 62 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
24 zmax 1;
• We can directly define the vertex coordinates in the section vertices 63 );
25
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 • In lines 60-63, we define the block topology, hex means that it is a
40 ($xmax $ymin $zmin) //vertex 1 • In lines 26-28, we define a set of variables that will be used at a later time. structured hexahedral block. In this case, we are generating a
41 ($xmax $ymax $zmin) //vertex 2
42 ($xmin $ymax $zmin) //vertex 3 rectangular mesh.
43 ($xmin $ymin $zmax) //vertex 4
• Finally, notice that the vertex numbering starts from 0 (as the counters in
44 ($xmax $ymin $zmax) //vertex 5 c++). This numbering applies for blocks as well. • (0 1 2 3 4 5 6 7) are the vertices used to define the block topology
45 ($xmax $ymax $zmax) //vertex 6 (and yes, the order is important). Each hex block is defined by eight
46 ($xmin $ymax $zmax) //vertex 7
47 vertices, in sequential order. Where the first vertex in the list
48 /* represents the origin of the coordinate system.
49 (0 0 0)
50 (1 0 0) • ($xcells $ycells $zcells) is the number of mesh cells in each
51 (1 1 0)
52 (0 1 0) direction (X Y Z). Notice that we are using macro syntax, which is
53 (0 0 0.1) equivalent to (20 20 1).
54 (1 0 0.1)
55 (1 1 0.1) • simpleGrading (1 1 1) is the expansion ratio or mesh stretching in
56 (0 1 0.1)
57 */ each direction (X Y Z), in this case the mesh is uniform.
58 );

90 91

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary The system/blockMeshDict dictionary
• The blockMeshDict dictionary then defines a block from the vertices: • The blockMeshDict dictionary also defines edges:

65 edges
66 (
67 //arc 0 1 (0.5 -0.1 0)
68 //arc 4 5 (0.5 -0.1 1)
69 );

• Edges, are constructed from the vertices definition.


• Each edge joining two vertex is assumed to be straight by default.

• Let us talk about the block ordering hex (0 1 2 3 4 5 6 7), which is extremely important. • The user can specified any edge to be curved by entries in the block edges.

• hex blocks are defined by eight vertices in sequential order. Where the first vertex in the list represents the • Possible options are: arc, spline, polyline, BSpline, line.
origin of the coordinate system (vertex 0 in this case). • For example, to define an arc we first define the vertices to be connected to form an edge and then we give an
• Starting from this vertex, we construct the block topology. So in this case, the first part of the block is made up interpolation point.
by vertices 0 1 2 3 and the second part of the block is made up by vertices 4 5 6 7. • In this case and as we do not specified anything, all edges are assumed to be straight lines.
• In this case, the vertices are ordered in such a way that if we look at the screen/paper (-Z direction), the • By the way, lines 67 and 68 are commented.
vertices rotate counter-clockwise.
92 93
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary The system/blockMeshDict dictionary
• The blockMeshDict dictionary also defines the boundary patches: • The blockMeshDict dictionary also defines the boundary patches:

• In the section boundary, we define all the surface • We can also group many faces into one patch, for
71 boundary 71 boundary
72 ( patches where we want to apply boundary conditions. 72 ( example, take a look at lines 86-88. In this case:
73 movingWall Name 73 movingWall
74 { • This step is of paramount importance, because if we do 74 { • The name of the patch is fixedWalls
75 type wall; Type 75 type wall;
not define the surface patches we will not be able to
76 faces 76 faces
• The base type is wall
77 (
Connectivity
apply the boundary conditions. 77 (
78 (3 7 6 2) 78 (3 7 6 2)
79 ); 79 ); • The surface patch is made up by the faces
• For example:
80
81
}
fixedWalls
80
81
}
fixedWalls
(0 4 7 3), (2 6 5 1), and (1 5 4 0).
82 { • In line 73 we define the patch name movingWall 82 {
83 type wall; 83 type wall; • The base type empty (line 93) is used to define a 2D
(the name is given by the user).
84
85
faces
(
84
85
faces
(
mesh. There is only one cell in the direction of the vector
86 (0 4 7 3) • In line 75 we give a base type to the surface patch. 86 (0 4 7 3) connecting faces (0 3 2 1) and (4 5 6 7).
87 (2 6 5 1) 87 (2 6 5 1)
88 (1 5 4 0) In this case wall (do not worry we are going to talk 88 (1 5 4 0)
• If you do not define a boundary patch, it will be
89 );
about this later on). 89 );
90 } 90 } automatically grouped in the patch defaultFaces of type
91 frontAndBack 91 frontAndBack
92 { • In line 78 we give the connectivity list of the 92 { empty.
93 type empty;
vertices that made up the surface patch or face, 93 type empty;
94 faces 94 faces • The name and type of the surface patch can be changed
95 ( that is, (3 7 6 2). Have in mind that the vertices 95 (
96 (0 3 2 1) 96 (0 3 2 1) outside of the blockMeshDict, we are going to address
need to be neighbors and it does not matter if the
97 (4 5 6 7) 97 (4 5 6 7)
this later.
98
99 }
);
ordering is clockwise or counter clockwise. 98
99 }
);

100 ); 100 );
• Remember, faces are defined by a list of 4 vertex
numbers, e.g., (3 7 6 2).
94 95

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary The system/blockMeshDict dictionary
• The blockMeshDict dictionary also defines how to merge multiple blocks: • To sum up, the blockMeshDict dictionary generates a single block with:
• X/Y/Z dimensions: 1.0/1.0/1.0
102 mergePatchPairs • Cells in the X, Y and Z directions: 20 x 20 x 1 cells.
103 (
104 //(interface1 interface2)
• One single hex block with straight lines.
105 );

• Patch type wall and patch name fixedWalls at three sides.


• Patch type wall and patch name movingWall at one side.
• A mesh can be created using more than 1 block. To do so we proceed in the same • Patch type empty and patch name frontAndBack patch at two sides.
way, the only difference is that we need to connect the blocks.
• We can merge blocks in the section mergePatchPairs (lines 102-105). This requires
that the block patches to be merged are first defined in the boundary list (interface1 • If you are interested in visualizing the actual block topology, you can use paraFoam
and interface2 in this case), blockMesh then connect the two blocks. as follows,
• Line 104 is commented. We are not merging blocks, we will talk about this during the • $> paraFoam –block
meshing session.

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

• As you can see, the blockMeshDict dictionary can be really tricky. • First at all, this file is automatically generated after you create the mesh
• If you deal with really easy geometries (rectangles, cylinders, and so on), then you using blockMesh or snappyHexMesh, or when you convert the mesh from
can use blockMesh to do the meshing, but this is the exception rather than the rule. a third-party format.
• When using snappyHexMesh, (a body fitted mesher that comes with OpenFOAM®) • In this file, the geometrical information related to the base type patch of
you will need to generate a background mesh using blockMesh. We are going to each boundary (or surface patch) of the domain is specified.
deal with this later on.
• The base type boundary condition is the actual surface patch where we are
• Our best advice is to create a template and reuse it until the end of the world. going to apply a primitive type boundary condition (or numerical boundary
• Also, take advantage of macro syntax for parametrization, and #calc syntax to condition).
perform inline calculations (lines 30-35 in the blockMeshDict dictionary we just
• The primitive type boundary condition assign a field value to the surface
studied).
patch (base type).
• We are going to deal with #codeStream syntax and #calc syntax during the
programming session. • You define the primitive type patch (or the value of the boundary condition),
in the directory 0 or time directories.

The mesher blockMesh has many more features that we did not address in
this short overview. Refer to the User Guide for more Information.
98 99

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

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

18 3 Number of surface patches 18 3


19 (
In the list bellow there must be 3 patches 19 ( Name and type of the surface patches
20 movingWall 20 movingWall Name
21 { definition. 21 {
22 type wall; 22 type wall; Type • The name and type of the patch is given by
23 inGroups 1(wall); movingWall 23 inGroups 1(wall);
24 nFaces 20; 24 nFaces 20; the user.
25 startFace 760; 25 startFace 760;
26 } frontAndBack 26 } • In this case the name and type was assigned
27 fixedWalls 27 fixedWalls in the dictionary blockMeshDict.
28 { 28 {
29 type wall; 29 type wall; • You can change the name if you do not like it.
30 inGroups 1(wall); 30 inGroups 1(wall);
31 nFaces 60; 31 nFaces 60; Do not use strange symbols or white spaces.
32 startFace 780; 32 startFace 780;
33 } 33 } • You can also change the base type. For
fixedWall
fixedWall

34 frontAndBack 34 frontAndBack instance, you can change the type of the


35 { 35 {
36 type empty; 36 type empty;
patch movingWall from wall to patch.
37 inGroups 1(empty); 37 inGroups 1(empty);
38 nFaces 800; 38 nFaces 800;
• When converting the mesh from a third party
39 startFace 840; 39 startFace 840; format, OpenFOAM® will try to recover the
40 } 40 } information from the original format. But it
41 ) 41 )
might happen that it does not recognizes the
frontAndBack
base type and name of the original file. In this
case you will need to modify this file manually.
fixedWall

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

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

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

• Groups can have more than one patch.

102 103

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

• There are a few base type patches that are constrained or paired. This means that the type • The following base type boundary conditions are constrained or paired.
should be the same in the boundary file and in the numerical boundary condition defined in the
That is, the type needs to be same in the boundary dictionary and field
field files, e.g., the files 0/U and 0/p.
variables dictionaries (e.g. U, p).
• In this case, the base type of the patch frontAndBack (defined in the file boundary), is
consistent with the primitive 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), constant/polyMesh/boundary 0/U - 0/p (IC/BC)
is consistent with the primitive 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
symmetry symmetry
the patches is set as you would like.
symmetryPlane symmetryPlane
• 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 primitive type of the patches (the empty empty
patch type defined in the field files contained in the directory 0 (or whatever time directory you
wedge wedge
defined the boundary and initial conditions).
cyclic cyclic
• If the base type and primitive type boundary conditions are not consistent, OpenFOAM® will
complain. processor processor
• Do not worry, we are going to address boundary conditions later on.

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

• The base type patch can be any of the primitive or derived type boundary • The wall base type boundary condition is defined as follows:
conditions available in OpenFOAM®. Mathematically speaking; they can be
Dirichlet, Neumann or Robin boundary conditions.
constant/polyMesh/boundary 0/U (IC/BC) 0/p (IC/BC)
constant/polyMesh/boundary 0/U - 0/p (IC/BC)

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

zeroGradient
inletOutlet
slip
patch
totalPressure
• This boundary condition is not contained in the patch base type boundary
condition group, because specialize modeling options can be used on this
supersonicFreeStream
boundary condition.
and so on …
Refer to the doxygen documentation for a list of all numerical • An example is turbulence modeling, where turbulence can be generated or
type boundary conditions available.
dissipated at the walls.
106 107

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary The system directory
(and by the way, open each file and go thru its content)
• The name of the base type boundary condition and the name of the
• The system directory consists of the following compulsory dictionary files:
primitive type boundary condition needs to be the same, if not,
• controlDict
OpenFOAM® will complain.
• fvSchemes
• Pay attention to this, specially if you are converting the mesh from another • fvSolution
format. • 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.
constant/polyMesh/boundary 0/U (IC/BC) 0/p (IC/BC) • 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).
movingWall movingWall movingWall • If you forget a compulsory keyword or give a wrong entry to the keyword, OpenFOAM® will
fixedWalls fixedWalls fixedWalls complain and it will let you what are you missing. This applies for all the dictionaries in the
hierarchy of the case directory.
frontAndBack frontAndBack frontAndBack
• 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
• As you can see, all the names are the same across all the dictionary files. optional. However, if the entry you use for the optional parameter is wrong OpenFOAM® will let
you know.
108 109
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The controlDict dictionary The controlDict dictionary
• The controlDict dictionary contains runtime simulation controls, such
as, start time, end time, time step, saving frequency and so on.
• So how do we know what options are available for each keyword?
17 application icoFoam; • Most of the entries are self-explanatory. 17 application icoFoam;
18 18 • The hard way is to refer to the source code.
19 startFrom startTime; • This case starts from time 0 (keyword startFrom – line 19 – and 19 startFrom startTime;
20
21 startTime 0; keyword startTime – line 21 –). If you have the initial solution in a
20
21 startTime 0;
• The easy way is to use the banana method.
22 different time directory, just enter the number in line 21. 22
23 stopAt endTime; 23 stopAt banana; • So what is the banana method? This method consist in inserting a
24
25 endTime 50;
• The case will stop when it reaches the desired time set using the keyword 24
25 endTime 50; dummy word (that does not exist in the installation) and let
26 stopAt (line 23). 26 OpenFOAM® list the available options.
27 deltaT 0.01; 27 deltaT 0.01;
28 • It will run up to 50 seconds (keyword endTime – line 25 –). 28
• For example. If you add banana in line 23, you will get this output:
29 writeControl runTime; 29 writeControl runTime;
30 30
31 writeInterval 1; • The time step of the simulation is 0.01 seconds (keyword deltaT 31 writeInterval 1; banana is not in enumeration
32 – line 27 –). 32 4
33 purgeWrite 0; 33 purgeWrite 0;
34
• It will write the solution every second (keyword writeInterval – line 31 –) 34 (
35 writeFormat ascii; 35 writeFormat ascii;
36 of simulation time (keyword runTime – line 29 –). 36 nextWrite
37 writePrecision 8; 37 writePrecision 8; writeNow
38 • It will keep all the solution directories (keyword purgeWrite – line 33 –). 38
39 writeCompression off; 39 writeCompression off; noWriteNow
If you want to keep only the last 5 solutions just change the value to 5.
40
41 timeFormat general;
40
41 timeFormat general;
endTime
42 • It will save the solution in ascii format (keyword writeFormat – line 35 –) 42 )
43 timePrecision 6; 43 timePrecision 6;
44
with a precision of 8 digits (keyword writePrecision – line 37 –). 44
45 runTimeModifiable true; 45 runTimeModifiable true;
• And as the option runTimeModifiable (line 45) is on (true), we can • So your options are nextWrite, writeNow, noWriteNow, endTime
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.

110 111

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

• And how do we know that banana does not exist in the source code? • If you forget a compulsory keyword, OpenFOAM® will tell you what
17 application icoFoam; 17 application icoFoam;
are you missing.
18 • Just type in the terminal: 18
19 startFrom startTime; 19 startFrom startTime;
20
• $> src 20 • So if you comment line 25, you will get this output:
21 startTime 0; 21 startTime 0;
22 22
23 stopAt banana; • $> grep –r –n banana . 23 stopAt endTime;
24 24 --> FOAM FATAL IO ERROR
25 endTime 50; 25 //endTime 50;
26 26 keyword endTime is undefined in dictionary …
27 deltaT 0.01; 27 deltaT 0.01;
28 • If you see some bananas in your output someone is messing around 28
29 writeControl runTime;
with your installation. 29 writeControl runTime;
30 30 • This output is just telling you that you are missing the keyword
31 writeInterval 1; 31 writeInterval 1;
32 • You can use the same command to look for information in the 32 endTime.
33
34
purgeWrite 0;
OpenFOAM® installation, just replace the word banana for the word 33
34
purgeWrite 0;

35 writeFormat ascii; you are looking for. 35 writeFormat ascii;


36 36
• Do not pay attention to the words FATAL ERROR, maybe the
37 writePrecision 8;
• Remember, you can use any dummy word, but you have to be sure 37 writePrecision 8;
38 38
developers of OpenFOAM® exaggerated a little bit.
39 writeCompression off; that it does not exist in OpenFOAM®. 39 writeCompression off;
40 40
41 timeFormat general; 41 timeFormat general;
42 42
43 timePrecision 6; 43 timePrecision 6;
44 44
45 runTimeModifiable true; 45 runTimeModifiable true;

112 113
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The fvSchemes dictionary The fvSolution dictionary

• The fvSchemes dictionary contains the information related to


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

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

• To solve U we are using the smoothSolver method, with the


• In the system directory you will also find these two additional files:
17 solvers
18 { smoother symGaussSeidel, an absolute tolerance equal to
19 p
20 { 1e-08 and a relative tolerance relTol equal to 0.
21
22
solver
preconditioner
PCG;
DIC; • The solvers will iterative until reaching any of the tolerance
• decomposeParDict
23 tolerance 1e-06;
values set by the user or reaching a maximum value of
• sampleDict
24 relTol 0;

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.
• decomposeParDict is read by the utility decomposePar. This dictionary
44 relTol 0;
45 } • The PISO sub-dictionary contains entries related to the
46
pressure-velocity coupling method (the PISO method).
47
48
U
{
file contains information related to the mesh partitioning. This is used when
• In this case we are doing only one PISO correction and no
49
50
solver
smoother
smoothSolver;
symGaussSeidel;
orthogonal corrections.
running in parallel. We will address running in parallel later.
51 tolerance 1e-08;
52 relTol 0;
53
54 }
} • You need to do at least one PISO loop (nCorrectors). • sampleDict is read by the utility postProcess. This utility sample field
55
56 PISO 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
57 {
58 nCorrectors 1;
59 nNonOrthogonalCorrectors 0;
60
61
pRefCell
pRefValue
0;
0;
gnuplot or Python.
62 }

116 117
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The sampleDict dictionary The sampleDict dictionary
Type of sampling, sets will sample along a line.
The sampled information is always saved in the
Format of the output file, raw format is a generic format directory,
17 type sets; that can be read by many applications. The output file is 17 type sets;
18
human readable (ascii format). 18 postProcessing/name_of_input_dictionary
19 setFormat raw; 19 setFormat raw;
20 20
23 interpolationScheme cellPointFace; Interpolation method at the solution level (location of the 23 interpolationScheme cellPointFace;
24 24
26 fields interpolation points). 26 fields As we are sampling the latest time solution (50) and
27 ( 27 (
28 U Fields to sample. 28 U using the dictionary sampleDict, the sampled data
29 ); 29 );
30 30 will be located in the directory:
31 sets 31 sets
32
33
(
Sample method. How to interpolate the solution to the
32
33
(
postProcessing/sampleDict/50
34
35
l1
{
sample entity (line in this case) 34
35
l1
{
36 type midPointAndFace; 36 type midPointAndFace;
43 axis x; 43 axis x;
44 start ( -1 0.5 0); Location of the sample line. We define start and end 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); point, and the axis of the sampling. 45
46 }
end ( 2 0.5 0);
directory postProcessing/sampleDict/50
47
48 l2
47
48 l2 contain the sampled data. Feel free to open them using
49 { 49 {
your favorite text editor.
50
54
type
axis
midPointAndFace;
y;
Sample method from the solution to the line. 50
54
type
axis
midPointAndFace;
y;
55 start (0.5 -1 0); 55 start (0.5 -1 0);
56 end (0.5 2 0); 56 end (0.5 2 0);
57 } 57 }
58 58 Name of the output file
59 );
Location of the sample line. We define start and end 59 );

point, and the axis of the sampling.


Name of the output file
118 119

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The 0 directory The 0 directory
(and by the way, open each file and go thru its content) (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, • 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): 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 17 dimensions [0 1 -1 0 0 0 0]; Dimensions of the field
18 18
19 internalField uniform (0 0 0); 19 internalField uniform (0 0 0);
20 20
21 boundaryField 21 boundaryField
22 { 22 {
23 movingWall 23 movingWall
24 { Uniform initial conditions. 24 {
25 type fixedValue; 25 type fixedValue; Numerical boundary condition for the patch
26 value uniform (1 0 0); The velocity field is initialize to (0 0 0) in all 26 value uniform (1 0 0); movingWall
27 } 27 }
the domain
28 28
29 fixedWalls Remember velocity is a vector with three 29 fixedWalls
30 { 30 {
31 type fixedValue; components, therefore the notation (0 0 0). 31 type fixedValue; Numerical boundary condition for the patch
32 value uniform (0 0 0); 32 value uniform (0 0 0); fixedWalls
33 } 33 }
34 34
35 frontAndBack Note: 35 frontAndBack
If you take some time and compare the files 0/U and
36 { 36 {
37 type empty;
constant/polyMesh/boundary, you will see that the name and type of each
37 type empty;
Numerical boundary condition for the patch
primitive 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). 38 } frontAndBack (this is a constrained boundary
39 } 39 } condition).
120 121
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The 0 directory The 0 directory
(and by the way, open each file and go thru its content) (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, • 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): 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 17 dimensions [0 2 -2 0 0 0 0]; Dimensions of the field
18 18
19 internalField uniform 0; 19 internalField uniform 0;
20 20
21 boundaryField 21 boundaryField
22 { 22 {
23 movingWall 23 movingWall
24 { Uniform initial conditions. 24 {
Numerical boundary condition for the patch
25 type zeroGradient; 25 type zeroGradient;
26 } The modified pressure field is initialize to 0 26 } movingWall
27 27
in all the domain. This is relative
28 fixedWalls 28 fixedWalls
29 { pressure. 29 {
30 type zeroGradient; 30 type zeroGradient;
Numerical boundary condition for the patch
31 } 31 } fixedWalls
32 32
33 frontAndBack 33 frontAndBack
34 { 34 {
35 type empty; Note: 35 type empty;
Numerical boundary condition for the patch
If you take some time and compare the files 0/p and frontAndBack (this is a constrained boundary
36 } 36 }
constant/polyMesh/boundary, you will see that the name and type of each
37 }
primitive type patch (the patch defined in 0/p), is consistent with the base
37 } condition).
38 type patch (the patch defined in the file constant/polyMesh/boundary). 38

122 123

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
• Coming back to the headers, and specifically the headers related to the field variable
A very important remark on the pressure field dictionaries (e.g. U, p).
• In the header of your field variables, the class type should be consistent with the type
• We just used icoFoam which is an incompressible solver. of field variable you are using.
• Let us be really loud on this. All the incompressible solvers implemented in OpenFOAM® • If the field variable is a scalar, the class should be volScalarField.
(icoFoam, simpleFoam, pisoFoam, and pimpleFoam), use the modified pressure, that is,

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


with units | ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 5.x |
| \\ / A nd | Web: www.OpenFOAM.org |
• Or in OpenFOAM® jargon: dimensions [0 2 -2 0 0 0 0] | \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
• So when visualizing or post processing the results do not forget to multiply the pressure by FoamFile
the density in order to get the right units of the physical pressure, that is, {
version 2.0;
format ascii;
class volScalarField;
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
• Or in OpenFOAM® jargon: dimensions [1 -1 -2 0 0 0 0]

124 125
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
• Coming back to the headers, and specifically the headers related to the field variable • Coming back to the headers, and specifically the headers related to the field variable
dictionaries (e.g. U, p). dictionaries (e.g. U, p).
• In the header of your field variables, the class type should be consistent with the type • In the header of your field variables, the class type should be consistent with the type
of field variable you are using. of field variable you are using.
• If the field variable is a vector, the class should be volVectorField. • If the field variable is a tensor (e.g. the velocity gradient tensor), the class should be
volTensorField.

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


| ========= | | /*--------------------------------*- C++ -*----------------------------------*\
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | | ========= | |
| \\ / O peration | Version: 5.x | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / A nd | Web: www.OpenFOAM.org | | \\ / O peration | Version: 5.x |
| \\/ M anipulation | | | \\ / A nd | Web: www.OpenFOAM.org |
\*---------------------------------------------------------------------------*/ | \\/ M anipulation | |
FoamFile \*---------------------------------------------------------------------------*/
{ FoamFile
version 2.0; {
format ascii; version 2.0;
class volVectorField; format ascii;
object U; class volTensorField;
} object gradU;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

126 127

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The log.icoFoam file The log.icoFoam file
• In this case, pyFoamPlotWatcher is plotting the initial residuals, continuity errors
• If you followed the previous instructions you should now have the log.icoFoam file.
and courant number.
This file contains all the residuals and convergence information.

• We already plotted this information using foamLog and gnuplot.

• Let us plot this information again but this time using PyFoam, in the terminal type:
• $> pyFoamPlotWatcher.py log.icoFoam -–with-courant

• The script pyFoamPlotWatcher.py will plot the information in the log file, even if
the simulation is not running.
• The option -–with-courant will plot the courant number.
• Remember, to use PyFoam you will need to source it. Type in the terminal:
• $> anaconda2 or $> anaconda3

128 129
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The output screen The output screen
• Finally, let us talk about the output screen, which shows a lot of information. • 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 {
Velocity residuals 51 Name of the folder where the output of
Simulation time 52 /////////////////////////////////////////////////////////////////////////// the functionObject will be saved
53
Courant number 54 minmaxdomain
Pressure residuals 55 {
No orthogonal corrections 56 type fieldMinMax; functionObject to use
57
Only one PISO correction 58 functionObjectLibs ("libfieldFunctionObjects.so");
Execution time (wall time)
59
60 enabled true; //true or false Turn on/off functionObject
Continuity errors 61
62 mode component;
63
Additional information 64 writeControl timeStep;
End of the simulation Minimum and maximum values of each field 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 };
130 131

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The output screen The output screen
• Another very important output information is the CFL or Courant number. • 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).
• The Courant number imposes the CFL number condition, which is the maximum allowable
• For a time step of 0.01 seconds, this is the output we get,
CFL number a numerical scheme can use. For the n - dimensional case, the CFL number
condition becomes,
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:


• In OpenFOAM®, most of the solvers are implicit, which means they are unconditionally min(p) = -0.37208362 at location (0.025 0.975 0.5)
max(p) = 0.77640927 at location (0.975 0.975 0.5)
stable. In other words, they are not constrained to the CFL number condition. 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)

• However, the fact that you are using a numerical method that is unconditionally stable, does Time = 50
CFL number at
not mean that you can choose a time step of any size. 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
• The time-step must be chosen in such a way that it resolves the time-dependent features, and it 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
maintains the solver stability. ExecutionTime = 4.47 s ClockTime = 5 s

fieldMinMax minmaxdomain output:


• For the moment and for the sake of simplicity, let us try to keep the CFL number below 5.0 and min(p) = -0.37208345 at location (0.025 0.975 0.5)
max(p) = 0.77640927 at location (0.975 0.975 0.5)
preferably less than 1.0 (for good accuracy). 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)

• 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. 132 133
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The output screen 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 • 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). changing the time step).
• For a time step of 0.1 seconds, this is the output we get, • For a time step of 0.5 seconds, this is the output we get,

Time = 49.9 Time = 2


CFL number at CFL number at
Courant Number mean: 0.4441161 max: 1.6798756 Courant Number mean: 1.6828931 max: 5.6061178
time step n - 1 time step n - 1
smoothSolver: Solving for Ux, Initial residual = 0.00016535808, Final residual = 2.7960145e-09, No Iterations 5 smoothSolver: Solving for Ux, Initial residual = 0.96587058, Final residual = 4.9900041e-09, No Iterations 27
smoothSolver: Solving for Uy, Initial residual = 0.00015920267, Final residual = 2.7704949e-09, No Iterations 5 smoothSolver: Solving for Uy, Initial residual = 0.88080685, Final residual = 9.7837781e-09, No Iterations 25
DICPCG: Solving for p, Initial residual = 0.0015842846, Final residual = 5.2788554e-07, No Iterations 26 DICPCG: Solving for p, Initial residual = 0.95568243, Final residual = 7.9266324e-07, No Iterations 33
time step continuity errors : sum local = 8.6128916e-09, global = 3.5439859e-19, cumulative = 2.4940081e-17 time step continuity errors : sum local = 6.3955627e-06, global = 1.3227253e-17, cumulative = 1.4125109e-17
ExecutionTime = 0.81 s ClockTime = 1 s ExecutionTime = 0.04 s ClockTime = 0 s

fieldMinMax minmaxdomain output: fieldMinMax minmaxdomain output:


min(p) = -0.34322821 at location (0.025 0.975 0.5) min(p) = -83.486425 at location (0.975 0.875 0.5) Compare these values with the values
max(p) = 0.73453489 at location (0.975 0.975 0.5) max(p) = 33.078468 at location (0.025 0.925 0.5)
of the previous cases. For the
min(U) = (0.0002505779 -0.00025371425 0) at location (0.025 0.025 0.5) min(U) = (0.1309243 -0.13648118 0) at location (0.025 0.025 0.5)
max(U) = (0.0002505779 -0.00025371425 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 = 50 Time = 2.5
CFL number at CFL number at
Courant Number mean: 0.44411473 max: 1.6798833 Courant Number mean: 8.838997 max: 43.078153
smoothSolver: Solving for Ux, Initial residual = 0.00016378098, Final residual = 2.7690608e-09, No Iterations 5 time step n #0 Foam::error::printStack(Foam::Ostream&) at ??:? time step n (way
smoothSolver: Solving for Uy, Initial residual = 0.00015720331, Final residual = 2.7354499e-09, No Iterations 5 #1 Foam::sigFpe::sigHandler(int) at ??:? too high)
DICPCG: Solving for p, Initial residual = 0.0015662416, Final residual = 5.2290439e-07, No Iterations 26 #2 ? in "/lib64/libc.so.6"
time step continuity errors : sum local = 8.5379223e-09, global = -3.6676527e-19, cumulative = 2.4573316e-17 #3 Foam::symGaussSeidelSmoother::smooth(Foam::word const&, Foam::Field<double>&, Foam::lduMatrix const&, Foam::Field<double> const&,
ExecutionTime = 0.81 s ClockTime = 1 s 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 ??:?
fieldMinMax minmaxdomain output: #5 Foam::smoothSolver::solve(Foam::Field<double>&, Foam::Field<double> const&, unsigned char) const at ??:?
min(p) = -0.34244269 at location (0.025 0.975 0.5) #6 ? at ??:?
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) The solver crashed.
max(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5) The offender? Time step too large.

134 135

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
The output screen Error output
• Another output you should monitor are the continuity errors. • If you forget a keyword or a dictionary file, give a wrong option to a compulsory or optional entry,
• These numbers should be small (it does not matter if they are negative or positive). 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.
• If these values increase in time (about the order of 1e-3), you better control the case setup because
something is wrong. • This error does not mean that the actual OpenFOAM® installation is corrupted. It is telling you
• The continuity errors are defined in the following file that you are missing something or something is wrong in a dictionary.
$WM_PROJECT_DIR/src/finiteVolume/cfdTools/incompressible/continuityErrs.H • Maybe the guys of OpenFOAM® went a little bit extreme here.

/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 5.x |
Time = 50 | \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
Courant Number mean: 0.44411473 max: 1.6798833 \*---------------------------------------------------------------------------*/
smoothSolver: Solving for Ux, Initial residual = 0.00016378098, Final residual = 2.7690608e-09, No Iterations 5 Build : 5.x-5d8318b22cbe
smoothSolver: Solving for Uy, Initial residual = 0.00015720331, Final residual = 2.7354499e-09, No Iterations 5 Exec : icoFoam
DICPCG: Solving for p, Initial residual = 0.0015662416, Final residual = 5.2290439e-07, No Iterations 26 Date : Nov 02 2014
time step continuity errors : sum local = 8.5379223e-09, global = -3.6676527e-19, cumulative = 2.4573316e-17 Time : 00:33:41
ExecutionTime = 0.81 s ClockTime = 1 s Host : "linux-cfd"
PID : 3675
fieldMinMax minmaxdomain output: Case : /home/cfd/my_cases_course/cavity
min(p) = -0.34244269 at location (0.025 0.975 0.5) nProcs : 1
max(p) = 0.73656831 at location (0.975 0.975 0.5) sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
min(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5) fileModificationChecking : Monitoring run-time modified files using timeStampMaster
max(U) = (0.00025028679 -0.00025338014 0) at location (0.025 0.025 0.5) Continuity errors allowSystemOperations : Allowing user-supplied system call operations

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

--> FOAM FATAL IO ERROR:

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

Build : 5.x-5d8318b22cbe
Exec : icoFoam
Date
Time
: Nov 02 2014
: 00:33:41 “Experience is simply the name we give our mistakes.”
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
• Train yourself to identify the errors. Hereafter we list a few possible errors.
--> FOAM FATAL IO ERROR:
• Missing compulsory file p
banana_endTime is not in enumeration: The origin of the error
4
( --> FOAM FATAL IO ERROR:
endTime
nextWrite cannot find file
Possible options to correct the error
noWriteNow
writeNow file: /home/joegi/my_cases_course/5x/101OF/cavity/0/p at line 0.
)

file: /home/cfd/my_cases_course/cavity/system/controlDict.stopAt at line 24. Location of the error From function regIOobject::readStream()
in file db/regIOobject/regIOobjectRead.C at line 73.
From function NamedEnum<Enum, nEnum>::read(Istream&) const
in file lnInclude/NamedEnum.C at line 72. FOAM exiting
FOAM exiting

138 139

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

--> FOAM FATAL IO ERROR: --> FOAM FATAL IO ERROR:


keyword class is undefined in dictionary "/home/joegi/my_cases_course/5x/101OF/cavity/0/p" Cannot find patchField entry for xmovingWall

file: /home/joegi/my_cases_course/5x/101OF/cavity/0/p from line 10 to line 13. file: /home/joegi/my_cases_course/5x/101OF/cavity/0/p.boundaryField from line 25 to line 35.

From function dictionary::lookupEntry(const word&, bool, bool) const From function GeometricField<Type, PatchField, GeoMesh>::GeometricBoundaryField::readField(const
in file db/dictionary/dictionary.C at line 442. DimensionedField<Type, GeoMesh>&, const dictionary&)
in file /home/joegi/OpenFOAM/OpenFOAM-5.x/src/OpenFOAM/lnInclude/GeometricBoundaryField.C at line 209.
FOAM exiting
FOAM exiting

• Misspelled word in file boundary • Missing compulsory keyword in fvSchemes


--> FOAM FATAL IO ERROR: --> FOAM FATAL IO ERROR:
unexpected class name spolyBoundaryMesh expected polyBoundaryMesh keyword div(phi,U) is undefined in dictionary
while reading object boundary "/home/joegi/my_cases_course/5x/101OF/cavity/system/fvSchemes.divSchemes"
file: /home/joegi/my_cases_course/5x/101OF/cavity/constant/polyMesh/boundary at line 15. file: /home/joegi/my_cases_course/5x/101OF/cavity/system/fvSchemes.divSchemes from line 30 to line 30.
From function regIOobject::readStream(const word&) From function dictionary::lookupEntry(const word&, bool, bool) const
in file db/regIOobject/regIOobjectRead.C at line 136. in file db/dictionary/dictionary.C at line 442.
FOAM exiting FOAM exiting

140 141
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
Error output Error output
• Missing entry in file fvSolution at keyword PISO • Missing keyword deltaT in file controlDict
--> FOAM FATAL IO ERROR:
"ill defined primitiveEntry starting at keyword 'PISO' on line 68 and ending at line 68" --> FOAM FATAL IO ERROR:
keyword deltaT is undefined in dictionary "/home/joegi/my_cases_course/5x/101OF/cavity/system/controlDict"
file: /home/joegi/my_cases_course/5x/101OF/cavity/system/fvSolution at line 68.
file: /home/joegi/my_cases_course/5x/101OF/cavity/system/controlDict from line 17 to line 69.
From function primitiveEntry::readEntry(const dictionary&, Istream&)
in file lnInclude/IOerror.C at line 132. From function dictionary::lookupEntry(const word&, bool, bool) const
in file db/dictionary/dictionary.C at line 442.
FOAM exiting
FOAM exiting

• Incompatible dimensions. Likely the offender is the file U


• Missing file points in directory polyMesh. Likely you are missing the mesh.
--> FOAM FATAL ERROR:
incompatible dimensions for operation
[U[0 1 -2 1 0 0 0] ] + [U[0 1 -2 2 0 0 0] ] --> FOAM FATAL ERROR:
Cannot find file "points" in directory "polyMesh" in times 0 down to constant
From function checkMethod(const fvMatrix<Type>&, const fvMatrix<Type>&)
in file /home/joegi/OpenFOAM/OpenFOAM-5.x/src/finiteVolume/lnInclude/fvMatrix.C at line 1295. From function Time::findInstance(const fileName&, const word&, const IOobject::readOption, const word&)
in file db/Time/findInstance.C at line 203.
FOAM aborting
FOAM exiting
#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 142 143

A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
Error output Error output
• Unknown boundary condition type. • This one is specially hard to spot

--> FOAM FATAL IO ERROR: /*---------------------------------------------------------------------------*\


Unknown patchField type sfixedValue for patch type wall | ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
Valid patchField types are : | \\ / O peration | Version: 5.x |
| \\ / A nd | Web: www.OpenFOAM.org |
74 | \\/ M anipulation | |
( \*---------------------------------------------------------------------------*/
SRFFreestreamVelocity Build : 5.x-5d8318b22cbe
SRFVelocity Exec : icoFoam
SRFWallVelocity Date : Nov 02 2014
activeBaffleVelocity 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
variableHeightFlowRateInletVelocity
waveTransmissive
wedge
zeroGradient
) • 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 white space between the word cavity and
file: /home/joegi/my_cases_course/5x/101OF/cavity/0/U.boundaryField.movingWall from line 25 to line 26.
the number 0).
From function fvPatchField<Type>::New(const fvPatch&, const DimensionedField<Type, volMesh>&, const
dictionary&) • Do not use white spaces or funny symbols when naming directories and files.
in file /home/joegi/OpenFOAM/OpenFOAM-5.x/src/finiteVolume/lnInclude/fvPatchFieldNew.C at line 143.

FOAM exiting
• Instead of cavity 0 you should use cavity_0.
144 145
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
Error output Dictionary files general features
• You should worry about the SIGFPE error signal. This error signal indicates that something
went really wrong (erroneous arithmetic operation). • OpenFOAM® follows same general syntax rules as in C++.
• This message (that seems a little bit difficult to understand), is giving you a lot information. • Commenting in OpenFOAM® (same as in C++):
• 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
// This is a line comment
(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" This is a block comment
#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 ??:?
• The #include directive (same as in C++):
#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 ??:?
#include “initialConditions”
#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 ??:?
Do not forget to create the respective include file initialConditions.
#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 146 147

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

• Scalars, vectors, lists and dictionaries. • Scalars, vectors, lists and dictionaries.
• Scalars in OpenFOAM® are represented by a single value, e.g., • List entries are contained within parentheses ( ). A list can contain scalars,
3.14159 vectors, tensors, words, and so on.
• A list of scalars is represented as follows:
name_of_the_list
• Vectors in OpenFOAM® are represented as a list with three components, e.g.,
(
(1.0 0.0 0.0) 0
1
2
• A second order tensor in OpenFOAM® is represented as a list with nine );
components, e.g.,
• A list of vectors is represented as follows:
(
name_of_the_list
1.0 0.0 0.0
(
0.0 1.0 0.0
(0 0 0)
0.0 0.0 1.0
(1 0 0)
)
(2 0 0)
);
148 149
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
Dictionary files general features Dictionary files general features

• Scalars, vectors, lists and dictionaries. • Scalars, vectors, lists and dictionaries.
• List entries are contained within parentheses ( ). A list can contain scalars, • OpenFOAM® uses dictionaries to specify data in an input file (dictionary file).
vectors, tensors, words, and so on. • A dictionary in OpenFOAM® can contain multiple data entries and at the same
• A list of words is represented as follows time dictionaries can contain sub-dictionaries.
name_of_the_list • To specify a dictionary entry, the name is follow by the keyword entries in curly
( braces:
“word1”
“word2” solvers Dictionary solvers
“word3” {
); p Sub-dictionary p
{
solver PCG;
preconditioner DIC;
tolerance 1e-06;
relTol 0;
}
}
150 151

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

• Macro expansion. • Macro expansion.


• We first declare a variable (x = 10) and then we use it through the $ macro • You can use macro expansion to duplicate and access variables in
substitution ($x). dictionaries

vectorField (20 0 0); //Declare variable p // Declare/create the dictionary p


{
internalField uniform $vectorField; //Use declared variable solver PCG;
preconditioner DIC;
tolerance 1e-06;
relTol 0;
scalarField 101328; //Declare variable }
type fixedValue;
value uniform $scalarField; //Use declared variable
$p; //To create a copy of the dictionary p
$p.solver; //To access the variable solver in the dictionary p

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

• Inline calculations. • Instead of writing (the poor man’s way):


• You can use the directive #calc to do inline calculations, the syntax is as follows:
leftWall
{
X = 10.0; //Declare variable type fixedValue;
Y = 3.0; //Declare variable value uniform (0 0 0);
}
Z #calc “$X*$Y – 12.0”; //Do inline calculation. The result is rightWall
//saved in the variable Z {
type fixedValue;
value uniform (0 0 0);
}
• With inline calculations you can access all the mathematical functions available in topWall
{
C++.
type fixedValue;
• Macro expansions and inline calculations are really useful to parametrize dictionaries
value uniform (0 0 0);
and avoid repetitive tasks.
}

154 155

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

• You can write (the lazy way): • 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:
“(left|right|top)Wall”
{
Switches
type fixedValue;
value uniform (0 0 0); false true
}
off on
• You could also try (even lazier): no yes

“.*Wall” n y
{
f t
type fixedValue;
value uniform (0 0 0); none true
}

• You can find all the valid switches in the following file:
• OpenFOAM® understands the syntax of regular expressions (regex or regexp). OpenFOAM-5.x/src/OpenFOAM/primitives/bools/Switch/Switch.C
156 157
A deeper view to my first OpenFOAM® case setup A deeper view to my first OpenFOAM® case setup
Solvers and utilities help Solvers and utilities help
• To get more information about the boundary conditions and post-processing utilities available in OpenFOAM®,
• If you need help about a solver or utility, you can use the option –help. For please read the Doxygen documentation. Just look for the Using OpenFOAM section at the bottom of the
page.
instance:
• If you did not compile the Doxygen documentation, you can access the information online,
http://cpp.openfoam.org/v5/

• $> 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.

158 159

Roadmap 3D Dam break – Free surface flow

Dam break free surface flow


1. OpenFOAM® brief overview
Physical and numerical side of the
2. OpenFOAM® directory organization Box with open top problem:
Gravity • In this case we are going to use the volume of
3. Directory structure of an application/utility fluid (VOF) method.

4. Applications/utilities in OpenFOAM® • This method solves the incompressible Navier-


Stokes equations plus an additional equation to
track the phases (free surface location).
5. Directory structure of an OpenFOAM® case
• As this is a multiphase case, we need to define
6. Running my first OpenFOAM® case setup blindfold the physical properties for each phase involved
(viscosity, density and surface tension).
7. A deeper view to my first OpenFOAM® case setup • The working fluids are water and air.
• Additionally, we need to define the gravity vector
8. 3D Dam break – Free surface flow Water column and initialize the two flows.

9. Flow past a cylinder – From laminar to turbulent flow • 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.
160 161
3D Dam break – Free surface flow 3D Dam break – Free surface flow

Workflow of the case At the end of the day, you should get something like this
blockMesh
+
snappyHexMesh

setFields

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

sampling paraview

162 163

3D Dam break – Free surface flow 3D Dam break – Free surface flow

VOF Fraction (Free surface tracking) – Very fine mesh


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

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

$PTOFC/101OF/3d_damBreak

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
164 165
3D Dam break – Free surface flow 3D Dam break – Free surface flow

Loading OpenFOAM® environment What are we going to do?


• If you are using our virtual machine or using the lab workstations, you will need to source OpenFOAM® (load
OpenFOAM® environment). • We will use this case to introduce the multiphase solver interFoam.
• interFoam is a solver for 2 incompressible, isothermal immiscible fluids using a VOF
• To source OpenFOAM®, type in the terminal: (volume of fluid) phase-fraction based interface capturing approach
• We will define the physical properties of two phases and we are going to initialize
• $> of5x
these phases.

• To use PyFoam you will need to source it. Type in the terminal:
• 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
• $> anaconda2 or $> anaconda3 now we are going to see things moving.
• We are going to briefly address how to post-process multiphase flows.
• Remember, every time you open a new terminal window you need to source OpenFOAM® and PyFoam.
• We are going to generate the mesh using snappyHexMesh, but for the purpose of this
tutorial we are not going to discuss the dictionaries.
• 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.

166 167

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

• In this directory, we will find the following compulsory dictionary files: • This dictionary file is located in the directory
8
9
FoamFile
{
constant.
10 version 2.0;
11 format ascii;
• For multiphase flows, this dictionary is
• g 12
13
class
location
uniformDimensionedVectorField;
"constant";
compulsory.
14 object g;

• transportProperties 15
17
}

• In this dictionary we define the gravity vector (line


18 dimensions [0 1 -2 0 0 0 0];

• turbulenceProperties 19 value (0 0 -9.81);


19).
• Pay attention to the class type (line 12).

• g contains the definition of the gravity vector.


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

168 169
3D Dam break – Free surface flow 3D Dam break – Free surface flow
The transportProperties dictionary file The turbulenceProperties dictionary file
Primary phase
• In this dictionary file we select what model we would like to use (laminar or
• This dictionary file is located in the directory turbulent).
17
18
phases (water air);
constant.
19
20
water
{
• We first define the name of the phases (line 17). • This dictionary is compulsory.
21 transportModel Newtonian;
22 nu [0 2 -1 0 0 0 0] 1e-06;
In this case we are defining the names water and
23
24 }
rho [1 -3 0 0 0 0 0] 1000;
air. The first entry in this list is the primary phase
• In this case we use a RANS turbulence model (kEpsilon).
25
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. 17 simulationType RAS;
32
33 sigma [1 0 -2 0 0 0 0] 0.07; 18
• The name of the phases is given by the user. 19 RAS
20 {
• In this file we set the kinematic viscosity (nu),
21 RASModel kEpsilon;
density (rho) and transport model 22
(transportModel) of the phases. 23 turbulence on;
24
• We also define the surface tension (sigma).
25 printCoeffs on;
26 }

170 171

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

• In this directory, we will find the dictionary files that contain the boundary and 17
18
dimensions [0 0 0 0 0 0 0];
• This file contains the boundary and initial conditions
initial conditions for all the primitive variables. 19
20
internalField uniform 0; for the non-dimensional scalar field alpha.water
21 boundaryField
• This file is named alpha.water, because the
• As we are solving the incompressible RANS Navier-Stokes equations using 22
23
{
front primary phase is water (we defined the primary
24 {
the VOF method, we will find the following field files: 25
26 }
type zeroGradient; phase in the transportProperties dictionary).
27
28
back
{
• Initially, this field is initialize as 0 in the whole domain
29 type zeroGradient; (line 19). This means that there is no water in the
30 }
• alpha.water (volume fraction of water phase) 31 left domain at time 0. Later, we will initialize the water
32
33
{
type zeroGradient;
column and this file will be overwritten with a non-
• p_rgh (pressure field minus hydrostatic component) 34
35
}
right
uniform field for the internalField.
36 {
• For the front, back, left, right, bottom and
• U (velocity field) 37
38 }
type zeroGradient;
stlSurface patches we are using a zeroGradient
39 bottom
boundary condition (we are just extrapolating the
• k (turbulent kinetic energy field) 40
41
{
type zeroGradient; internal values to the boundary face).
42 }

• epsilon (rate of dissipation of turbulence energy field) 43


44
top
{ • For the top patch we are using an inletOutlet
45 type inletOutlet; boundary condition. This boundary condition avoids
• nut (turbulence viscosity field) 46
47
inletValue
value
uniform 0;
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 wall;
52 } (line 46).
53
54 }

172 173
3D Dam break – Free surface flow 3D Dam break – Free surface flow
The file 0/p_rgh The file 0/U

17 dimensions [1 -1 -2 0 0 0 0]; 17 dimensions [0 -1 -1 0 0 0 0];


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

174 175

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

17 dimensions [0 2 -2 0 0 0 0]; 17 dimensions [0 2 -3 0 0 0 0];


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

176 177
3D Dam break – Free surface flow 3D Dam break – Free surface flow
The file 0/nut The system directory

17
18
dimensions [0 2 -1 0 0 0 0];
• This file contains the boundary and initial conditions
• The system directory consists of the following compulsory dictionary files:
19 internalField uniform 0;
for the dimensional scalar field nut.
20
21 boundaryField • controlDict
22 { • This scalar (turbulent viscosity), is related to the
23 “(front|back|left|right|bottom|stlSurface)”
24
25
{
type nutkWallFunction;
turbulence model. • fvSchemes
26 value $internalField; • This field is initialize as 0 in the whole domain, and
27
28
}
all the boundary patches take the same value • fvSolution
29
30
top
{
($internalField).
31 type calculated;
32 value $internalField;; • For the front, back, left, right, bottom and
33 }
stlSurface patches we are using a
34
35 } nutkWallFunction boundary condition, which applies • controlDict contains general instructions on how to run the case.
a wall function at the walls (refer to the source code
or doxygen documentation to know more about this • fvSchemes contains instructions for the discretization schemes that will be
boundary condition). used for the different terms in the equations.
• For the top patch we are using the calculated
boundary condition, this boundary condition • fvSolution contains instructions on how to solve each discretized linear
computes the value of nut from k and epsilon (refer to
the source code or doxygen documentation to know
equation system.
more about this boundary condition).
• We will deal with turbulence modeling later.

178 179

3D Dam break – Free surface flow 3D Dam break – Free surface flow
The controlDict dictionary The controlDict dictionary
• This case starts from time 0 (startTime), and it will run up to 8
17 application interFoam; seconds (endTime). 55 functions • Let us take a look at the functionObjects definitions.
18 56 {
19 startFrom startTime;
• The initial time step of the simulation is 0.0001 seconds • In lines 60-76 we define the fieldMinMax functionObject
20 60 minmaxdomain
21 startTime 0; (deltaT). 61 { which computes the minimum and maximum values of
22 62 type fieldMinMax;
the field variables (p p_rgh U alpha.water k epsilon).
23
24
stopAt endTime;
• It will write the solution every 0.02 seconds (writeInterval) of 63
64 functionObjectLibs ("libfieldFunctionObjects.so");
25 endTime 8; simulation time (runTime). It will automatically adjust the time 65
26 66 enabled true; //true or false
27 deltaT 0.0001; step (adjustableRunTime), in order to save the solution at the 67
28
29 writeControl adjustableRunTime;
precise write interval. 68
69
mode component;

30 70 writeControl timeStep;
31 writeInterval 0.02; • It will keep all the solution directories (purgeWrite). 71 writeInterval 1;
32 72
33 purgeWrite 0; • It will save the solution in ascii format (writeFormat). 73 log true;
34 74
35 writeFormat ascii; 75 fields (p p_rgh U alpha.water k epsilon);
36 • The write precision is 8 digits (writePrecision). It will only save 76 }
37
38
writePrecision 8; eight digits in the output files. 144 };
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 0.5; 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).
180 181
3D Dam break – Free surface flow 3D Dam break – Free surface flow
The controlDict dictionary The controlDict dictionary

55 functions • Let us take a look at the functionObjects definitions. 55 functions • Let us take a look at the functionObjects definitions.
56 { 56 {
• In lines 81-102 we define the volRegion functionObject • In lines 107-131 we define the probes functionObject
81 water_in_domain 107 probes1
82 { which computes the volume integral (volIntegrate) of the 108 { which sample the selected fields (lines 124-127) at the
83
84
type volRegion;
functionObjectLibs ("libfieldFunctionObjects.so");
field variable alpha.water in all the domain. 109
110
type probes;
functionObjectLibs ("libsampling.so");
selected locations (lines 112-122).
85 enabled true; 111
86 • Basically, we are monitoring the quantity of water in the 112 pobeLocations • This sampling is done on-the-fly. All the information
87
88
enabled true;
domain. 113
114
(
(0.82450002 0 0.021)
sample by this functionObject is saved in the directory
89 //writeControl outputTime; 115 (0.82450002 0 0.061) ./postProcessing/probes1
90 writeControl timeStep; 116 (0.82450002 0 0.101)
91
92
writeInterval 1; 117
118
(0.82450002 0 0.141)
(0.8035 0 0.161)
• As we are sampling starting from time 0, the sampled
93 log true; 119 (0.7635 0 0.161) data will be located in the directory:
94 120 (0.7235 0 0.161)
95
96
regionType all; 121
122 );
(0.6835 0 0.161)
postProcessing/probes1/0
97 operation volIntegrate; 123
98 fields 124 fields • Feel free to open the files located in the directory
99
100
(
alpha.water
125
126
(
p p_rgh
postProcessing/probes1/0 using your favorite text
101 ); 127 ); editor.
102 } 128
129 writeControl timeStep;
144 }; 130 writeInterval 1;
131 }

144 };

Sampling locations
(probeLocations)

182 183

3D Dam break – Free surface flow 3D Dam break – Free surface flow
The controlDict dictionary The fvSchemes dictionary
• In this case, for time discretization (ddtSchemes) we are
55 functions • Let us take a look at the functionObjects definitions. 17 ddtSchemes using the Euler method.
56 { 18 {
• In lines 135-141 we define the yplus functionObject 19 default Euler; • For gradient discretization (gradSchemes) we are using the
135
136
yplus
{ which computes the yplus value.
21
22
} Gauss linear as the default method and slope limiters
137 type yPlus; 23 gradSchemes (cellLimited) for the velocity gradient or grad(U).
138 functionObjectLibs ("libutilityFunctionObjects.so "); • This quantity is related to the turbulence modeling. 24 {
139 enabled true; 25 default Gauss linear; • For the discretization of the convective terms (divSchemes)
140 writeControl outputTime; 26 grad(U) cellLimited Gauss linear 1;
141 } • This functionObject will save the yplus field in the 27 } we are using linearUpwindV interpolation method for the
solution directories with the same saving frequency as the 28 term div(rhoPhi,U).
144 }; 29 divSchemes
solution (line 140). 30 { • For the term div(phi,alpha) we are using vanLeer
31 div(rhoPhi,U) Gauss linearUpwindV grad(U);
• It will also save the minimum, maximum and mean values 32 div(phi,alpha) Gauss vanLeer; interpolation. For the term div(phirb,alpha) we are using
33 div(phirb,alpha) Gauss linear;
of yplus in the directory: 35 div(phi,k) Gauss upwind; linear interpolation. These terms are related to the volume
36 div(phi,epsilon) Gauss upwind; fraction equation.
postProcessing/yplus 37 div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear;
38 } • For the terms div(phi,alpha) and div(phi,alpha) we are
39
40 laplacianSchemes using upwind (these terms are related to the turbulence
41
42
{
default Gauss linear corrected;
modeling).
43
44
}
• For the term div(((rho*nuEff)*dev2(T(grad(U))))) we are
45 interpolationSchemes using linear interpolation (this term is related to the
46 {
47 default linear; turbulence modeling).
48 }
49 • For the discretization of the Laplacian (laplacianSchemes
50
51
snGradSchemes
{
and snGradSchemes) we are using the Gauss linear
52 default corrected; corrected method
53 }
• In overall, this method is second order accurate but a little bit
diffusive. Remember, at the end of the day we want a
184 solution that is second order accurate. 185
3D Dam break – Free surface flow 3D Dam break – Free surface flow
The fvSolution dictionary The fvSolution dictionary

17 solvers • To solve the volume fraction or alpha.water (lines 19-32) we 51 p_rghFinal • In lines 51-56 we setup the solver for p_rghFinal. This
18
19
{
"alpha.water.*"
are using the smoothSolver method. 52
53
{
$p_rgh;
correspond to the last iteration in the loop (we can use a tighter
20 { 54 relTol 0; convergence criteria to get more accuracy without increasing
21 nAlphaCorr 3; • In line 25 we turn on the semi-implicit method MULES. The 55 minIter 1;
the computational cost)
22
23
nAlphaSubCycles 1;
cAlpha 1;
keyword nLimiterIter controls the number of MULES iterations 56
57
}

24 over the limiter. 58 "(U|UFinal)" • In lines 58-72 we setup the solvers for U and UFInal.
25 MULESCorr yes; 59 {
26
27
nLimiterIter 10;
• To have more stability it is possible to increase the number of 60
61
solver
Preconditioner
PBiCGStab;
DILU;
• In lines 74-80 we setup the solvers for the turbulent quantities,
28 solver smoothSolver; loops and corrections used to solve alpha.water (lines 21-22). 62 tolerance 1e-08; namely, k and epsilon.
29 smoother symGaussSeidel; 63 relTol 0;
30
31
tolerance
relTol
1e-8;
0;
• The keyword cAlpha (line 23) controls the sharpness of the 72
73
}

32 } interface (1 is usually fine for most cases). 74 "(k|epsilon).*"


33 75 {
34 “(pcorr|pcorrFinal)”
35 {
• In lines 34-40 we setup the solver for pcorr and pcorrFinal 76
77
solver
Preconditioner
PBiCGStab;
DILU;
36 solver PCG; (pressure correction). 78 tolerance 1e-08;
37 preconditioner DIC; 79 relTol 0;
38 tolerance 1e-8; 80 }
39 relTol 0; • Iin this case pcorr is solved only one time at the beginning of 81 }
40 } the computation. 82
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 }

186 187

3D Dam break – Free surface flow 3D Dam break – Free surface flow
The fvSolution dictionary The system directory

82 • In lines 83-89 we setup the entries related to the pressure- • In the system directory you will find the following optional dictionary files:
83
84
PIMPLE
{
velocity coupling method used (PIMPLE in this case). Setting
85
86
momentumPredictor
nOuterCorrectors
yes;
1;
the keyword nOuterCorrectors to 1 is equivalent to running • decomposeParDict
87 nCorrectors 3; using the PISO method.
• setFieldsDict
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 {
the PIMPLE method. By setting the coefficients to one we are
• decomposeParDict is read by the utility decomposePar. This dictionary
95 ".*" 1;
96
97
}
equations
not under-relaxing.
98
99
{
".*" 1; • The option momentumPredictor (line 85), is recommended for file contains information related to the mesh partitioning. This is used when
100
101 }
}
highly convective flows. running in parallel.
102

• setFieldsDict is read by the utility setFields. This utility set values on


selected cells/faces.

188 189
3D Dam break – Free surface flow 3D Dam break – Free surface flow
The setFieldsDict dictionary The decomposeParDict dictionary
• This dictionary file is located in the directory system. • This dictionary file is located in the directory system.
• In lines 17-20 we set the default value to be 0 in the whole • This dictionary is used to decompose the domain in order to run in parallel.
17 defaultFieldValues domain (no water).
18 ( • The keyword numberOfSubdomains (line 17) is used to set the number of cores we want to use in the
19
20 );
volScalarFieldValue alpha.water 0
• In lines 22-32, we initialize a rectangular region (box) parallel simulation.
21 containing water (alpha.water 1).
22 regions • In this dictionary we also set the decomposition method (line 19).
23 ( • In this case, setFields will look for the dictionary file
24 boxToCell • Most of the times the scotch method is fine.
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. • In this case we set the numberOfSubdomains to 4, therefore we will run in parallel using 4 cores.
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 17 numberOfSubdomains 4;
alpha.water = 0
18
Water 19 method scotch;
alpha.water = 1
20

boxToCell region
190 191

3D Dam break – Free surface flow 3D Dam break – Free surface flow

Running the case Running the case

• Let us first generate the mesh. • Let us run the simulation in parallel using the solver interFoam.
• To generate the mesh will use snappyHexMesh (sHM), do not worry we will talk about • We will talk more about running in parallel tomorrow
sHM tomorrow. • To run the case, type in the terminal:

1. $> foamCleanTutorials 1. $> rm –rf 0


2. $> rm –rf 0 2. $> cp –r 0_org 0
3. $> blockMesh 3. $> setFields
4. $> surfaceFeatureExtract 4. $> paraFoam
5. $> snappyHexMesh -overwrite 5. $> decomposePar
6. $> createPatch -dict system/createPatchDict.0 -overwrite 6. $> mpirun –np 4 interFoam –parallel | tee log.interFoam
7. $> createPatch -dict system/createPatchDict.1 -overwrite 7. $> reconstructPar
8. $> checkMesh 8. $> paraFoam
9. $> paraFoam

192 193
3D Dam break – Free surface flow 3D Dam break – Free surface flow

Running the case • To plot the sampled data using gnuplot you can proceed as follows. To enter to the
gnuplot prompt type in the terminal:
• 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
1. $> gnuplot
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. • Now that we are inside the gnuplot prompt, we can type,
• In step 4 we visualize the initialization using paraFoam. 1. set xlabel 'Time (seconds)'
• In step 5 we use the utility decomposePar to do the domain decomposition needed
to run in parallel. 2. set ylabel 'Water volume integral'

• In step 6 we run the simulation in parallel. Notice that np means number of 3. gnuplot> plot 'postProcessing/water_in_domain/0/volRegion.dat' u 1:2 w l title
processors and the value used should be the same number as the one you set in the 'Water in domain'
dictionary decomposeParDict. 4. set xlabel 'Time (seconds)'
• If you want to run in serial, type in the terminal: interFoam | tee log
5. set ylabel 'Pressure'
• In step 7 we reconstruct the parallel solution. This step is only needed if you are
running in parallel.
6. plot 'SPHERIC_Test2/case.txt' u 1:2 w l title 'Experiment',
• Finally, in step 8 we visualize the solution. 'postProcessing/probes1/0/p' u 1:2 w l title 'Numerical simulation'
7. gnuplot> exit
To exit gnuplot
194 195

3D Dam break – Free surface flow 3D Dam break – Free surface flow
• The output of steps 3 and 6 is the following: 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
alpha.water vs. time p vs. time (at probe 0) 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
196 197
3D Dam break – Free surface flow 3D Dam break – Free surface flow

Post-processing multiphase flows in paraFoam Post-processing multiphase flows in paraFoam


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

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

4. Press apply

3. Select Surface in the


Representation drop-down
menu

2. Select alpha.water or the field you


want to use to plot the iso-surface (it
Air Water has to be a scalar)
alpha.water = 0 alpha.water = 1

1. In the Properties tab select 3. Enter the value 0.5 which


alpha.water in Volume Fields corresponds to the interface Iso-surface representing the interface
between water and air between water and air

Interface
alpha.water = 0.5
198 199

3D Dam break – Free surface flow Roadmap


Post-processing multiphase flows in paraFoam
• To visualize all the cells representing the water fraction, proceed as follows, 1. OpenFOAM® brief overview
5. To animate the solution, press Play in the
VCR Controls
2. OpenFOAM® directory organization
3. Directory structure of an application/utility
1. Select the filter Threshold

4. Applications/utilities in OpenFOAM®
4. Press apply 5. Directory structure of an OpenFOAM® case
6. Running my first OpenFOAM® case setup blindfold
2. Select alpha.water or the field
you want to use to visualize the
7. A deeper view to my first OpenFOAM® case setup
cells (it has to be a scalar)
8. 3D Dam break – Free surface flow
9. Flow past a cylinder – From laminar to turbulent flow
Cells representing the
3. Select the range you want to water location
visualize. To visualize the
water select Minimum 0.5 and
Maximum 1.

200 201
Flow past a cylinder – From laminar to turbulent flow 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


• At this point we all have a rough idea of what is going problem:
on with all these dictionary files. • In this case we are going to solve the flow
around a cylinder. We are going to use
• Unless it is strictly necessary, from now on we will not incompressible and compressible solvers, in
laminar and turbulent regime.
go into details about the dictionaries and files we are • Therefore, the governing equations of the
using. problem are the incompressible/compressible
laminar/turbulent Navier-Stokes equations.
• Also, if you are using the lab computers or our virtual • We are going to work in a 2D domain.

machine, do not forget to load the environment • Depending on the Reynolds number, the flow
can be steady or unsteady.
variables. • This problem has a lot of validation data.
All the dimensions are in meters

202 203

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Workflow of the case Vortex shedding behind a cylinder
blockMesh
Or
fluentMeshToFoam C reeping flow (no s eparation)
S teady flow Re < 5

icoFoam A pair of s table vortices

NOTE: pisoFoam
in the wake
S teady flow
5 < Re < 40 - 46
One single mesh can be used with all
solvers and utilities pimpleFoam
pimpleDyMFoam Laminar vortex s treet
simpleFoam (Von Karman s treet) 40 - 46 < Re < 150 Drag coefficient
functionObjects Uns teady flow
rhoPimpleFoam
interFoam Laminar boundary layer up to 150 < Re < 300
sonicFoam the s eparation point, turbulent Trans ition to turbulence
wake
potentialFoam Uns teady flow 300 < Re < 3 x 10 5
mapFields
Boundary layer trans ition to 5 6
turbulent 3 x 10 < Re < 3 x 10
Uns teady flow

Turbulent vortex s treet, but the


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

Strouhal number
sampling paraview

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

Reference cd – Re = 20 Lrb – Re = 20 cd – Re = 40 Lrb – Re = 40 Reference cd – Re = 100 cl – Re = 100 cd – Re = 200 cl – Re = 200

[1] Tritton (E) 2.22 – 1.48 – [1] Russel and Wang (N) 1.38 ± 0.007 ± 0.322 1.29 ± 0.022 ± 0.50

[2] Cuntanceau and Bouard (E) – 0.73 – 1.89 [2] Calhoun and Wang (N) 1.35 ± 0.014 ± 0.30 1.17 ± 0.058 ± 0.67

[3] Russel and Wang (N) 2.13 0.94 1.60 2.29 [3] Braza et al. (N) 1.386± 0.015 ± 0.25 1.40 ± 0.05 ± 0.75

[4] Calhoun and Wang (N) 2.19 0.91 1.62 2.18 [4] Choi et al. (N) 1.34 ± 0.011 ± 0.315 1.36 ± 0.048 ± 0.64

[5] Ye et al. (N) 2.03 0.92 1.52 2.27 [5] Liu et al. (N) 1.35 ± 0.012 ± 0.339 1.31 ± 0.049 ± 0.69

[6] Fornbern (N) 2.00 0.92 1.50 2.24 [6] Guerrero (N) 1.38 ± 0.012 ± 0.333 1.408 ± 0.048 ± 0.725

[7] Guerrero (N) 2.20 0.92 1.62 2.21 cl = lift coefficient, cd = drag coefficient, Re = Reynolds number

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. [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] 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 [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.
Mechanics, 79:257-272, 1973. [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,
[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. 1986.
[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. [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] 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, [5] C. Liu, X. Zheng, and C. Sung. Preconditioned multigrid methods for unsteady incompressible flows. Journal of Computational Physics, 139:33-57, 1998.
156:209-240, 1999. [6] J. Guerrero. Numerical Simulation of the unsteady aerodynamics of flapping flight. PhD Thesis, University of Genoa, 2009.
[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.
206 207

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
At the end of the day, you should get something like this 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

208 Incompressible flow – Reynolds 200 209


Flow past a cylinder – From laminar to turbulent flow 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.
• We will learn how to convert the mesh from a third party software.
• We will learn how to use setFields to accelerate the convergence.
• Let us run our first case. Go to the directory:
• 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.

$PTOFC/101OF/vortex_shedding • 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.

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
210 211

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case Running the case
• Let us first convert the mesh from a third-party format (Fluent format). • To avoid this problem, type in the terminal,
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c2
1. $> paraFoam -builtin
• In the terminal window type:
• Basically, the problem is related to the names and type of the patches in the file
1. $> foamCleanTutorials
boundary and the boundary conditions (U, p). Notice that OpenFOAM® is telling you
2. $> fluent3DMeshToFoam ../../../meshes_and_geometries/vortex_shedding/ascii.msh what and where is the error.
3. $> checkMesh
Created temporary 'c2.OpenFOAM'
4. $> paraFoam
--> FOAM FATAL IO ERROR:

• In step 2, we convert the mesh from Fluent format to OpenFOAM® format. Have in patch type 'patch' not constraint type 'empty' What
for patch front of field p in file "/home/joegi/my_cases_course/5x/101OF/vortex_shedding/c2/0/p"
Where

mind that the Fluent mesh must be in ascii format.


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

• If we try to open the mesh using paraFoam (step 4), it will crash. Can you tell what is From function Foam::emptyFvPatchField<Type>::emptyFvPatchField(const Foam::fvPatch&, const
Foam::DimensionedField<Type, Foam::volMesh>&, const Foam::dictionary&) [with Type = double]
the problem (read the screen)? in file fields/fvPatchFields/constraint/empty/emptyFvPatchField.C at line 80.

FOAM exiting

212 213
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
• Remember, when converting meshes the name and type of the patches are not The boundary dictionary file
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.
18 7
• This dictionary is located in the
• Let us modify the boundary dictionary file. 19 (
20
21
out
{
constant/polyMesh directory.
• In this case, we would like to setup the following primitive type boundary conditions. 22
23
type
nFaces
patch;
80; • This file is automatically created when converting
24 startFace 18180;
25 } or generating the mesh.
26 sym1
27 {
28 type symmetry; • To get a visual reference of the patches, you can
29
30
inGroups
nFaces
1(symmetry);
100; the mesh with paraFoam/paraview.
31 startFace 18260;
32
33
}
sym2
• The type of the out patch is OK.
34 {
35 type symmetry; • The type of the sym1 patch is OK.
36 inGroups 1(symmetry);
37
38
nFaces
startFace
100;
18360; • The type of the sym2 patch is OK.
39 }
40
41
in
{
• The type of the in patch is OK.
42 type patch;
43 nFaces 80;
44 startFace 18460;
45 }

214 215

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The boundary dictionary file • At this point, check that the name and type of the base type boundary conditions
and primitive type boundary conditions are consistent. If everything is ok, we are
ready to go.
46 cylinder
• The type of the cylinder patch is OK.
47
48
{
type wall; • Do not forget to explore the rest of the dictionary files, namely:
49 inGroups 1(wall);
• The type of the back patch is NOT OK.
50
51
nFaces
startFace
80;
18540; Remember, this is a 2D simulation, therefore the • 0/p (p is defined as relative pressure)
52 }
53 back type should be empty. • 0/U
54 {
55 type patch;
56 nFaces 9200; • The type of the front patch is NOT OK. • constant/transportProperties
57
58 }
startFace 18620;
Remember, this is a 2D simulation, therefore the
59
60
front
{
type should be empty. • system/controlDict
61 type patch;
62 nFaces 9200; • Remember, we assign the primitive type • system/fvSchemes
63 startFace 27820;
boundary conditions (numerical values), in the
• system/fvSolution
64 }
65 )
field files found in the directory 0
• Reminder:
• The diameter of the cylinder is 2.0 m.
• And we are targeting for a Re = 200.

216 217
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case Running the case
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c2 • 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
• In the folder c1 you will find the same setup, but to generate the mesh we use
meshes), therefore is highly recommended to always do it.
blockMesh (the mesh is identical).
• In step 2 we run the simulation and save the log file. Notice that we are sending the
• To run this case, in the terminal window type: job to background.
• In step 3 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
1. $> renumberMesh -overwrite job is running in background, we can launch this utility in the same terminal tab.
2. $> icoFoam | tee log.icofoam • In step 4 we use the gnuplot script scripts0/plot_coeffs to plot the force
$> pyFoamPlotWatcher.py log.icofoam coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
3. monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
You will need to launch this script in a different terminal

$> gnuplot scripts0/plot_coeffs • The force coefficients are computed using functionObjects.
4.
You will need to launch this script in a different terminal • After the simulation is over, we use paraFoam to visualize the results. Remember to
5. $> paraFoam 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).

218 219

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
• At this point try to use the following utilities. In the terminal type: Let us run the same case but using a non-uniform field
• $> postProcess –func vorticity –noZero • In the previous case, it took about 150 seconds to onset the instability.
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 • If you are not interested in the initial transient or if you want to speed-up the
saved solutions, including 0
computation, we can add a perturbation in order to trigger the onset of the instability.
• $> postprocess –func 'grad(U)' –latestTime Let us use setFields to initialize a non-uniform flow.
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. • This case is already setup in the directory
• $> postprocess –func 'grad(p)'
This utility will compute and write the pressure gradient or grad(U) in the whole domain (including at the walls).

• $> postProcess -func 'div(U)' $PTOFC/101OF/vortex_shedding/c3


This utility will compute and write the divergence of the velocity field or grad(U) in the whole domain (including at the
walls). You will need to add the keyword div(U) Gauss linear; in the dictionary fvSchemes.

• $> 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

• $> 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. 220 221
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
• Let us run the same case but using a non-uniform field • 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
The setFieldsDict dictionary • Feel free to use the Fluent mesh or the mesh generated with blockMesh.
• This dictionary file is located in the directory system. • In this case, we will use blockMesh.
17 defaultFieldValues • In lines 17-20 we set the default value of the velocity vector • To run this case, in the terminal window type:
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 1. $> foamCleanTutorials
22 regions
behind the cylinder with a velocity vector equal to (0.98480
23
24
(
boxToCell 0.17364 0) 2. $> blockMesh
25 {
26
27
box (0 -100 -100) (100 100 100);
fieldValues • In this case, setFields will look for the dictionary file U 3. $> rm –rf 0 > /dev/null 2>&1
28 ( and it will overwrite the original values according to the
29
30 );
volVectorFieldValue U (0.98480 0.17364 0)
regions defined in setFieldsDict. 4. $> cp –r 0_org/ 0
31 }
32 );
5. $> setFields
boxToCell region
6. $> renumberMesh -overwrite

U (0.98480 0.17364 0)
7. $> icoFoam | log.icofoam

U (1 0 0)
$> pyFoamPlotWatcher.py log.icofoam
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

222 10. $> paraFoam 223

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case Does field initialization make a difference?
Let us run the same case but using a non-uniform field • A picture is worth a thousand words. No need to tell you yes, even if the solutions are
• In step 2 we generate the mesh using blockMesh. The name and type of the slightly different.
patches are already set in the dictionary blockMeshDict so there is no need to • This bring us to the next subject, for how long should we run the simulation?
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
No field initialization With field initialization
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
224 225
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
For how long should run the simulation? What about the residuals?

• This is the difficult part when dealing with • Residuals are telling you a lot, but they are
unsteady flows. difficult to interpret.
• Usually you run the simulation until the • In this case the fact that the initial residuals
behavior of a quantity of interest does not are increasing after about 10 seconds, does
oscillates or it becomes periodic. not mean that the solution is diverging. This
• In this case we can say that after the 50 is in indication that something is happening
seconds mark the solution becomes (in this case the onset of the instability).
periodic, therefore there is no need to run up • Remember, the residuals should always
to 350 seconds (unless you want to gather a drop to the tolerance criteria set in the
lot of statistics). fvSolution dictionary (final residuals). If
they do not drop to the desired tolerance, we
• We can stop the simulation at 150 seconds
are talking about unconverged time-steps.
(or maybe less), and do the average of the
quantities between 100 and 150 seconds. • Things that are not clear from the residuals:
• For how long should we run the
simulation?
• Is the solution converging to the right
value?

226 227

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
How to compute force coefficients Can we compute basic statistics of the force coefficients using gnuplot?
• Yes we can. Enter the gnuplot prompt and type:
68 functions • To compute the force coefficients we use
69 {
functionObjects.
195
196
forceCoeffs_object
{
• Remember, functionObjects are defined at the end of
1. gnuplot> stats ‘postProcessing/forceCoeffs_object/0/forceCoeffs.dat’ u 3
205 type forceCoeffs; the controlDict dictionary file.
206 functionObjectLibs ("libforces.so"); This will compute the basic statistics of all the rows in the file forceCoeffs.dat (we are sampling column 3 in the input file)
208 patches (cylinder); • In line 195 we give a name to the functionObject.
209
2. gnuplot> stats ‘postProcessing/forceCoeffs_object/0/forceCoeffs.dat’ every ::3000::7000 u 3
210 pName p; • In line 208 we define the patch where we want to
211 Uname U; 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)
212 rhoName rhoInf; compute the forces.
213 rhoInf 1.0;
214 • In lines 212-213 we define the reference density value. 3. gnuplot> plot ‘postProcessing/forceCoeffs_object/0/forceCoeffs.dat’ u 3 w l
215 //// Dump to file This will plot column 3 against the row number (iteration number)
216 log true; • In line 218 we define the center of rotation (for moments).
217
218 CofR (0.0 0 0); • In line 219 we define the lift force axis. 4. gnuplot> exit
219 liftDir (0 1 0); To exit gnuplot
220 dragDir (1 0 0); • In line 220 we define the drag force axis.
221 pitchAxis (0 0 1);
222 magUInf 1.0; • In line 221 we define the axis of rotation for moment
223
224
lRef 1.0;
Aref 2.0;
computation.
225
• In line 223 we give the reference length (for computing
• Remember the force coefficients information is saved in the file forceCoeffs.dat
226 outputControl timeStep;
227 outputInterval 1; the moments)
228 }
• In line 224 we give the reference area (in this case the located in the directory postProcessing/forceCoeffs_object/0
255 };
frontal area).
• The output of this functionObject is saved in the file
forceCoeffs.dat located in the directory
forceCoeffs_object/0/

228 229
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
On the solution accuracy On the solution tolerance and linear solvers

17 ddtSchemes
• At the end of the day we want a solution that is second order 17 solvers
• We define the solution tolerance and linear solvers in the
18 { accurate. 18 { dictionary fvSolution.
20 default backward; 31 p
22
23
}
• We define the discretization schemes (and therefore the 32
33
{
solver GAMG;
• To solve the pressure (p) we are using the GAMG method
24 gradSchemes accuracy) in the dictionary fvSchemes. 34 tolerance 1e-6; with an absolute tolerance of 1e-6 and a relative tolerance
25 { 35 relTol 0;
relTol of 0.01.
31
37 }
default cellLimited leastSquares 1;
• In this case, for time discretization (ddtSchemes) we are 36
37
smoother
nPreSweeps
GaussSeidel;
0;
38 using the backward method. 38 nPostSweeps 2; • The entry pFinal refers to the final correction of the PISO
39 divSchemes 39 cacheAgglomeration on;
loop. It is possible to use a tighter convergence criteria only
40 {
• For gradient discretization (gradSchemes) we are using the 40 agglomerator faceAreaPair;
41 default none; 41 nCellsInCoarsestLevel 100; in the last iteration.
45 div(phi,U) Gauss linearUpwindV default; leastSquares method with slope limiters (cellLimited). 42 mergeLevels 1;
49 } 43 }
• To solve U we are using the solver PBiCG and the DILU
50
• For the discretization of the convective terms (divSchemes) 44
51 laplacianSchemes 45 pFinal
preconditioner, with an absolute tolerance of 1e-8 and a
52 { we are using linearUpwindV interpolation method for the 46 {
59 default Gauss linear limited 1; 47 $p; relative tolerance relTol of 0 (the solver will stop iterating
60 } term div(rho,U). 48 relTol 0;
61 49 } when it meets any of the conditions).
62 interpolationSchemes • For the discretization of the Laplacian (laplacianSchemes 50
63 { 51 U • Solving for the velocity is relative inexpensive, whereas
64 default linear; and snGradSchemes) we are using the Gauss linear 52 {
solving for the pressure is expensive.
66
67
}
limited 1 method 53
54
solver
preconditioner
PBiCG;
DILU;
68 snGradSchemes 55 tolerance 1e-08; • The PISO sub-dictionary contains entries related to the
69 { • This method is second order accurate. 56 relTol 0;
71 default limited 1; 57 } pressure-velocity coupling (in this case the PISO method).
72 } 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 }

230 231

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
On the runtime parameters The output screen
• This is the output screen of the icoFoam solver.

nCorrector 1
17 application icoFoam;
• 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 Time = 350
Courant number
21
22 startTime 0;
0 (startTime). Courant Number mean: 0.11299953 max: 0.87674198
23 DILUPBiCG: Solving for Ux, Initial residual = 0.0037946307, Final residual = 4.8324843e-09, No Iterations 3
24 stopAt endTime; • It will run up to 350 seconds (endTime). 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
26
GAMG: Solving for p, Initial residual = 0.0033723932, Final residual = 5.8494331e-07, No Iterations 8
27 endTime 350; • The time step of the simulation is 0.05 seconds (deltaT). The nNonOrthogonalCorrectors 2
GAMG: Solving for p, Initial residual = 0.0010074964, Final residual = 4.4726195e-07, No Iterations 7
29
33 deltaT 0.05; time step has been chosen in such a way that the Courant 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
34
35 writeControl runTime;
number is less than 1 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
43 time step continuity errors : sum local = 2.0062733e-11, global = 1.2592813e-13, cumulative = -2.8695809e-10
44 writeInterval 1; • It will write the solution every 1 second (writeInterval) of ExecutionTime = 746.46 s ClockTime = 807 s
45
52 purgeWrite 0;
simulation time (runTime). faceSource inMassFlow output:
53 sum(in) of phi = -40 Mass flow at in patch
• It will keep all the solution directories (purgeWrite).
nCorrector 2

54 writeFormat ascii;
55 faceSource outMassFlow output:
sum(out) of phi = 40 Mass flow at out patch
56
57
writePrecision 8;
• It will save the solution in ascii format (writeFormat).
fieldAverage fieldAverage output:
58 writeCompression off;
59 • The write precision is 8 digits (writePrecision). Calculating averages Computing averages of fields
60 timeFormat general; Writing average fields nCorrectors 2
61 • And as the option runTimeModifiable is on, we can modify
62 timePrecision 6; forceCoeffs forceCoeffs_object output:
63 all these entries while we are running the simulation. Cm = 0.0043956828
64 runTimeModifiable true; 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)

232 233
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Let us run the same case but this time using a potential solver Running the case
• In this case we are going to use the potential solver potentialFoam (remember potential Let us run the same case but this time using a potential solver
solvers are inviscid, irrotational and incompressible)
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c4
• 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. • Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this
case we will use blockMesh.
• A good initial condition will accelerate and improve the convergence rate.
• This case is already setup in the directory
• To run this case, in the terminal window type:

$PTOFC/101OF/vortex_shedding/c4 1. $> foamCleanTutorials


2. $> blockMesh
• Do not forget to explore the dictionary files. 3. $> rm –rf 0
• The following dictionaries are different 4. $> cp –r 0_org 0
• system/fvSchemes
5. $> potentialFoam –noFunctionObjects –initialiseUBCs –writep -writePhi
• system/fvSolution
6. $> paraFoam

Try to spot the differences.

234 235

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case Potential solution
Let us run the same case but this time using a potential solver • Using a potential solution as initial conditions is much better than using a uniform
• In step 2 we generate the mesh using blockMesh. The name and type of the flow. It will speed up the solution and it will give you more stability.
patches are already set in the dictionary blockMeshDict so there is no need to • Finding a solution using the potential solver is inexpensive.
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.
Velocity field Pressure field

236 237
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The output screen Let us map a solution from a coarse mesh to a finer mesh
• This is the output screen of the potentialFoam solver. • It is also possible to map the solution from a coarse mesh to a finer mesh (and all the
• The output of this solver is also a good indication of the sensitivity of the mesh quality way around).
to gradients computation. If you see that the number of iterations are dropping • For instance, you can compute a full Navier Stokes solution in a coarse mesh (fast
iteration after iteration, it means that the mesh is fine. solution), and then map it to a finer mesh.
• If the number of iterations remain stalled, it means that the mesh is sensitive to • Let us map the solution from the potential solver to a finer mesh (if you want you can
gradients, so should use non-orthogonal correction. map the solution obtained using icoFoam). To do this we will use the utility
• In this case we have a good mesh. mapFields.
• This case is already setup in the directory
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
DICPCG: Solving for Phi, Initial residual
=
=
1.8251249e-06, Final residual = 8.8483568e-07, No Iterations 1
1.1220074e-06, Final residual = 5.6696809e-07, No Iterations 1
$PTOFC/101OF/vortex_shedding/c6
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

238 239

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case Running the case
Let us map a solution from a coarse mesh to a finer mesh 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 • In step 2 we generate a finer mesh using blockMesh. The name and type of the
• To generate the mesh, use blockMesh (remember this mesh is finer). patches are already set in the dictionary blockMeshDict so there is no need to
modify the boundary file.
• To run this case, in the terminal window type:
• 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.
1. $> foamCleanTutorials
• In step 5 we use the utility mapFields with the following options:
2. $> blockMesh
• We copy the solution from the directory ../c4
3. $> rm –rf 0
• The options –consistent is used when the domains and BCs are the same.
4. $> cp –r 0_org 0
• The option –noFunctionObjects is used to avoid conflicts with the
5. $> mapfields ../c4 –consistent –noFunctionObjects –mapMethod cellPointInterpolate -sourceTime 0 functionObjects.
6. $> paraFoam • The option –mapMethod cellPointInterpolate defines the interpolation
method.
• The option -sourceTime 0 defines the time from which we want to interpolate
the solution.

240 241
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The meshes and the mapped fields The output screen
• This is the output screen of the mapFields utility.
Coarse mesh Fine mesh
• 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: ".." "c4" Source case


Target: "/home/joegi/my_cases_course/5x/101OF/vortex_shedding" "c6" Target case
Mapping method: cellPointInterpolate Interpolation method
mapFields
Create databases as time

Source time: 0 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

242 243

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Setting a turbulent case • The following dictionaries remain unchanged
• So far we have used laminar incompressible solvers. • system/blockMeshDict
• Let us do a turbulent simulation. • constant/polyMesh/boundary
• When doing turbulent simulations, we need to choose the turbulence model, define • 0/p
the boundary and initial conditions for the turbulent quantities, and modify the
fvSchemes and fvSolution dictionaries to take account for the new variables we • 0/U
are solving (the transported turbulent quantities).
• This case is already setup in the directory • The following dictionaries need to be adapted for the turbulence case
• constant/transportProperties
$PTOFC/101OF/vortex_shedding/c14
• system/controlDict
• system/fvSchemes
• system/fvSolution

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


• constant/turbulenceProperties
244 245
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The transportProperties dictionary file The turbulenceProperties dictionary file
• This dictionary file is located in the directory constant. • This dictionary file is located in the directory constant.

• In this file we set the transport model and the kinematic viscosity (nu). • 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

16 transportModel Newtonian; 17 simulationType RAS; RANS type simulation


17 18
19 nu nu [ 0 2 -1 0 0 0 0 ] 0.0002; 19 RAS RANS sub-dictionary
20 {
21 RASModel kOmegaSST; RANS model to use
22
23 turbulence on; Turn on/off turbulence. Runtime modifiable
24
• Reminder: 25 printCoeffs on; Print coefficients at the beginning
26 }
• The diameter of the cylinder is 2.0 m.
• And we are targeting for a Re = 10000.

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

246 247

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

17 application pimpleFoam;
• This case will start from the last saved solution (startFrom). If there is • In this case, for time discretization (ddtSchemes) we are using the
18 no solution, the case will start from time 0 (startTime). 17 ddtSchemes blended CrankNicolson method. The blending coefficient goes from 0
18 {
20 startFrom latestTime;
21 default CrankNicolson 0.5; to 1, where 0 is equivalent to the Euler method and 1 is a pure Crank
21 • It will run up to 500 seconds (endTime).
22 startTime 0; 22 } Nicolson.
24 gradSchemes
23 • The initial time step of the simulation is 0.001 seconds (deltaT).
24 stopAt endTime; 25 { • For gradient discretization (gradSchemes) we are using as default
31 default cellLimited leastSquares 1;
25
• It will write the solution every 1 second (writeInterval) of simulation time 36 grad(U) cellLimited Gauss linear 1; option the leastSquares method. For grad(U) we are using Gauss
26 endTime 500;
27 (runTime). 37 } linear with slope limiters (cellLimited). You can define different
39 divSchemes
28 deltaT 0.001;
40 {
methods for every term in the governing equations, for example, you
32 • It will keep all the solution directories (purgeWrite). 41 default none; can define a different method for grad(p).
33 writeControl runTime;
47 div(phi,U) Gauss linearUpwindV grad(U);
41 • It will save the solution in ascii format (writeFormat). 49 div((nuEff*dev2(T(grad(U))))) Gauss linear; • For the discretization of the convective terms (divSchemes) we are
42 writeInterval 1;
51 div(phi,k) Gauss linearUpwind default;
43
• The write precision is 8 digits (writePrecision). 52 div(phi,omega) Gauss linearUpwind default;
using linearUpwindV interpolation method with slope limiters for the
50 purgeWrite 0;
51 63 } term div(phi,U).
52 writeFormat ascii; • And as the option runTimeModifiable is on, we can modify all these 65 laplacianSchemes
53 entries while we are running the simulation. 66 { • For the terms div(phi,k) and div(phi,omega) we are using
74 default Gauss linear limited 1;
54 writePrecision 8;
75 }
linearUpwind interpolation method with no slope limiters. These terms
55 • In line 64 we turn on the option adjustTimeStep. This option will 77 interpolationSchemes are related to the turbulence modeling.
56 writeCompression off;
57 automatically adjust the time step to achieve the maximum desired 78 {
58 timeFormat general; courant number maxCo (line 66). 79 default linear; • For the term div((nuEff*dev2(T(grad(U))))) we are using linear
81 }
59
83 snGradSchemes
interpolation (this term is related to turbulence modeling).
60 timePrecision 6; • We also set a maximum time step maxDeltaT in line 67. 84 {
61
86 default limited 1; • For the discretization of the Laplacian (laplacianSchemes and
62 runTimeModifiable yes; • Remember, the first time step of the simulation is done using the value 87 } snGradSchemes) we are using the Gauss linear limited 1 method.
63
64 adjustTimeStep yes; set in line 28 and then it is automatically scaled to achieve the desired 89 wallDist
65 maximum values (lines 66-67). 90 { • To compute the distance to the wall and normals to the wall, we use the
91 method meshWave;
66 maxCo 0.9;
92 } method meshWave. This only applies when using wall functions
67 maxDeltaT 0.1; • The feature adjustTimeStep is only present in the PIMPLE family (turbulence modeling).
solvers, but it can be added to any solver by modifying the source code.
• This method is second order accurate.

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

17 solvers
• To solve the pressure (p) we are using the GAMG method, with an 17 solvers
• To solve UFinal we are using the solver PBiCGStab with an absolute
18 { absolute tolerance of 1e-6 and a relative tolerance relTol of 0.001. 18 { tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
31 p Notice that we are fixing the number of minimum iterations (minIter). 77 UFinal fixing the number of minimum iterations (minIter).
32 { 78 {
33 solver GAMG; 79 solver PBiCGStab;
34 tolerance 1e-6;
• To solve the final pressure correction (pFinal) we are using the PCG 80 preconditioner DILU;
• To solve omega and omegaFinal we are using the solver PBiCGStab
35 relTol 0.001; method with the DIC preconditioner, with an absolute tolerance of 1e-6 81 tolerance 1e-08; with an absolute tolerance of 1e-8 and a relative tolerance relTol of 0.
36 smoother GaussSeidel; and a relative tolerance relTol of 0. 82 relTol 0; Notice that we are fixing the number of minimum iterations (minIter).
37 nPreSweeps 0; 83 minIter 3;
38 nPostSweeps 2; 84 }
39 cacheAgglomeration on;
• Notice that we can use different methods between p and pFinal. In this 85
• To solve k we are using the solver PBiCGStab with an absolute
40 agglomerator faceAreaPair; case we are using a tighter tolerance for the last iteration. 86 omega tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
41 nCellsInCoarsestLevel 100; 87 { fixing the number of minimum iterations (minIter).
42 mergeLevels 1; • We are also fixing the number of minimum iterations (minIter). This 88 solver PBiCGStab;
44 minIter 2; 89 preconditioner DILU;
45 }
entry is optional. 90 tolerance 1e-08;
46 91 relTol 0;
47 pFinal • To solve U we are using the solver PBiCGStab with the DILU 92 minIter 3;
48 { preconditioner, an absolute tolerance of 1e-8 and a relative tolerance 93 }
49 solver PCG; 94
50 preconditioner DIC;
relTol of 0. Notice that we are fixing the number of minimum iterations 95 omegaFinal
51 tolerance 1e-06; (minIter). 96 {
52 relTol 0; 97 solver PBiCGStab;
54 minIter 3; 98 preconditioner DILU;
55 } 99 tolerance 1e-08;
56 100 relTol 0;
57 U 101 minIter 3;
58 { 102 }
59 solver PBiCGStab; 103
60 preconditioner DILU; 104 k
61 tolerance 1e-08; 105 {
62 relTol 0; 106 solver PBiCGStab;
63 minIter 3; 107 preconditioner DILU;
64 } 108 tolerance 1e-08;
109 relTol 0;
110 minIter 3;
111 }

250 251

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary • The following dictionaries are new
• 0/k
113 kFinal
• To solve kFinal we are using the solver PBiCGStab with an absolute
114
115
{
solver PBiCGStab;
tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
fixing the number of minimum iterations (minIter).
• 0/omega
116 preconditioner DILU;
117
118
tolerance
relTol
1e-08;
0;
• In lines 123-133 we setup the entries related to the pressure-velocity • 0/nut
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
} These are the field variables related to the closure equations of the turbulent
• To gain more stability we are using 1 outer correctors
123
124
PIMPLE
{ (nOuterCorrectors), 3 inner correctors or PISO correctors model.
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
• As we are going to use the model we need to define the initial
135
136
relaxationFactors
{
outer corrections (pseudo transient iterations). If you are working in conditions and boundaries conditions.
137 fields PISO mode (only one outer correction or nOuterCorrectors), these
138 { values are ignored.
139
140 }
p 0.3; • To define the IC/BC we will use the free stream values of and
141 equations
142
143
{
U 0.7; • In the following site, you can find a lot information abut choosing initial and
144 k 0.7;
145
146 }
omega 0.7; boundary conditions for the different turbulence models:
147 }

• https://turbmodels.larc.nasa.gov/

252 253
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Turbulence model free-stream boundary conditions The file 0/k
19 internalField uniform 0.00015;
• The initial value for the turbulent kinetic energy can be found as follows 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;
• The initial value for the specific kinetic energy can be found as follows 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 }
• Where is the viscosity ratio and is the turbulence intensity. 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;
• If you are working with external aerodynamics or virtual wind tunnels, you can use the following 41 } • The rest of the patches are constrained.
42 cylinder
reference values for the turbulence intensity and the viscosity ratio. They work most of the 43
44
{
type kqRWallFunction;
• FYI, the inlet velocity is 1 and the turbulence intensity is
times, but it is a good idea to have some experimental data or a better initial estimate. 45 value uniform 0.00015; equal to 1%.
46 }
47 back
48 {
Low Medium High 49 type empty;
50 }
51 front
1.0 % 5.0 % 10.0 % 52 {
53 type empty;
54 }
1 10 100 55 }

254 255

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The file 0/omega The file 0/nut
19 internalField uniform 0.075;
20 19 internalField uniform 0;
21 boundaryField • We are using uniform initial conditions (line 19). 20 • We are using uniform initial conditions (line 19).
22 { 21 boundaryField
23 out • For the in patch we are using a fixedValue boundary 22 { • For the in patch we are using the calculated boundary
24 { 23 out
25 type inletOutlet; condition. 24 { condition (nut is computed from kappa and omega)
26 inletValue uniform 0.075; 25 type calculated;
27
28 }
value uniform 0.075; • For the out patch we are using an inletOutlet boundary 26
27 }
value uniform 0; • For the out patch we are using the calculated
29 sym1 condition (this boundary condition avoids backflow). 28 sym1 boundary condition (nut is computed from kappa and
30 { 29 {
omega)
31
32 }
type symmetryPlane;
• For the cylinder patch (which is base type wall), we 30
31 }
type symmetryPlane;

33 sym2 are using the omegaWallFunction boundary condition. 32 sym2 • For the cylinder patch (which is base type wall), we
34 { 33 {
35 type symmetryPlane; This is a wall function, we are going to talk about this 34 type symmetryPlane; are using the nutkWallFunction boundary condition.
36 } when we deal with turbulence modeling. Remember, we 35
36
}
in
This is a wall function, we are going to talk about this
37 in
38 { can use wall functions only if the patch is of base type 37 { when we deal with turbulence modeling. Remember, we
39 type fixedValue; 38 type calculated;
40 value uniform 0.075;
wall. 39 value uniform 0;
can use wall functions only if the patch is of base type
41 } 40 } wall.
42 cylinder • The rest of the patches are constrained. 41 cylinder
43 { 42 {
• The rest of the patches are constrained.
44
45
type
Cmu
omegaWallFunction;
0.09;
• FYI, the inlet velocity is 1 and the eddy viscosity ratio is 43
44
type
Cmu
nutkWallFunction;
0.09;
46 kappa 0.41; equal to 10. 45 kappa 0.41; • Remember, the turbulent viscosity (nut) is equal to
47 E 9.8; 46 E 9.8;
48 beta1 0.075; 47 value uniform 0;
49 value uniform 0.075; 48 }
50 } 49 back
51 back 50 {
52 { 51 type empty;
53 type empty; 52 }
54 } 53 front
55 front 54 {
56 { 55 type empty;
57 type empty; 56 }
58 } 57 }
59 }
256 257
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case – Setting a turbulent case 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 • In step 3 we use the utility renumberMesh to make the linear system more diagonal
blockMesh. dominant, this will speed-up the linear solvers.
• To run this case, in the terminal window type:
• In step 4 we run the simulation and save the log file. Notice that we are sending the
job to background.
1. $> foamCleanTutorials
• In step 5 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
2. $> blockMesh job is running in background, we can launch this utility in the same terminal tab.
3. $> renumberMesh -overwrite • In step 6 we use the gnuplot script scripts0/plot_coeffs to plot the force
$> pimpleFoam | log coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
4. monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
You will need to launch this script in a different terminal

$> pyFoamPlotWatcher.py log • In step 7 we use the utility postProcess to compute the value of each saved
5. solution (we are going to talk about when we deal with turbulence modeling).
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
258 259

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
pimpleFoam output screen
The output screen
Courant Number mean: 0.088931706 max: 0.90251464 Courant number
deltaT = 0.040145538
Time = 499.97
Time step
Simulation time
• This is the output screen of the yPlus utility.
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
Time = 500.01
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 Reading field U
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 Reading/calculating face flux field phi
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 Transport model
PIMPLE: iteration 2 Outer iteration 2 (nOuterCorrectors) Selecting incompressible transport model Newtonian
DILUPBiCG: Solving for Ux, Initial residual = 0.0013482181, Final residual = 4.1395468e-10, No Iterations 3 Selecting RAS turbulence model kOmegaSST Turbulence model
DILUPBiCG: Solving for Uy, Initial residual = 0.0032433196, Final residual = 3.3969121e-09, No Iterations 3 kOmegaSSTCoeffs Model coefficients
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 alphaK1 0.85;
GAMG: Solving for p, Initial residual = 0.0050231165, Final residual = 3.2656397e-06, No Iterations 8 alphaK2 1;
DICPCG: Solving for p, Initial residual = 0.00031459519, Final residual = 9.4260163e-07, No Iterations 36 pFinal alphaOmega1 0.5;
time step continuity errors : sum local = 5.4344408e-11, global = 4.0060595e-12, cumulative = -9.8443445e-08
alphaOmega2 0.856;
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 gamma1 0.55555556; Patch where we are computing y+
bounding k, min: -3.6865398e-05 max: 0.055400108 average: 0.0015914926 gamma2 0.44;
ExecutionTime = 1689.51 s ClockTime = 1704 s beta1 0.075;
beta2 0.0828;
fieldAverage fieldAverage output:
Calculating averages Message letting you know that kappa and omega residuals betaStar 0.09;
the variable is becoming a1 0.31;
forceCoeffs forceCoeffs_object output: b1 1;
Cm = 0.0023218797 unbounded
c1 10;
Cd = 1.1832452 Minimum, maximum and average values
Cl = -1.3927646 Force coefficients F3 false;
Cl(f) = -0.69406044 }
Cl(r) = -0.6987042
Patch 4 named cylinder y+ : min: 0.94230389 max: 12.696632 average: 7.3497345
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) Writing yPlus to field yPlus Writing the field to the solution directory
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) 260 261
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Using a compressible solver • The following dictionaries remain unchanged
• So far we have only used incompressible solvers.
• Let us use the compressible solver rhoPimpleFoam, which is a • system/blockMeshDict
Transient solver for laminar or turbulent flow of compressible fluids for HVAC and
• constant/polyMesh/boundary
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 • Reminder:
properties of the working fluid and the temperature field (we are also solving the • The diameter of the cylinder is 0.002 m.
energy equation)
• The working fluid is air at 20° Celsius and at a sea level.
• This case is already setup in the directory
• Isothermal flow.
$PTOFC/101OF/vortex_shedding/c24 • And we are targeting for a Re = 200.

262 263

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

• In this directory, we will find the following compulsory dictionary files: • 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;

• thermophysicalProperties 22
23
transport
thermo
const;
hConst;
• In the sub-dictionary thermoType (lines 18-27), we
24 equationOfState perfectGas; define the thermophysical models.
• turbulenceProperties 25
26
specie
energy
specie;
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
• thermophysicalProperties contains the definition of the physical 32
33
{
nMoles 1;
evaluating the specific heat Cp (line 23). In this case Cp
is constant
properties of the working fluid. 34
35 }
molWeight 28.9;

36 thermodynamics • The equationOfState keyword (line 24) concerns to the


• turbulenceProperties contains the definition of the turbulence model to 37
38
{
Cp 1005; equation of state of the working fluid. In this case
39 Hf 0;
use. 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).

264 265
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The thermophysicalProperties dictionary file The turbulenceProperties dictionary file
• In this dictionary file we select what model we would like to use (laminar or
• In the sub-dictionary mixture (lines 29-46), we define the
18 thermoType thermophysical properties of the working fluid.
turbulent).
19 {
20
21
type
mixture
hePsiThermo;
pureMixture;
• In this case, we are defining the properties for air at 20° • This dictionary is compulsory.
22 transport const; Celsius and at a sea level.
23 thermo hConst;
24
25
equationOfState
specie
perfectGas;
specie;
• As we do not want to model turbulence, the dictionary is defined as follows,
26 energy sensibleEnthalpy;
27 }
28
29 mixture
30 {
31 specie
32 {
33 nMoles 1;
34 molWeight 28.9;
35 } 17 simulationType laminar;
36 thermodynamics
37 {
38 Cp 1005;
39 Hf 0;
40 }
41 transport
42 {
43 mu 1.84e-05;
44 Pr 0.713;
45 }
46 }

266 267

Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The 0 directory The file 0/p
• This file contains the boundary and initial conditions
• In this directory, we will find the dictionary files that contain the boundary and 17
18
dimensions [1 -1 -2 0 0 0 0];
for the scalar field pressure (p). We are working
with absolute pressure.
initial conditions for all the primitive variables. 19
20
internalField uniform 101325;

21 boundaryField
• Contrary to incompressible flows where we defined
• As we are solving the compressible laminar Navier-Stokes equations, we will 22
23
{
in relative pressure, this is the absolute pressure.
24 {
find the following field files: 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).
• p (pressure) 32
34
}
cylinder • For the in patch we are using a zeroGradient
35 {
boundary condition.
• T (temperature) 36
37 }
type zeroGradient;

39 sym1 • For the outlet patch we are using a fixedValue


• U (velocity field) 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 }

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

270 271

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

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


18
application icoFoam;
• This case will start from the last saved solution (startFrom). If there is
no solution, the case will start from time 0 (startTime).
19 startFrom startTime;
• controlDict 20
21
//startFrom latestTime; • It will run up to 0.3 seconds (endTime).
22 startTime 0; • The initial time step of the simulation is 0.00001 seconds (deltaT).
• fvSchemes
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
• fvSolution 27
28
endTime 0.3; will adjust the time-step to save the solution at the precise intervals. This
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).
• controlDict contains general instructions on how to run the case. 34
35 purgeWrite 0; • And as the option runTimeModifiable is on, we can modify all these
36
entries while we are running the simulation.
• fvSchemes contains instructions for the discretization schemes that will be
37 writeFormat ascii;
38
39 writePrecision 10; • In line 49 we turn on the option adjustTimeStep. This option will
used for the different terms in the equations. 40
41 writeCompression off;
automatically adjust the time step to achieve the maximum desired
42 courant number (line 50).
• fvSolution contains instructions on how to solve each discretized linear 43
44
timeFormat general;
• We also set a maximum time step in line 51.
45 timePrecision 6;
equation system. 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.

272 273
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary The fvSchemes dictionary

55 functions • As usual, at the bottom of the controlDict dictionary file 17 ddtSchemes • In this case, for time discretization (ddtSchemes) we are
56 {
we define the functionObjects (lines 55-236). 18
19
{
default Euler;
using the Euler method.
178 forceCoeffs_object 20 }
179 { • Of special interest is the functionObject 21 • For gradient discretization (gradSchemes) we are using the
188
189
type forceCoeffs;
functionObjectLibs ("libforces.so");
forceCoeffs_object. 22
23
gradSchemes
{
leastSquares method.
190 patches (cylinder); 29 default cellLimited leastSquares 1;
191 • As we changed the domain dimensions and the inlet 34 } • For the discretization of the convective terms (divSchemes)
192
193
pName p;
Uname U;
velocity we need to update the reference values (lines 204- 35
36 divSchemes
we are using linearUpwind interpolation with no slope limiters
194 //rhoName rhoInf; 206). 37 { for the term div(phi,U).
195 rhoInf 1.205; 38 default none;
196
197 //// Dump to file
• It is also important to update the reference density (line 39
40
div(phi,U) Gauss linearUpwindV default;
• For the terms div(phi,K) (kinetic energy) and div(phi,h)
198 log true; 195). 41 div(phi,K) Gauss linear; (enthalpy) we are using linear interpolation method with no
199 42 div(phi,h) Gauss linear;
200 CofR (0.0 0 0); 43 slope limiters.
201 liftDir (0 1 0); 44 div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear;
202 dragDir (1 0 0); 45 } • For the term div(((rho*nuEff)*dev2(T(grad(U))))) we are
203 pitchAxis (0 0 1); 46
204 magUInf 1.5; 47 laplacianSchemes using linear interpolation (this term is related to the turbulence
205
206
lRef 0.001;
Aref 0.000002;
48
49
{
default Gauss linear limited 1;
modeling).
207 50 }
208 outputControl timeStep; 51 • For the discretization of the Laplacian (laplacianSchemes
209
210
outputInterval
}
1; 52
53
interpolationSchemes
{
and snGradSchemes) we are using the Gauss linear limited
54 default linear; 1 method.
235 55 }
56
236 };
57 snGradSchemes
• This method is second order accurate.
58 {
59 default limited 1;
60 }

274 275

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

17 solvers • To solve the pressure (p) we are using the PCG method with 88 • The PIMPLE sub-dictionary contains entries related to the
18
20
{
p
an absolute tolerance of 1e-6 and a relative tolerance relTol 89
90
PIMPLE
{
pressure-velocity coupling (in this case the PIMPLE method).
21 { of 0.01. 91 momentumPredictor yes;
22 solver PCG; 92 nOuterCorrectors 1; • Setting the keyword nOuterCorrectors to 1 is equivalent to
23
24
preconditioner
tolerance
DIC;
1e-06;
• The entry pFinal refers to the final correction of the PISO 93
94
nCorrectors 2;
nNonOrthogonalCorrectors 1;
running using the PISO method.
25 relTol 0.01; loop. Notice that we are using macro expansion ($p) to copy 95 rhoMin 0.5;
26 minIter 2; 96 rhoMax 2.0; • Hereafter we are doing 2 PISO correctors (nCorrectors) and
the entries from the sub-dictionary p.
27
46
}
pFinal
97 }
1 non-orthogonal corrections (nNonOrthogonalCorrectors).
47 { • To solve U and UFinal (U.*) we are using the solver
48 $p; • In lines 95-96 we set the minimum and maximum physical
PBiCGStab with an absolute tolerance of 1e-8 and a relative
49 relTol 0;
values of rho (density).
50
51 }
minIter 2;
tolerance relTol of 0.
53 "U.*" • If we increase the number of nCorrectors and
54 { • To solve hFinal (enthalpy) we are using the solver
nNonOrthogonalCorrectors we gain more stability but at a
55 solver PBiCGStab;
PBiCGStab with an absolute tolerance of 1e-8 and a relative
56 preconditioner DILU; higher computational cost.
57 tolerance 1e-08; tolerance relTol of 0.
58 relTol 0;
• The choice of the number of corrections is driven by the
59 minIter 2;
• To solve rho and rhoFinal (rho.*) we are using the diagonal
60 } quality of the mesh and the physics involve.
74 hFinal solver (remember rho is found from the equation of state, so
75 {
76 solver PBiCGStab; this is a back-substitution). • You need to do at least one PISO loop (nCorrectors).
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 }

276 277
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
Running the case – Using a compressible solver Running the case
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c24
Using a compressible solver
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this case we will use • In step 3 we scale the mesh.
blockMesh.
• In step 4 we use the utility renumberMesh to make the linear system more diagonal
• To run this case, in the terminal window type:
dominant, this will speed-up the linear solvers.
1. $> foamCleanTutorials • In step 5 we run the simulation and save the log file. Notice that we are sending the
$> blockMesh job to background.
2.
• In step 6 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
3. $> transformPoints –scale ‘(0.001 0.001 0.001)’
job is running in background, we can launch this utility in the same terminal tab.
4. $> renumberMesh -overwrite • In step 7 we use the gnuplot script scripts0/plot_coeffs to plot the force
5. $> rhoPimpleFoam | tee log coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
$> pyFoamPlotWatcher.py log monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
6. • In step 8 we use the utility MachNo to compute the Mach number.
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
278 279

Flow past a cylinder – From laminar to turbulent flow 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

• In the directory:
PIMPLE: iteration 1 (rho)
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

$PTOFC/101OF/vortex_shedding
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 You will find 28 variations of the cylinder case
involving different solvers and models. Feel free to
Writing average fields

forceCoeffs forceCoeffs_object output:


Cm = -0.001269886395
Cd
Cl
=
=
Cl(f) =
1.419350733
0.6247248606
0.3110925439
Force coefficients
Minimum and
explore all them.
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) 280 281
Flow past a cylinder – From laminar to turbulent flow Flow past a cylinder – From laminar to turbulent flow
• This is what you will find in each directory, • This is what you will find in each directory,
• c1 = blockMesh – icoFoam – Re = 200. • c19 = blockMesh – pimpleFoam – Re = 1000000 – Spalart Allmaras turbulent model with no wall
functions.
• c2 = fluentMeshToFoam – icoFoam – Re = 200.
• c20 = blockMesh – sonicFoam – Mach = 2.0 – Compressible – Laminar.
• c3 = blockMesh – icoFoam – Field initialization – Re = 200.
• c21 = blockMesh – sonicFoam – Mach = 2.0 – Compressible – K-Omega SST turbulent model with wall
• c4 = blockMesh – potentialFoam – Re = 200.
functions.
• c5 = blockMesh – mapFields – icoFoam – original mesh – Re = 200.
• c22 = blockMesh – pimpleFoam – Re = 200 – No turbulent model – Source terms (momentum)
• c6 = blockMesh – mapFields – icoFoam – Finer mesh – Re = 200.
• c23 = blockMesh – pimpleFoam – Re = 200 – No turbulent model – Source terms (scalar transport)
• c7 = blockMesh – pimpleFoam – Re = 200 – No turbulent model.
• c24 = blockMesh – rhoPimpleFoam – Re = 200 – Laminar, isothermal
• c8 = blockMesh – pisoFoam – Re = 200 – No turbulent model.
• c25 = blockMesh – rhoPimpleFoam – Re = 20000 – Turbulent, compressible
• c9 = blockMesh – pisoFoam – Re = 200 – K-Omega SST turbulent model.
• c26 = blockMesh – pimpleDyMFoam – Re = 200 – Laminar, moving cylinder (oscillating).
• c10 = blockMesh – simpleFoam – Re = 200 – No turbulent model.
• c27 = blockMesh – pimpleDyMFoam/pimpleFoam – Re = 200 – Laminar, rotating cylinder using AMI
• c11 = blockMesh – simpleFoam – Re = 40 – No turbulent model. patches.
• c12 = blockMesh – pisoFoam – Re = 40 – No turbulent model. • c28 = blockMesh – interFoam – Laminar, multiphase, free surface.
• c14 = blockMesh – pimpleFoam – Re = 10000 – K-Omega SST turbulent model with wall functions. • c29 = blockMesh – pimpleFoam laminar with source terms and AMR.
• c15 = blockMesh – pimpleFoam – Re = 100000 – K-Omega SST turbulent model with wall functions.
• c16 = blockMesh – simpleFoam – Re = 100000 – K-Omega SST turbulent model with no wall functions.
• c17 = blockMesh – simpleFoam – Re = 100000 – K-Omega SST turbulent model with wall functions.
• c18 = blockMesh – pisoFoam – Re = 100000, LES Smagorinsky turbulent model.
282 283

Roadmap

Module 2
1. CFD simulation workflow
CFD simulation workflow – Solid modeling
2. Solid modeling – Preliminaries
3. Solid modeling using Onshape

284 285
CFD simulation workflow CFD simulation workflow

GEOMETRY

UP TO 80% OF USER TIME

MESH

CASE SETUP UP TO 15% OF USER TIME

POST-PROCESSING UP TO 25% OF USER TIME

• The starting point of every CFD workflow is the geometry.


• Then we proceed to generate the mesh and assign the boundaries surface patches.
• Mesh quality and mesh dimensions depend on the underlying geometry. • The percentages shown are based on personal experience.
• And the quality and convergence rate of the solution highly depend on the mesh. • The percentages do not add to 100% because the overload changes from case to
• So try to do your best when generating the geometry and the mesh. case.
• After we have a valid mesh, we proceed to the case setup and we launch/monitor the simulation. • During this course we are going to address every single step.
• At the end, we do the post-processing (quantitative and qualitative). 286 287

Roadmap 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.
• 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 the solid modeling sessions we are going to show you how to get
started with the geometry generation tools. The rest is on you.
1. CFD simulation workflow
• The best way to learn how to use these tools is by doing.
2. Solid modeling – Preliminaries
• Think about a strategy to create your design, we call this design intent.
3. Solid modeling using Onshape • Should I extrude or revolve the sketch?
• How should I set the dimensions?
• Should I use multiple parts?
• Do I need to parametrize my design?
• We are going to work with design intent during the hands-on sessions.
288 289
Solid modeling – Preliminaries Solid modeling – Preliminaries
Potential geometry issues that can affect mesh quality Potential geometry issues that can affect mesh quality
• The following issues must be fixed in order to create a smooth, clean, watertight solid
model and to prevent meshing issues (bad quality cells or too many cells).
• Missing faces, small faces, misaligned faces and overlapping faces.
• Sliver faces (high aspect-ratio).
• Repeated faces.
• Several surfaces connected to a single surface.
• Cracks and gaps.
• Free faces, edges, nodes.
• Hard edges, small edges, repeated edges, and misaligned edges.
• Sharp angles.
• Surfaces with high curvature.
• In general, when generating the geometry and by using good solid modeling
practices, we should not experience geometry issues. To improve quality, split the single surface
into two surfaces

• Usually, we find these issues when importing or exporting the geometry from/to
different formats.
290 291

Solid modeling – Preliminaries Solid modeling – Preliminaries


Potential geometry issues that can affect mesh quality 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.

Original Geometry

Defeatured Geometry

Sew faces
Align faces
Delete overlapping faces
Connect/disconnect edges
292 293
Solid modeling – Preliminaries Roadmap
A few open-source/free CAD/solid modeling applications
• On-shape: it is a full cloud based 3D CAD system. It runs in a web browser and on any device
with a working web browser. It has the same capabilities of commercial CAD systems. You can
create a free account and start to use it immediately. http://www.onshape.org/
• Salome: it is a history based CAD tool (but not a 100% parametric). It has quite extensive
capabilities for creation and manipulation of solid geometries. Its capabilities mirror those of
commercial CAD systems. http://www.salome-platform.org/
• Autodesk 360 fusion: it is a full desktop 3D CAD system. It runs in windows and Mac. It is free
for student, enthusiasts, hobbyists, and startups. http://www.autodesk.com/products/fusion-
1. CFD simulation workflow
360/overview
2. Solid modeling – Preliminaries
• Free-CAD: it is a history based CAD tool (parametric design). Light CAD software, good for not
very complicated mechanical designs. http://sourceforge.net/apps/mediawiki/free-cad/ 3. Solid modeling using Onshape
• OpenVSP: it is a parametric aircraft geometry tool. It allows users to create a 3D model of an
aircraft defined by common engineering parameters. http://www.openvsp.org/
• Openscad: it is a 3D programming modeling tool. It reads in a script file that describes the
object and renders the 3D model from this script file. http://www.openscad.org/
• DesignSpark mechanical: it is a full CAD/solid modeling software. It is distributed for free.
This particular one will blow your mind, the only drawback is that it only runs in windows.
https://www.rs-online.com/designspark/mechanical-software
294 295

Solid modeling using Onshape Solid modeling using Onshape


• Onshape is a professional CAD/solid modeling application. • Even if you have not used a CAD software before, you will find the GUI easy to use.
• It provides powerful parametric and direct modeling capabilities. • You will notice that there is no save button because everything you do is
automatically saved.
• It is cloud based therefore you do not need to install any software. Help
Versioning, branching, and history menu Toolbar
• Documents are shareable.
• Multiple users can work in the same document at the same time Undo/Redo View cube

(simultaneous editing).
• It runs in any device with a working web browser.
Enter to sketch mode
• It is freely available for educational use.
• To start using onshape register at: https://cad.onshape.com/
Feature list

Parts list

3D area
296 Document tabs 297
Solid modeling using Onshape Solid modeling using Onshape
• Mouse interaction in the 3D area (it can be configure in the preference area). • Parametric modeling and feature based modeling are crucial components in the
design experience.
Mouse interaction in the
3D viewer
• In onshape you will find the following features:

Feature toolbar:
Selection

Rotate Sketch toolbar:

Pan
• Remember, sketches are the core of good 3D designs and parametrization.
• This is all we need to know about onshape.
Zoom
• 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.

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


298 299

Solid modeling using Onshape Solid modeling using Onshape


• Let us create this solid using the dimensions illustrated. • 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.

Note: all the dimensions are in meters


300 301
Solid modeling using Onshape Solid modeling using Onshape
• Enter the document page and crate a new design • In the part studio page, select the top plane and start a new sketch.

Start a new sketch

Create new document

Select this plane

Part studio page

302 303

Solid modeling using Onshape Solid modeling using Onshape


• In the part studio page, select the top plane and start a new sketch. • Using the sketching features, draw the following line.
When you are done sketching
press the checkmark

Select this plane

Right click on the 3D area and select


view normal to sketch plane

In sketch mode: Use the dimensions illustrated to


• Blue geometry is free to move. draw this line
• Black geometry is fully defined.
• Red geometry is over-constrained.
304 305
Solid modeling using Onshape Solid modeling using Onshape
• Select the right plane and start a new sketch. • Use the sweep feature to create a new solid.
• Draw a circle with the center in the origin (the white point).
Select the circle as the Select new solid Select the lines as the
When you are done sketching sweep patch
face to sweep
press the checkmark

Select this plane

Sweep feature

Origin

Use the dimensions illustrated to


draw the circle

306 307

Solid modeling using Onshape Solid modeling using Onshape


• At this point, you should have this solid. • 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

Solid name.
Right click to rename
or view the properties

Sketch these lines using the


dimensions illustrated. Pay attention
to the angle and the offset distance.
308 309
Solid modeling using Onshape Solid modeling using Onshape
• Create a plane normal to a line and passing through a point • Sketch a circle in the newly created plane.

Create new plane

Select point normal,


and select the line and
point as illustrated

New plane

To get better visibility, you To get better visibility, you


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

Use this point to create Sketch this circle in the newly created plane
the new plane

310 311

Solid modeling using Onshape Solid modeling using Onshape


• Using the feature extrude to create a new solid using the previous sketch. • Add this point you should have the following solid.
• Extrude the circle until in intercept the solid.
Add the new solid to the previous part
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.
312 313
Solid modeling using Onshape Solid modeling using Onshape
• If you want to know the mass properties of the solid, select it, and then click on the • To export the design, right click on the part name and select the option export.
mass properties icon. • Choose the desired format. In this case choose STL.
• To get the inertia, you will need to assign a material.

Select the part.


Right click and select the
Right click and select
option export.
assign material.

Mass properties icon

314 315

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.

Module 3
• Experimenting with dimension schemes is one of the best ways to improve your
understanding of design intent.
• Finally, feel free to visit our youtube channel where you will find a few solid modeling
videos:
https://www.youtube.com/channel/UCNNBm3KxVS1rGeCVUU1p61g
Meshing preliminaries – Mesh quality
assessment – Meshing in OpenFOAM®

316 317
Before we begin Before we begin
• OpenFOAM® comes with the following meshing applications:
By the end of this module, you will realize that
• blockMesh
You will use snappyHexMesh to mesh the sphinx
• snappyHexMesh
• foamyHexMesh
• foamyQuadMesh You will use blockMesh to mesh the pyramids

• 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 confortable 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®.

318 319

Roadmap Meshing preliminaries


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

2. What is a good mesh?


3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. blockMesh guided tutorials.
6. Mesh generation using snappyHexMesh.
7. snappyHexMesh guided tutorials.
8. Mesh conversion
9. Geometry and mesh manipulation utilities
www.wolfdynamics.com/wiki/moving/ani1.gif www.wolfdynamics.com/wiki/moving/ani2.gif
320 321
Meshing preliminaries Meshing preliminaries
Mesh generation process Geometry generation - Input geometry
• The geometry must be watertight.
• Generally speaking, when generating the mesh we follow these three
• Remember, the quality of the mesh and hence the quality of the solution greatly depends on the geometry. So
simple steps: always do your best when creating the geometry.
• 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.

322 323

Meshing preliminaries Meshing preliminaries


Mesh generation Definition of boundary surfaces (patches)
• If we are interested in external aerodynamics, we define a physical domain and we mesh the region around • In order to assign boundary conditions, we need to create boundary surfaces (patches) where we are going to
the body. apply the boundary values.
• If we are interested in internal aerodynamics, we simply mesh the internal volume of the geometry. • The boundary surfaces (patches) are created at meshing time.
• To resolve better the flow features, we can add surface and volume refinement. • 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.
• Remember to always check the mesh quality.

inlet outlet

top

left right

airplane

324 bottom 325


Meshing preliminaries Roadmap
What cell type should I use?
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
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.
5. blockMesh guided tutorials.
• Each cell type has its very own properties when it comes to approximate the gradients 6. Mesh generation using snappyHexMesh.
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 7. snappyHexMesh guided tutorials.
conditions.
8. Mesh conversion
• 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 9. Geometry and mesh manipulation utilities
final mesh should be acceptable and your mesh should resolve the physics
326 327

What is a good mesh? What is a good mesh?


• There is no written theory when it comes to mesh generation. • The user can rely on grid dependency studies, but they are time consuming and
• Basically, the whole process depends on user experience and good standard expensive.
practices.
Coarse mesh Medium mesh Fine mesh Extra fine mesh
• A standard rule of thumb is that the elements shape and distribution should be
pleasing to the eye.
Cells ≈ 3 500 000 ≈ 11 000 000 ≈ 36 000 000 ≈ 105 000 000

0.0282 0.0270 0.0268 0.0269

-0.0488 -0.0451 -0.0391 -0.0391

22rd IMR Meshing Maestro Contest Winner


Travis Carrigan, John Chawner and Carolyn Woeber. Pointwise.
http://imr.sandia.gov/22imr/MeshingContest.html Results from AIAA CFD Drag Prediction Workshop

328 329
What is a good mesh? What is a good mesh?
• No single standard benchmark or metric exists that can effectively assess Mesh quality metrics. Mesh orthogonality
the quality of a mesh, but the user can rely on suggested best practices.
• Mesh orthogonality is the angular deviation of the vector S (located at the face center
• Hereafter, we will present the most common mesh quality metrics: f ) from the vector d connecting the two cell centers P and N. In this case is .
• Orthogonality. • Affects the gradient of the face center f.
• Skewness. • It adds numerical diffusion to the solution.
• Aspect Ratio. • It mainly affects the diffusive terms.
• Smoothness.

• After generating the mesh, we measure these quality metrics and we use
them to assess mesh quality.
• Have in mind that there are many more mesh quality metrics out there,
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.

330 331

What is a good mesh? What is a good mesh?


Mesh quality metrics. Mesh skewness Mesh quality metrics. Mesh aspect ratio AR
• Skewness is the deviation of the vector d that connects the two cells P and N, from • Mesh aspect ratio AR is the ratio between the longest side and the shortest
the face center f. side .
• The deviation vector is represented with and is the point where the vector d • Large AR are ok if gradients in the largest direction are small.
intersects the face f . • High AR smear gradients.
• Affects the interpolation of the cell centered quantities to the face center f.
• It adds numerical diffusion and wiggles to the solution.
• It affects the convective and diffusive terms.

332 333
What is a good mesh? What is a good mesh?
Mesh quality metrics. Element type close to the walls - Cell/Flow alignment
Mesh quality metrics. Smoothness
• Smoothness, also known as expansion rate, growth factor or uniformity, defines the • Hexes, prisms, and quadrilaterals can be stretched easily to resolve boundary layers
transition in size between contiguous cells. without losing quality.
• Large transition ratios between cells add diffusion to the solution. • Triangular and tetrahedral meshes have inherently larger truncation error.
• Ideally, the maximum change in mesh spacing should be less than 20%: • Less truncation error when faces aligned with flow direction and gradients.

Flow direction

Steep transition Smooth transition 334 335

What is a good mesh? What is a good mesh?


Striving for quality Striving for quality
• For the same cell count, hexahedral meshes will give more accurate solutions, • The mesh density should be high enough to capture all relevant flow features. In
especially if the grid lines are aligned with the flow. areas where the solution change slowly, you can use larger elements.
• But this does not mean that tetrahedral meshes are not good, by carefully choosing • A good mesh does not rely in the fact that the more cells we use the better the
the numerical scheme you can get the same level of accuracy as in hexahedral solution.
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
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.
Year 336 http://www.sandia.gov/imr/MeshingContest.html 337
What is a good mesh? What is a good mesh?
Striving for quality Striving for quality
• And by the way, you can combine all cell types to get a hybrid mesh. • 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.
• Triangular and tetrahedral meshes have inherently larger truncation error.
• 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. But attention, 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
338 rocket the cell count and increase the computing time. 339

What is a good mesh? What is a good mesh?


Striving for quality
• Use hexahedral meshes whenever is possible, specially if high accuracy in predicting A good mesh might not lead to the ideal solution, but a bad
forces is your goal (drag prediction) or for turbo machinery applications. mesh will always lead to a bad solution.
• For complex flows without dominant flow direction, quad and hex meshes loose their
advantages.
P. Baker – Pointwise
• 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 Who owns the mesh, owns the solution.
give you inaccurate results. H. Jasak – Wikki Ltd.
• Plan your meshing approach.
• 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.
Avoid the GIGO syndrome (Garbage In – Garbage Out).
• So, as long as your results are physically realistic, reliable and accurate; your As I am a really positive guy I prefer to say,
mesh is good. good mesh – good results.
• Know your physics and generate a mesh able to resolve the physics involve, J. G.
without over-doing.

340 341
Roadmap Mesh quality assessment in OpenFOAM®
Mesh quality metrics in OpenFOAM®
1. Meshing preliminaries • In the file primitiveMeshCheck.C located in the directory
$WM_PROJECT_DIR/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/
you will find the quality metrics used in OpenFOAM®. Their maximum (or minimum) values are
2. What is a good mesh? defined as follows:

3. Mesh quality assessment in OpenFOAM®


4. Mesh generation using blockMesh. 36 Foam::scalar Foam::primitiveMesh::closedThreshold_ = 1.0e-6;
37 Foam::scalar Foam::primitiveMesh::aspectThreshold_ = 1000;
5. blockMesh guided tutorials. 38 Foam::scalar Foam::primitiveMesh::nonOrthThreshold_ = 70; // deg
39 Foam::scalar Foam::primitiveMesh::skewThreshold_ = 4;
6. Mesh generation using snappyHexMesh. 40 Foam::scalar Foam::primitiveMesh::planarCosAngle_ = 1.0e-6;

7. snappyHexMesh guided tutorials.


8. Mesh conversion • You will be able to run with mesh quality errors such as high skewness, high aspect
ratio, and high non-orthogonality.
9. Geometry and mesh manipulation utilities • But remember, they will affect the solution accuracy, might give you strange results,
and eventually can made the solver blow-up.
342 343

Mesh quality assessment in OpenFOAM® Mesh quality assessment in OpenFOAM®


Mesh quality metrics in OpenFOAM® Checking the mesh quality in OpenFOAM®
• The default quality metrics in OpenFOAM® seems to be a little bit conservative. • To check the mesh quality and validity, OpenFOAM® comes with the utility
checkMesh.
• In our experience, we have found that you can run with no problem with a non-
orthogonality up to 85 and skewness up to 10. • To use this utility, just type in the terminal checkMesh, and read the screen output.
• In overall, large aspect ratios do not represent a problem. It is just an indication that • checkMesh will look for/check for:
you have very fine meshes (which is the case when you are resolving the boundary • Mesh stats and overall number of cells of each type.
layer).
• Check topology (boundary conditions definitions).
• Of course, you will need to adapt the numerics to deal with this kind of meshes.
• Check geometry and mesh quality (bounding box, cell volumes, skewness,
• We will give you our recipe later when we deal with the numerics. orthogonality, aspect ratio, and so on).
• By the way, the only situation to avoid when assessing mesh quality is non- • If for any reason checkMesh finds errors, it will give you a message and it will tell you
orthogonality close to 90. This is an indication that you have zero-volume cells. 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/

344 345
Mesh quality assessment in OpenFOAM® Mesh quality assessment in OpenFOAM®
Checking the mesh quality in OpenFOAM® Visualizing the failed sets in OpenFOAM®
• Mesh topology and patch topology errors must be repaired.
• You can load the failed sets directly within
• You will be able to run with mesh quality errors such as skewness, aspect ratio, paraFoam.
minimum face area, and non-orthogonality.
• Remember, you will need to create the sets. To
• But remember, they will severely tamper the solution accuracy, might give you strange do so just run the checkMesh utility.
results, and eventually can made the solver blow-up.
• If there are problems in the mesh, checkMesh
• Unfortunately, checkMesh does not repair these errors.
will automatically save the sets in the directory
• You will need to check the geometry for possible errors and generate a new mesh. constant/polyMesh/sets
• You can visualize the failed sets directly in paraFoam . • In paraFoam, simply select the option Include
• Alternatively, you can use the utility foamToVTK to convert the failed sets to VTK Sets and then select the sets you want to
format. visualize.
• This method only works with paraFoam.
• When working with large meshes we prefer to
convert the faulty sets to VTK format using
foamToVTK. Failed sets

346 347

Mesh quality assessment in OpenFOAM® Mesh quality assessment in OpenFOAM®


Visualizing the failed sets in OpenFOAM® Checking mesh quality in OpenFOAM®
• To convert the failed faces/cells/points to VTK format, you can proceed as follows: • Sample checkMesh output,

Mesh stats
• $> foamToVTK -set_type name_of_sets points:
faces:
81812
902132
internal faces: 871012
cells: 443286
faces per cell: 4 Mesh stats
boundary patches: 9
where set_type is the type of sets (faceSet, cellSet, pointSet, surfaceFields) and point zones: 0
name_of_sets is the name of the set in the directory constant/polyMesh/sets face zones:
cell zones:
1
1
(highAspectRatioCells, nonOrthoFaces, wrongOrientedFaces, skewFaces, Overall number of cells of each type:
unusedPoints, and so on). hexahedra: 0
prisms: 0
• At the end, foamToVTK will create a directory named VTK, where you will find the wedges:
pyramids:
0
0 Number of each type of cells
failed faces/cells/points in VTK format. tet wedges:
tetrahedra:
0
443286
polyhedra: 0
• At this point you can use paraview/paraFoam to open the VTK files and visualize
the failed sets. 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
348 349
Mesh quality assessment in OpenFOAM® Mesh quality assessment in OpenFOAM®
Checking mesh quality in OpenFOAM® Visualization of faulty sets in paraFoam
• Sample checkMesh output, • You will find this case ready to use in the directory,
$PTOFC/mesh_quality_manipulation/M1_wingbody
Checking patch topology for multiply connected surfaces...
Patch Faces Points Surface topology • To run the case, just follow the instructions in the README.FIRST files.
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 350 Non orthogonal faces (green spheres) and unused points (yellow spheres) 351

Roadmap Mesh generation using blockMesh

blockMesh
1. Meshing preliminaries • “blockMesh is a multi-block mesh generator.”
• For simple geometries, the mesh generation utility blockMesh can be used.
2. What is a good mesh?
• The mesh is generated from a dictionary file named blockMeshDict
3. Mesh quality assessment in OpenFOAM® located in the system directory.
• The meshing tool generates high quality meshes, it is the tool to use for very
4. Mesh generation using blockMesh. simple geometries. As the complexity of the geometry increases, the effort
5. blockMesh guided tutorials. and time required to setup the dictionary increases a lot.
• Usually the background mesh used with snappyHexMesh consist of a single
6. Mesh generation using snappyHexMesh. rectangular block, therefore blockMesh can be used with no problem.
7. snappyHexMesh guided tutorials. • It is highly recommended to create a template of the dictionary
blockMeshDict that you can change according to the dimensions of your
8. Mesh conversion domain.
9. Geometry and mesh manipulation utilities • You can also use m4 or Python scripting to automate the whole process.

352 353
Mesh generation using blockMesh Mesh generation using blockMesh
blockMesh workflow
blockMesh

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

Roadmap blockMesh guided tutorials

1. Meshing preliminaries • Let us take a close look to a blockMeshDict dictionary.


2. What is a good mesh? • We will use the square cavity case.
3. Mesh quality assessment in OpenFOAM® • You will find this case in the directory:

4. Mesh generation using blockMesh.


$PTOFC/101BLOCKMESH/C1
5. blockMesh guided tutorials.
6. Mesh generation using snappyHexMesh.
7. snappyHexMesh guided tutorials. • From this point on, please follow me.
8. Mesh conversion • We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
9. Geometry and mesh manipulation utilities
unpacked the tutorials.
356 357
blockMesh guided tutorials blockMesh guided tutorials
What are we going to do? The blockMeshDict dictionary.
• We will use this simple case to take a close look at a blockMeshDict dictionary. • The keyword convertToMeters (line 17), is a scaling
17 convertToMeters 1; factor. In this case we do not scale the dimensions.
• We will study all sections in the blockMeshDict dictionary. 18
19 xmin 0;
20 xmax 1; • In lines 19-24 we declare some variables using macro
• We will introduce two features useful for parameterization, namely, macro syntax and
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
inline calculations. 24 zmax 1;
use the variables by adding the symbol $ to the variable
25
30 deltax 0.05; name (lines 47-54).
• You can use this dictionary as a blockMeshDict template that you can change 31 deltay 0.05;
32 deltaz 0.05;
automatically according to the dimensions of your domain and the desired cell 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.
spacing. 35
36
ly #calc "$ymax - $ymin";
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 );

358 359

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.
• In lines 34-40 we are doing inline calculations using the • To do inline calculations using the directive #calc, we
17 convertToMeters 1; directive #calc. 17 convertToMeters 1; proceed as follows (we will use line 35 as example):
18 18
19 xmin 0; 19 xmin 0;
20 xmax 1; • Basically we are programming directly in the dictionary. 20 xmax 1;
21 ymin 0; OpenFOAM® will compile this function as it reads it. 21 ymin 0;
22 ymax 1; 22 ymax 1; ly #calc "$ymax - $ymin";
23 zmin 0; 23 zmin 0;
24 zmax 1; • With inline calculations and codeStream you can access 24 zmax 1;
25
30 deltax 0.05;
many OpenFOAM® functions from the dictionaries. 25
30 deltax 0.05;
31 deltay 0.05; 31 deltay 0.05; • We first give a name to the new variable (ly), we then tell
32 deltaz 0.05; • Inline calculations and codeStream are very convenient 32 deltaz 0.05;
OpenFOAM® that we want to do an inline calculation
33
ways to parameterize dictionaries and program directly 33
34 lx #calc "$xmax - $xmin"; 34 lx #calc "$xmax - $xmin"; (#calc), and then we do the inline calculation ("$ymax-
35 ly #calc "$ymax - $ymin"; on the dictionaries. 35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin"; 36 lz #calc "$zmax – $zmin"; $ymin";). Notice that the operation must be between
37
38 xcells #calc "round($lx/$deltax)";
37
38 xcells #calc "round($lx/$deltax)";
double quotation marks.
39 ycells #calc "round($ly/$deltay)"; 39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)"; 40 zcells #calc "round($lz/$deltaz)";
41 41
44 vertices 44 vertices
45 ( 45 (
46 //BLOCK 0 46 //BLOCK 0
47 ($xmin $ymin $zmin) //0 47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1 48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2 49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3 50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4 51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5 52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6 53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7 54 ($xmin $ymax $zmax) //7
66 ); 66 );

360 361
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The blockMeshDict dictionary.
• In lines lines 34-36, we use inline calculations to • By the way, as this dictionary is designed for blocks with
17 convertToMeters 1; compute the length in each direction. 17 convertToMeters 1; positive vertices coordinates, there is a small catch in the
18 18
19 xmin 0; 19 xmin 0; way we compute the length (lines 34-36) and the number
• Then we compute the number of cells to be used in each
20 xmax 1; 20 xmax 1;
of cells (lines 38-40).
21
22
ymin
ymax
0;
1;
direction (lines 38-40). 21
22
ymin
ymax
0;
1;
23 zmin 0; 23 zmin 0; • What will happen if xmin is negative?
24 zmax 1; • To compute the number of cells we use as cell spacing 24 zmax 1;
25
30 deltax 0.05;
the values declared in lines 30-32. 25
30 deltax 0.05;
• What will happen if xcells is negative?
31 deltay 0.05; 31 deltay 0.05;
32 deltaz 0.05; • By proceeding in this way, we can compute automatically 32 deltaz 0.05; • What will happen if xcells is a float with decimals?
33
the number of cells needed in each direction according to 33
34 lx #calc "$xmax - $xmin"; 34 lx #calc "$xmax - $xmin"; • Can you find a solution to these small problems?
35 ly #calc "$ymax - $ymin"; the desired cell spacing. 35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin"; 36 lz #calc "$zmax – $zmin";
37 37
38 xcells #calc "round($lx/$deltax)"; 38 xcells #calc "round($lx/$deltax)";
39 ycells #calc "round($ly/$deltay)"; 39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)"; 40 zcells #calc "round($lz/$deltaz)";
41 41
44 vertices 44 vertices
45 ( 45 (
46 //BLOCK 0 46 //BLOCK 0
47 ($xmin $ymin $zmin) //0 47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1 48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2 49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3 50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4 51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5 52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6 53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7 54 ($xmin $ymax $zmax) //7
66 ); 66 );

362 363

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.
• In the vertices section (lines 44-66), we define the vertex
• In lines 68-71, we define the block topology, hex means that it is a structured hexahedral block. In this case,
17 convertToMeters 1; coordinates of the geometry.
18 we are generating a rectangular mesh.
19 xmin 0;
• In this case, there are eight vertices defining a 3D block.
20
21
xmax
ymin
1;
0;
• 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
22 ymax 1; • Remember, OpenFOAM® always uses 3D meshes, even hex block is defined by eight vertices, in sequential order. Where the first vertex in the list represents the
23 zmin 0;
24 zmax 1; if the simulation is 2D. For 2D meshes, you only add one origin of the coordinate system (vertex 0 in this case).
25
30 deltax 0.05;
cell in the third dimension. • ($xcells $ycells $zcells) is the number of mesh cells in each direction (X Y Z). Notice that we are using
31 deltay 0.05;
32 deltaz 0.05; • Notice that the vertex numbering starts from 0 (as the macro syntax, and we compute the values using inline calculations.
33
counters in c++). This numbering applies for blocks as
34 lx #calc "$xmax - $xmin"; • simpleGrading (1 1 1) is the grading or mesh stretching in each direction (X Y Z), in this case the mesh is
35 ly #calc "$ymax - $ymin"; well. uniform. We will deal with mesh grading/stretching in the next case.
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 68 blocks
47 ($xmin $ymin $zmin) //0 69 (
48 ($xmax $ymin $zmin) //1 70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
49 ($xmax $ymax $zmin) //2 71 );
50 ($xmin $ymax $zmin) //3 72
51 ($xmin $ymin $zmax) //4 73 edges
52 ($xmax $ymin $zmax) //5 74 (
53 ($xmax $ymax $zmax) //6 75
54 ($xmin $ymax $zmax) //7 76 );
66 );

364 365
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The blockMeshDict dictionary.
• Let us talk about the block ordering hex (0 1 2 3 4 5 6 7), which is extremely important. • Edges, are constructed from the vertices definition.
• hex blocks are defined by eight vertices in sequential order. Where the first vertex in the list represents the • Each edge joining two vertices is assumed to be straight by default.
origin of the coordinate system (vertex 0 in this case).
• The user can specified any edge to be curved by entries in the section edges.
• Starting from this vertex, we construct the block topology. So in this case, the first part of the block is made up
• Possible options are: arc, spline, polyline, BSpline, line.
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). • 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.
• 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. • 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.
• 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 might need to merges faces, we will address this later. • In this case and as we do not specified anything, all edges are assumed to be straight lines.

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

366 367

blockMesh guided tutorials blockMesh guided tutorials


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

368 369
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The blockMeshDict dictionary.
• Have in mind that the vertices need to be neighbors and • In lines 112-119 we define the patch front.
78 boundary it does not matter if the ordering is clockwise or counter 112 front
79 ( 113 { • In lines 120-127 we define the patch back.
80 top clockwise. 114 type wall;
81 { 115 faces
• You can also group many faces into one patch, for
82 type wall; • Remember, faces are defined by a list of 4 vertex 116 (
83 faces 117 (4 5 6 7) example, instead of creating the patches front and back,
84 ( numbers, e.g., (3 7 6 2). 118 );
85 (3 7 6 2) 119 } you can group them into a single patch named
86
87 }
); • In lines 88-95 we define the patch left. 120
121
back
{
backAndFront, as follows,
88 left 122 type wall;
89 { • In lines 96-103 we define the patch right. 123 faces
90 type wall; 124 (
backAndFront
91 faces • In lines 104-11 we define the patch bottom. 125 (0 3 2 1)
92 ( 126 ); {
93 (0 4 7 3) 127 }
94 ); 128 ); type wall;
95 } 129 faces
96 right 130 mergePatchPairs
97 { 131 ( (
98 type wall; 132 (4 5 6 7)
99 faces 133 );
100 ( (0 3 2 1)
101 (2 6 5 1) );
102 );
103 } }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }

370 371

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.
• We can merge blocks in the section mergePatchPairs
112 front (lines 130-133). • To sum up, the blockMeshDict dictionary
113 {
114 type wall;
• The block patches to be merged must be first defined in generates a single block with:
115 faces
116 ( the boundary list, blockMesh then connect the two
117 (4 5 6 7) • X/Y/Z dimensions: 1.0/1.0/1.0
118 ); blocks.
119 }
120 back • In this case, as we have one single block there is no • As the cell spacing in all directions is
121
122
{
type wall; need to merge patches. defined as 0.05, it will use the following
123 faces number of cells in the X, Y and Z directions:
124 (
125 (0 3 2 1) 20 x 20 x 20 cells.
126 );
127 }
128 ); • One single hex block with straight lines.
129
130
131
mergePatchPairs
(
• Six patches of base type wall, namely, left,
132 right, top, bottom, front and back.
133 );

• 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.

372 373
blockMesh guided tutorials blockMesh guided tutorials
The constant/polyMesh/boundary dictionary The constant/polyMesh/boundary dictionary
18
19
6
(
• First at all, this file is automatically generated after you 18
19
6
(
• If you do not define the boundary patches in the dictionary
20 top create the mesh or you convert it from a third party format. 20 top blockMeshDict, they are grouped automatically in a default
21 { 21 {
22 type wall; 22 type wall; group named defaultFaces of type empty.
23 inGroups 1(wall); • In this file, the geometrical information related to the base 23 inGroups 1(wall);
24
25
nFaces
startFace
400;
22800; type patch of each boundary of the domain is specified.
24
25
nFaces
startFace
400;
22800;
• For instance, if you do not assign a base type to the patch
26 } 26 } front, it will be grouped as follows:
27 left 27 left
28 { • The base type boundary condition is the actual surface 28 {
29 type wall; 29 type wall;
30 inGroups 1(wall); patch where we are going to apply a primitive type 30 inGroups 1(wall);
defaultFaces
31
32
nFaces
startFace
400;
23200;
boundary condition (or numerical boundary condition). 31
32
nFaces
startFace
400;
23200; {
33 } 33 } type empty;
34
35
right
{
• The primitive type boundary condition assign a field value 34
35
right
{
inGroups 1(empty);
nFaces 400;
36 type empty; to the surface patch. 36 type empty;
startFace 24800;
37 inGroups 1(wall); 37 inGroups 1(wall);
38 nFaces 400; 38 nFaces 400; }
39 startFace 23600; • You define the numerical type patch (or the value of the 39 startFace 23600;
40 } 40 }
41 bottom boundary condition), in the directory 0 or time directories. 41 bottom
42 { 42 {
43 type wall; 43 type wall; • Remember, you can manually change the name and type.
44 inGroups 1(wall); • The name and base type of the patches was defined in the 44 inGroups 1(wall);
45
46
nFaces
startFace
400;
24000;
dictionary blockMeshDict in the section boundary. 45
46
nFaces
startFace
400;
24000;
47 } 47 }
48 front 48 front
49 { • You can change the name if you do not like it. Do not use 49 {
50
51
type
inGroups
wall;
1(wall);
strange symbols or white spaces. 50
51
type
inGroups
wall;
1(wall);
52 nFaces 400; 52 nFaces 400;
53
54 }
startFace 24400; • You can also change the base type. For instance, you can 53
54 }
startFace 24400;

55 back change the type of the patch top from wall to patch. 55 back
56 { 56 {
57 type empty; 57 type empty;
58 inGroups 1(wall); 58 inGroups 1(wall);
59 nFaces 400; 59 nFaces 400;
60 startFace 24800; 60 startFace 24800;
61 } 61 }
62 ) 374 62 ) 375

blockMesh guided tutorials blockMesh guided tutorials


The constant/polyMesh/boundary dictionary The constant/polyMesh/boundary dictionary
18
19
6
(
Number of surface patches 18
19
6
(
20 top 20 top
21 { 21 {
22 type wall; In the list bellow there must be 6 patches 22 type wall; Name and type of the surface patches
23 inGroups 1(wall); 23 inGroups 1(wall);
24 nFaces 400; definition. 24 nFaces 400;
25 startFace 22800; 25 startFace 22800;
26 } 26 } • The name and base type of the patch is given
27 left 27 left
28 { 28 { by the user.
29 type wall; 29 type wall;
top
30
31
inGroups
nFaces
1(wall);
400;
30
31
inGroups
nFaces
1(wall);
400;
• In this case the name and base type was
32 startFace 23200; 32 startFace 23200; assigned in the dictionary blockMeshDict.
33 } 33 }
34 right 34 right
35 { 35 { • You can change the name if you do not like it.
36
37
type
inGroups
empty;
1(wall); back
36
37
type
inGroups
wall;
1(wall);
Do not use strange symbols or white spaces.
38 nFaces 400; 38 nFaces 400;
39 startFace 23600; 39 startFace 23600; • You can also change the base type. For
40 } 40 }
41 bottom 41 bottom instance, you can change the type of the
42
43
{
type wall;
42
43
{
type wall;
patch top from wall to patch.
44 inGroups 1(wall); 44 inGroups 1(wall);
45 nFaces 400; left right 45 nFaces 400;
46 startFace 24000; 46 startFace 24000;
47 } 47 }
48 front 48 front
49 { 49 {
50 type wall; 50 type wall;
51 inGroups 1(wall); 51 inGroups 1(wall);
52 nFaces 400; front 52 nFaces 400;
53 startFace 24400; 53 startFace 24400;
54 } 54 }
55 back 55 back
56 { 56 {
57 type empty; 57 type wall;
58 inGroups 1(wall); 58 inGroups 1(wall);
59 nFaces 400; bottom 59 nFaces 400;
60 startFace 24800; 60 startFace 24800;
61 } 61 }
62 ) 376 62 ) 377
blockMesh guided tutorials blockMesh guided tutorials
The constant/polyMesh/boundary dictionary The constant/polyMesh/boundary dictionary
18 6 18 6
19 ( 19 (
20 top 20 top
21 { 21 {
22 type wall; inGroups keyword 22 type wall; nFaces and startFace keywords
23 inGroups 1(wall); 23 inGroups 1(wall);
24 nFaces 400; 24 nFaces 400;
25 startFace 22800; 25 startFace 22800;
26 } • This is optional. 26 } • Unless you know what you are doing, you do
27 left 27 left
not need to change this information.
28
29
{
type wall; • You can erase this information safely. 28
29
{
type wall;
30 inGroups 1(wall); 30 inGroups 1(wall); • Basically, this is telling you the starting face
31 nFaces 400; • It is used to group patches during visualization 31 nFaces 400;
32 startFace 23200; 32 startFace 23200; and ending face of the patch.
33 } in ParaView/paraFoam. If you open this mesh 33 }
34 right 34 right
35 { in paraFoam you will see that there are two 35 { • This information is created automatically when
36
37
type
inGroups
wall;
1(wall);
groups, namely: wall and empty. 36
37
type
inGroups
wall;
1(wall);
generating the mesh or converting the mesh.
38 nFaces 400; 38 nFaces 400;
39 startFace 23600; • As usual, you can change the name. 39 startFace 23600;
40 } 40 }
41
42
bottom
{ • If you want to put a surface patch in two 41
42
bottom
{
43
44
type
inGroups
wall;
1(wall);
groups, you can proceed as follows: 43
44
type
inGroups
wall;
1(wall);
45 nFaces 400; 45 nFaces 400;
46 startFace 24000; 2(wall wall1) 46 startFace 24000;
47 } 47 }
48
49
front
{
In this case the surface patch belongs to the 48
49
front
{
50 type wall; group wall (which can have another patch) 50 type wall;
51 inGroups 1(wall); 51 inGroups 1(wall);
52 nFaces 400; and the group wall1 52 nFaces 400;
53 startFace 24400; 53 startFace 24400;
54 } 54 }
55 back 55 back
56 { 56 {
57 type wall; 57 type wall;
58 inGroups 1(wall); 58 inGroups 1(wall);
59 nFaces 400; 59 nFaces 400;
60 startFace 24800; 60 startFace 24800;
61 } 61 }
62 ) 378 62 ) 379

blockMesh guided tutorials blockMesh guided tutorials


Running the case
• Let us take a close look to a blockMeshDict dictionary to
• To generate the mesh, in the terminal window type:
study how to use mesh grading.
1. $> foamCleanTutorials • We will use the square cavity case.
2. $> blockMesh • You will find this case in the directory:
3. $> checkMesh
4. $> paraFoam
$PTOFC/101BLOCKMESH/C2

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

1. $> paraFoam -block • From this point on, please follow me.
• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
• You can run the rest of the cases following the same steps. unpacked the tutorials.
380 381
blockMesh guided tutorials blockMesh guided tutorials
What are we going to do? The blockMeshDict dictionary.
• We will use this case to study how to change mesh grading (growth rate).
No grading
• 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 61 blocks
spacing and growth rate. 62
63
(
hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
88 );

Mesh grading
• To control mesh grading, we use the simpleGrading keyword.
• Setting the values to (1 1 1) means no grading (uniform mesh).
• A value different from 1 will add grading to the edge, that is, it will cluster more cells
towards one extreme of the block.
Mesh with no grading Mesh with grading • Let us take a look at a 2D mesh.

382 383

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.

Unidirectional grading Unidirectional grading


Stretching in the Y direction (edge 0-3) Stretching in the Y direction (edge 0-3)

61 blocks 61 blocks
62 ( 62 (
63 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (0.125 8 1) 63 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (0.125 0.125 1)
88 ); 88 );

Stretching in the X direction (edge 0-1) Stretching in the X direction (edge 0-1)

Unidirectional grading Unidirectional grading


Stretching in the Y direction (edge 0-3) Stretching in the Y direction (edge 0-3)

61 blocks 61 blocks
62 ( 62 (
63 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (8 8 1) 63 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (8 0.125 1)
88 ); 88 );

Stretching in the X direction (edge 0-1) Stretching in the X direction (edge 0-1)

384 385
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The blockMeshDict dictionary.
Multi-grading of a block
Multi-grading of a block 61
62
blocks
( • Let us use multi-grading in the X-direction (lines 70-
64
74).
• Using a single grading to describe mesh 65
66
hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells)
simpleGrading
• First, we split the block into 3 divisions in the X-
grading permits only one-way grading of 67
68
(
// x-direction expansion ratio
direction representing 20% or 0.2 (division 1), 60% or
70 (
the block. BLOCK 0 BLOCK 1 71 (0.2 0.25 8) //Division 1 0.6 (division 2), and 20% or 0.2 (division 3) of the
72 (0.6 0.50 1) //Division 2
block length.
• For example, to mesh the square cavity 73
74 )
(0.2 0.25 0.125) //Division 3

75 • Then, we assign 25% (0.25) of the total cells in the X-


with grading towards all the walls requires 76 // y-direction expansion ratio
direction in divisions 1 and 3, and the remaining 50%
78 (
four blocks, each one with different 79 (0.2 0.25 8) (0.50) in division 2.
80 (0.6 0.5 1)
grading. 81
82 )
(0.2 0.25 0.125) • Finally, we apply a grading of 8 in division 1, a grading
83 of 1 (uniform mesh) in division 2, and a grading of(1/8)
• To reduce complexity and effort we can 84 // z-direction expansion ratio
in division 3.
85 1 //no expansion ratio
use multi-grading to control grading within 86 )

separate divisions of a single block, rather BLOCK 3 BLOCK 2 87


88 );

than have to define several blocks with


one grading per block.

386 387

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.
Multi-grading of a block Multi-grading of a block
61 blocks 61 blocks
62 ( • Let us use multi-grading in the Y-direction (lines 78- 62 ( • Finally, as the mesh is 2D, we do not need to add
64 64
65 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) 82). 65 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) grading in the Z-direction (line 85).
66 simpleGrading 66 simpleGrading
67 ( • First, we split the block into 3 divisions in the Y- 67 (
68 // x-direction expansion ratio 68 // x-direction expansion ratio
70 (
direction representing 20% or 0.2 (division 1), 60% or 70 (
71 (0.2 0.25 8) 0.6 (division 2), and 20% or 0.2 (division 3) of the 71 (0.2 0.25 8)
72 (0.6 0.50 1) 72 (0.6 0.50 1)
73 (0.2 0.25 0.125) block length. 73 (0.2 0.25 0.125)
74 ) 74 )
75 • Then, we assign 25% (0.25) of the total cells in the Y- 75
76
78
// y-direction expansion ratio
(
direction in divisions 1 and 3, and the remaining 50% 76
78
// y-direction expansion ratio
(
79 (0.2 0.25 8) //Division 1 (0.50) in division 2. 79 (0.2 0.25 8)
80 (0.6 0.5 1) //Division 2 80 (0.6 0.5 1)
81 (0.2 0.25 0.125) //Division 3 • Finally, we apply a grading of 8 in division 1, a grading 81 (0.2 0.25 0.125)
82 ) 82 )
83 of 1 (uniform mesh) in division 2, and a grading of(1/8) 83
84
85
// z-direction expansion ratio
1 //no expansion ratio
in division 3. 84
85
// z-direction expansion ratio
1
86 ) 86 )
87 87
88 ); 88 );

388 389
blockMesh guided tutorials blockMesh guided tutorials
What are we going to do?
• Let us take a close look to a blockMeshDict dictionary to • We will use this case to take a close look at a blockMeshDict dictionary.
study how to create multiple blocks. • We will study how to work with multiple blocks.
• We will use the square cavity case. • When working with multiples blocks, we need to deal with the common face between
• You will find this case in the directory: blocks. If we do not connect these blocks, blockMesh will create a boundary patch
and we will need to assign a boundary condition to this patch.
• When we connect the blocks, blockMesh will create an internal face (therefore we
$PTOFC/101BLOCKMESH/C3 do not need to assign a boundary condition to the face).
• There are two ways to connect blocks, using face matching and face merging.
Hereafter we are going to study face merging.

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
390 391

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.
Multiple blocks – Face merging
19 xmin 0; 73 blocks
20 xmax 1; 74 (
21 ymin 0.5; • To do a mesh with multiple blocks we proceed in the 75 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1) //BLOCK 0
22 ymax 1; same as we have done so far. 76 hex (8 9 10 11 12 13 14 15) ($xcells $ycells $zcells) simpleGrading (1 1 1) //BLOCK 1
23 zmin 0; 77 //hex (8 9 10 11 12 13 14 15) (40 $ycells $zcells) simpleGrading (1 1 1)
24 zmax 1; 78 );
25 • When using face merging we need to define all the
26 ymin2 0; vertices that made up each block.
27 ymax2 0.5;
28
29 xcells 20; • In lines 19-27 we use macro syntax to declare the Multiple blocks – Face merging
30
31
ycells 10;
zcells 1;
variables that we will use to define the vertices.
39 • In lines 73-78, we define the blocks.
40 vertices • In lines 29-31 we use macro syntax to define the
41 (
number of cells in each direction. As this is a 2D case • In line 75, (0 1 2 3 4 5 6 7) are the vertices used to define
42 //BLOCK 0
43 ($xmin $ymin $zmin) //0 there is only one cell in the Z-direction. block 0 (the top block).
44 ($xmax $ymin $zmin) //1
45 ($xmax $ymax $zmin) //2
• In lines 40-71 we use macro syntax to define the • Remember, the first vertex in the list represents the origin of
46 ($xmin $ymax $zmin) //3
47 ($xmin $ymin $zmax) //4 vertices that made up each block. the coordinate system (vertex 0 in this case). Starting from
48
49
($xmax
($xmax
$ymin
$ymax
$zmax)
$zmax)
//5
//6
this vertex, we construct the block topology. So in this case,
50 ($xmin $ymax $zmax) //7 the first part of the block is made up by vertices 0 1 2 3 and
51
52 //BLOCK 1 the second part of the block is made up by vertices 4 5 6 7
53 ($xmin $ymin2 $zmin) //8 (notice that we start from vertex 4 which is the projection in
54 ($xmax $ymin2 $zmin) //9
55 ($xmax $ymax2 $zmin) //10 the Z-direction of vertex 0).
56 ($xmin $ymax2 $zmin) //11
57 ($xmin $ymin2 $zmax) //12 • ($xcells $ycells $zcells) is the number of mesh cells in each
58 ($xmax $ymin2 $zmax) //13
59 ($xmax $ymax2 $zmax) //14 direction (X Y Z). Notice that we are using macro syntax.
60 ($xmin $ymax2 $zmax) //15
71 ); • simpleGrading (1 1 1) is the grading or mesh stretching in
each direction (X Y Z), in this case the mesh is uniform.
392 393
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The blockMeshDict dictionary.
Multiple blocks – Face merging
73 blocks 86 boundary
74 ( 87 (
75 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1) //BLOCK 0 88 movingWall • In lines 88-139 we define the boundary patches of the
76 hex (8 9 10 11 12 13 14 15) ($xcells $ycells $zcells) simpleGrading (1 1 1) //BLOCK 1 89 { domain.
77 //hex (8 9 10 11 12 13 14 15) (40 $ycells $zcells) simpleGrading (1 1 1) 90 type wall;
78 ); 91 faces
92 ( • We are defining the external patches.
93 (3 7 6 2)
94 );
95 }
Multiple blocks – Face merging 96 fixedWalls
97 {
98 type wall;
• In line 76, (8 9 10 11 12 13 14 15) are the vertices used to 99 faces
define block 1 (the bottom block). 100 (
101 (0 4 7 3)
102 (2 6 5 1)
• The first vertex in the list represents the origin of the 104 (11 15 12 8)
coordinate system (vertex 8 in this case). Starting from this 105 (10 14 13 9)
106 (8 9 13 12)
vertex, we construct the block topology. So in this case, the 107 );
108 }
first part of the block is made up by vertices 8 9 10 11 and the 131 back
second part of the block is made up by vertices 12 13 14 15 132 {
133 type empty;
(notice that we start from vertex 12 which is the projection in 134 faces
the Z-direction of vertex 8). 135
136
(
(0 3 2 1)
137 (8 11 10 9)
• ($xcells $ycells $zcells) is the number of mesh cells in each 138 );
direction (X Y Z). Notice that we are using macro syntax. 139 }

• simpleGrading (1 1 1) is the grading or mesh stretching in


each direction (X Y Z), in this case the mesh is uniform.

394 395

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.
Multiple blocks – Face merging Multiple blocks – Face merging
141 interface1
142 {
143 type wall; • In lines 141-157 we define the boundary patches • The advantage of using face merging instead of face matching, is that we can use blocks with different
144 faces common to each block. grading and number of cells.
145 (
146 (0 1 5 4)
147 ); • In this case we need to use mergePatchPairs to • If the blocks are different, blockMesh will modify the block that owns the slave patch in order to have a
148 } create an internal face, otherwise OpenFOAM® will conforming mesh.
149
150 interface2 see this patch as an boundary patch.
151 { • The block that owns the master patch remains unchanged.
152
153
type wall;
faces
• To merge patches we need to define them in the
154 ( section boundary of the blockMeshDict dictionary.
155 (11 10 14 15)
156
157 }
);
• In line 162 we merge the patches. The first entry
158 ); corresponds to the master patch and the second entry
159
160 mergePatchPairs is the slave patch.
161 (
162 (interface1 interface2)
163 );

Master Slave

396 397
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The extrudeMeshDict dictionary.
• The utility extrudeMesh will create a 2D mesh by projecting the source patch into the exposed
73 blocks
74 ( patch.
75 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1) //BLOCK 0
76
77
//hex (8 9 10 11 12 13 14 15) ($xcells $ycells $zcells) simpleGrading (1 1 1)
hex (8 9 10 11 12 13 14 15) (40 $ycells $zcells) simpleGrading (1 1 1) //BLOCK 1
• To create the 2D mesh, you will need to use 1 layer (nLayers).
78 );
• It is also recommended to set the extrusion thickness to 1.

Multiple blocks – Face merging 18 constructFrom patch;


19
• To have different blocks, we changed the number of
20 sourceCase “.”
cells in the X-direction of the bottom block (line 77).
21 sourcePatches (back); Name of source patch
• The definition of the block topology remains unchanged, 22
i.e., (8 9 10 11 12 13 14 15). 23 exposedPatchName front; Name of the mirror patch
24
• Also, the grading does not change. If you want you can
27 extrudeModel linearNormal
use a non-uniform grading.
28
Number of layers to use in the linear extrusion.
• Have in mind that the mesh will no longer be 2D 29 nLayers 1; As this is a 2D case we must use 1 layer
because blockMesh will add cells to make the blocks 30
conforming. To get the 2D mesh, you will need to use 31 linearNormalCoeffs
the utility extrudeMesh, which reads the 32 {
extrudeMeshDict dictionary. 33 thickness 1; Thickness of the extrusion.
It is highly recommended to use a value of 1
34 }
• Type in the terminal,
35
• $> extrudeMesh 39 mergeFaces false;
398 399

blockMesh guided tutorials blockMesh guided tutorials


What are we going to do?
• Let us take a close look to a blockMeshDict dictionary to • We will use this case to take a close look at a blockMeshDict dictionary.
study how to create multiple blocks. • We will study how to work with multiple blocks.
• We will use the square cavity case. • When working with multiples blocks, we need to deal with the common face between
• You will find this case in the directory: blocks. If we do not connect these blocks, blockMesh will create a boundary patch
and we will need to assign a boundary condition.
• When we connect the blocks, blockMesh will create an internal face (therefore we
$PTOFC/101BLOCKMESH/C4 do not need to assign a boundary condition to the face).
• There are two ways to connect blocks, using face matching and face merging.
Hereafter we are going to study face matching.

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
400 401
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The blockMeshDict dictionary.
Multiple blocks – Face matching Multiple blocks – Face matching
19 xmin 0; 19 xmin 0;
20 xmax 1; 20 xmax 1;
21 ymin 0.5; • To do a mesh with multiple blocks we proceed in the 21 ymin 0.5; • In lines 40-68 we use macro syntax to define the
22 ymax 1; same way as we have done so far. 22 ymax 1; vertices that made up each block.
23 zmin 0; 23 zmin 0;
24 zmax 1; 24 zmax 1;
25 • When using face matching we do not need to define 25 • In lines 43-50 we define the vertices that made up the
26 ymin2 0; all the vertices that made up each block. 26 ymin2 0; top block.
27 ymax2 0.5; 27 ymax2 0.5;
28 28
29 xcells 20; • For the common face between blocks, we only need to 29 xcells 20; • In lines 53-56 we define the vertices that made up the
30
31
ycells 10;
zcells 1;
define one set of vertices. 30
31
ycells 10;
zcells 1;
bottom block. Notice that we are only defining the new
39 39 vertices (8 9 10 11).
40 vertices • In lines 19-27 we use macro syntax to declare the 40 vertices
41
42
(
//BLOCK 0
variables that we will use to define the vertices. 41
42
(
//BLOCK 0
• The vertices (0 1 4 5), that are common between the
43 ($xmin $ymin $zmin) //0 43 ($xmin $ymin $zmin) //0 block are not redefined.
44 ($xmax $ymin $zmin) //1 • In lines 29-31 we use macro syntax to define the 44 ($xmax $ymin $zmin) //1
45
46
($xmax
($xmin
$ymax
$ymax
$zmin)
$zmin)
//2
//3
number of cells in each direction. As this is a 2D case 45
46
($xmax
($xmin
$ymax
$ymax
$zmin)
$zmin)
//2
//3
47 ($xmin $ymin $zmax) //4 there is only one cell in the Z-direction. 47 ($xmin $ymin $zmax) //4
48 ($xmax $ymin $zmax) //5 48 ($xmax $ymin $zmax) //5
49 ($xmax $ymax $zmax) //6 49 ($xmax $ymax $zmax) //6
50 ($xmin $ymax $zmax) //7 50 ($xmin $ymax $zmax) //7
51 51
52 //BLOCK 1 52 //BLOCK 1
53 ($xmin $ymin2 $zmin) //8 53 ($xmin $ymin2 $zmin) //8
54 ($xmax $ymin2 $zmin) //9 54 ($xmax $ymin2 $zmin) //9
55 ($xmin $ymin2 $zmax) //10 55 ($xmin $ymin2 $zmax) //10
56 ($xmax $ymin2 $zmax) //11 56 ($xmax $ymin2 $zmax) //11
68 ); 68 );

138 mergePatchPairs 138 mergePatchPairs


139 ( 139 (
140 140
141 ); 141 );

402 403

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary.
Multiple blocks – Face matching • Let us take a close look to a blockMeshDict dictionary to
• Have in mind that the blocks need to be identical, that is,
same number of cells and same grading.
study how to create non-straight edges.
• If the blocks are different, blockMesh will not generate • We will use the square cavity case.
the mesh. • You will find this case in the directory:
• You do not need to define the common patches in the
section boundary of the blockMeshDict dictionary.
• Finally, we do not need to define the patches in the
keyword mergePatchPairs as blockMesh will $PTOFC/101BLOCKMESH/C5
automatically merge the common faces.

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
404 405
blockMesh guided tutorials blockMesh guided tutorials
What are we going to do? The blockMeshDict dictionary.
• We will use this case to take a close look at a blockMeshDict dictionary.
• In lines 70-133 we define spline edges.
• We will study how to create non straight edges. Interpolation method
• As we are using face merging, we need to define the splines
Vertices to connect in each common patch.
• Possible options are: arc, spline, polyline, Bspline, line. 70
71
edges
(
107 spline 0 1 • To define a spline we first define the vertices to be connected
• Edges are constructed from the vertices definition. 108
109
(
(0.25 0.4 0) to form an edge and then we give a list of the coordinates of
Interpolation
110 (0.5 0.6 0)
the interpolation points.
• Each edge joining two vertices is assumed to be straight by default. 111
112 )
(0.75 0.4 0) points
113 spline 4 5 • In lines 107-118 we define the splines belonging to block 0.
• The user can specified any edge to be curved by entries in the section edges. 114 (
115 (0.25 0.4 1) • In lines 119-130 we define the splines belonging to block 1.
116 (0.5 0.6 1)
• For example, to define an arc we first define the vertices to be connected to form an 117
118 )
(0.75 0.4 1)

edge and then we give an interpolation point. 119


120
spline 11 10
(
121 (0.25 0.4 0)
• To define a polyline we first define the vertices to be connected to form an edge and 122
123
(0.5 0.6 0)
(0.75 0.4 0)
then we give a list of the coordinates of the interpolation points. 124
125
)
spline 15 14
126 (
• Let us study how to create curved edges using the square cavity case with face 127 (0.25 0.4 1)
128 (0.5 0.6 1)
merging. 129
130 )
(0.75 0.4 1)

133 );

406 407

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary.

• In lines 70-133 we define arc edges.


• Let us take a close look to a blockMeshDict dictionary to
Interpolation method • As we are using face merging, we need to define the arcs in study how to create an O-grid mesh.
each common patch.
• We will use the square cavity case.
• To define an arc we first define the vertices to be connected to
70 edges
Interpolation points
form an edge and then we give an interpolation point. • You will find this case in the directory:
71 (
73 arc 0 1 (0.5 0.3 0) • In lines 73-74 we define the arcs belonging to block 0.
74 arc 4 5 (0.5 0.3 1)
75 arc 11 10 (0.5 0.3 0) • In lines 75-76 we define the arcs belonging to block 1.
76
133 );
arc 15 14 (0.5 0.3 1)
$PTOFC/101BLOCKMESH/C6
Vertices to connect

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
408 409
blockMesh guided tutorials blockMesh guided tutorials
What are we going to do? The blockMeshDict dictionary.
• We will use this case to take a close look at a blockMeshDict dictionary.
17 convertToMeters 0.025; • In this case we use and scaling factor of 0.025 (line 17).
• We will create a 3D pipe using an O-grid topology. 18
19 vertices
• We can also scale the mesh using the mesh utility
20 (
transformPoints.
• To create the O-grid topology we will use five blocks.
21 //block0 vertices
22 (-0.25 0.25 0) //0
23 (-0.707106 0.707106 0) //1
24 (0.707106 0.707106 0) //2 • In lines 19-42 we define the coordinates of all the vertices.
• At a first glance, this seems to be an easy task but it requires some work to layout the 25 (0.25 0.25 0) //3 Remember, we are using face matching.
26 (-0.25 0.25 100) //4
topology. 27 (-0.707106 0.707106 100) //5
• In lines 45-53 we use macro syntax to declare a set of
28 (0.707106 0.707106 100) //6
29 (0.25 0.25 100) //7 variables that will be used later.
• We will use face matching. 30
31 //block1 new vertices
32 (0.25 -0.25 0) //8
33 (0.707106 -0.707106 0) //9
34 (0.25 -0.25 100) //10
35 (0.707106 -0.707106 100) //11
36
37 //block3 new vertices
38 (-0.25 -0.25 0) //12
39 (-0.707106 -0.707106 0) //13
40 (-0.25 -0.25 100) //14
41 (-0.707106 -0.707106 100) //15
42 );
43
44
45 xcells 20;
46 ycells 40;
47 zcells 60;
48
49 xcells1 20;
50 ycells1 20;
51 zcells1 60;
52
53 stretch 0.25;

410 411

blockMesh guided tutorials blockMesh guided tutorials


The blockMeshDict dictionary. The blockMeshDict dictionary.

54
69 edges • In lines 69-86 we define arc edges.
70 (
55 blocks
56 (
71
72
//block0 arc
arc 1 2 (0 1 0)
• In lines 88-129 we define the boundary patches.
57 //block0 73 arc 5 6 (0 1 100)
58
59
hex (0 3 2 1 4 7 6 5)
//block1
($xcells $ycells $zcells) simpleGrading (1 $stretch 1) 74 • In lines 91-102 we define the patch inlet. Notice that this
75 //block1 arc
60 hex (3 8 9 2 7 10 11 6) ($xcells $ycells $zcells) simpleGrading (1 $stretch 1) 76 arc 2 9 (1 0 0) boundary patch has five faces.
61 //block2 77 arc 6 11 (1 0 100)
62 hex (8 12 13 9 10 14 15 11) ($xcells $ycells $zcells) simpleGrading (1 $stretch 1) 78
63 //block3 79 //block2 arc
64 hex (12 0 1 13 14 4 5 15) ($xcells $ycells $zcells) simpleGrading (1 $stretch 1) 80 arc 9 13 (0 -1 0)
65 //block4 81 arc 11 15 (0 -1 100)
66 hex (0 12 8 3 4 14 10 7) ($xcells1 $ycells1 $zcells1) simpleGrading (1 1 1) 82
67 ); 83 //block3 arc
84 arc 1 13 (-1 0 0)
85 arc 5 15 (-1 0 100)
86 );
87
88 boundary
89 (
• In lines 55-67, we define all the blocks that made up the 90
91 inlet
O-grid topology. 92 {
93 type patch;
• Notice that we are creating five blocks. 94
95
faces
(
96 (0 1 2 3)
• We also define the number of cells of each block and 97 (2 3 8 9)
the grading. 98
99
(8 9 13 12)
(13 12 0 1)
100 (0 3 8 12)
• As we are using face matching, the grading and 101 );
number of cells in the common faces need to be the 102
103
}

same.

412 413
blockMesh guided tutorials blockMesh guided tutorials
The blockMeshDict dictionary. The final mesh should looks like this one

104 outlet • In lines 88-129 we define the boundary patches.


105 {
106
107
type patch;
faces
• In lines 104-115 we define the patch outlet. Notice that this
108 ( boundary patch has five faces.
109 (4 5 6 7)
110 (6 7 10 11)
111 (15 11 10 14) • In lines 117-127 we define the patch pipe. Notice that this
112 (15 14 4 5) boundary patch has four faces.
113 (4 7 10 14)
114 );
115 } • In this case we do not use face merging (lines 131-133).
116
117 pipe
118 {
119 type wall;
120 faces
121 (
122 (1 5 6 2)
123 (2 6 11 9)
124 (9 11 15 13)
125 (15 13 5 1)
126 );
127 }
128
129 );
130
131 mergePatchPairs
132 (
133 );

3D pipe O-grid topology (outlet patch)

414 415

Roadmap Mesh generation using snappyHexMesh

snappyHexMesh
1. Meshing preliminaries • “Automatic split hex mesher. Refines and snaps to surface.”
• For complex geometries, the mesh generation utility snappyHexMesh can be used.
2. What is a good mesh? • The snappyHexMesh utility generates 3D meshes containing hexahedra and split-
3. Mesh quality assessment in OpenFOAM® hexahedra from a triangulated surface geometry in Stereolithography (STL) format.
• The mesh is generated from a dictionary file named snappyHexMeshDict located in
4. Mesh generation using blockMesh. the system directory and a triangulated surface geometry file located in the directory
constant/triSurface.
5. blockMesh guided tutorials.
6. Mesh generation using snappyHexMesh.
7. snappyHexMesh guided tutorials.
8. Mesh conversion
9. Geometry and mesh manipulation utilities
416 417
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
snappyHexMesh workflow snappyHexMesh workflow – Background mesh
• To generate a mesh with snappyHexMesh we proceed as follows: • The background or base mesh can be generated using blockMesh or an
external mesher.
• Generation of a background or base mesh.
• Geometry definition.
• The following criteria must be observed when creating the background
mesh:
• Generation of a castellated mesh or cartesian mesh.
• The mesh must consist purely of hexes.
• Generation of a snapped mesh or body fitted mesh.
• The cell aspect ratio should be approximately 1, at least near the
• Addition of layers close to the surfaces or boundary layer meshing.
STL surface.
• Check/enforce mesh quality.
• There must be at least one intersection of a cell edge with the
blockMesh or external mesher STL surface.
blockMesh or external mesher

Background mesh Geometry (STL file)

Background mesh Geometry (STL file)

snappyHexMesh
snappyHexMesh

OpenFOAM mesh OpenFOAM mesh

418 419

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


snappyHexMesh workflow – Geometry (STL file) snappyHexMesh workflow
• The STL geometry can be obtained from any geometry modeling tool. • The meshing utility snappyHexMesh reads the dictionary
• The STL file can be made up of a single surface describing the geometry, or snappyHexMeshDict located in the directory system.
multiple surfaces that describe the geometry. • The castellation, snapping, and boundary layer meshing steps are controlled
• In the case of a STL file with multiple surfaces, we can use local refinement by the dictionary snappyHexMeshDict.
in each individual surface. This gives us more control when generating the • The final mesh should be always located in the directory
mesh. constant/polyMesh
• The STL geometry is always located in the directory
constant/triSurface

blockMesh or external mesher blockMesh or external mesher

Background mesh Geometry (STL file) Background mesh Geometry (STL file)

snappyHexMesh snappyHexMesh

OpenFOAM mesh OpenFOAM mesh

420 421
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
snappyHexMesh workflow 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: • The process of generating a mesh using snappyHexMesh will be described using this figure.
• In 2D each quad is subdivided in 4
quads. • The objective is to mesh a rectangular shaped region (shaded grey in the figure) surrounding an object
• In 3D each hex is subdivided in 8 described by a STL surface (shaded green in the figure).
hexes. • This is an external mesh (e.g. for external aerodynamics). You can also generate an internal mesh (e.g. flow in
a pipe).
422 423

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


snappyHexMesh workflow snappyHexMesh workflow

Step 1. Creating the background hexahedral mesh Step 2. Cell splitting at feature edges
• Before snappyHexMesh is executed the user must create a background mesh of hexahedral cells that fills the entire region as • Cell splitting is performed according to the specification supplied by the user in the castellatedMeshControls sub-dictionary in
shown in the figure. This can be done by using blockMesh or any other mesher. the snappyHexMeshDict dictionary.
• The following criteria must be observed when creating the background mesh: • The splitting process begins with cells being selected according to specified edge features as illustrated in the figure.
• The mesh must consist purely of hexes. • The feature edges can be extracted from the STL geometry file using the utility surfaceFeatureExtract.
• 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.
424 425
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
snappyHexMesh workflow snappyHexMesh workflow

Step 3. Cell splitting at surfaces Step 4. Cell removal


• Following feature edges refinement, cells are selected for splitting in the locality of specified surfaces as illustrated in the figure. • Once the feature edges and surface splitting is complete, a process of cell removal begins.
• The surface refinement (splitting) is performed according to the specification supplied by the user in the • The region in which cells are retained are simply identified by a location point within the region, specified by the locationInMesh
refinementMeshControls in the castellatedMeshControls sub-dictionary in the snappyHexMeshDict dictionary. 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.

426 427

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


snappyHexMesh workflow snappyHexMesh workflow

Step 5. Cell splitting in specified regions Step 6. Snapping to surfaces


• Those cells that lie within one or more specified volume regions can be further split by a region (in the figure, the rectangular • After deleting the cells in the region specified and refining the volume mesh, the points are snapped on the surface to create a
region within the red rectangle). conforming mesh.
• The information related to the refinement of the volume regions is supplied by the user in the refinementRegions block in the • The snapping is controlled by the user supplied information in the snapControls sub-dictionary in snappyHexMeshDict.
castellatedMeshControls sub-dictionary in the snappyHexMeshDict dictionary. • Sometimes, the default snapControls options are not enough and you will need to adjust the values to get a good mesh, so it is
• This is a valid castellated or cartesian mesh that can be used for a simulation. 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.
428 429
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
snappyHexMesh workflow snappyHexMesh in action
www.wolfdynamics.com/wiki/shm/ani.gif

Step 7. Mesh layers


• The mesh output from the snapping stage may be 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.
430 431

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


Let us explore the snappyHexMeshDict dictionary.

• Open the dictionary snappyHexMeshDict with your favorite text editor (we use
• Let us study the snappyHexMesh dictionary in gedit).
details. • The dictionary snappyHexMeshDict consists of five main sections:

• We are going to work with the case we just saw in • geometry


Definition of geometry entities to be used for meshing
action.
• castellatedMeshControls
• You will find this case in the directory:
Definition of feature, surface and volume mesh refinement
• snapControls
Definition of surface mesh snapping and advanced parameters
• addLayersControls
$PTOFC/101SHM/M101_wolf
Definition of boundary layer meshing and advanced parameters
• meshQualityControls
Definition of mesh quality metrics

432 433
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary. Let us explore the snappyHexMeshDict dictionary.

castellatedMesh true; //or false castellatedMesh true; //or false • Have in mind that there are more than 70
snap true; //or false snap true; //or false
addLayers true; //or false addLayers true; //or false parameters to control in
snappyHexMeshDict dictionary.
geometry geometry
{ {
... ... • Adding the fact that there is no native GUI, it
... ... can be quite tricky to control the mesh
} }
generation process.
castellatedMeshControls castellatedMeshControls
{ {
... ... • Nevertheless, snappyHexMesh generates
... ...
} } really good hexa dominant meshes.
snapControls snapControls
{ { • Hereafter, we will only comment on the most
... ...
... ...
important parameters.
} }
• The snappyHexMesh dictionary is made up of five sections, namely:
addLayersControls geometry, castellatedMeshControls, snapControls, addLayersControls • The parameters that you will find in the
{ addLayersControls and meshQualityControls. Each section
controls a step of the meshing process.
{ snappyHexMeshDict dictionaries distributed
... ...
... ... with the tutorials, in our opinion are robust and
} • In the first three lines we can turn off and turn on the different }
meshing steps. For example, if we want to generate a body fitted will work most of the times.
meshQualityControls mesh with no boundary layer we should proceed as follows: meshQualityControls
{ {
... castellatedMesh true; ...
... snap true; ... May be located In a separated file
} addLayers false; }
434 435

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


Let us explore the snappyHexMeshDict dictionary. Let us explore the snappyHexMeshDict dictionary.
Geometry controls section Castellated mesh controls section
geometry castellatedMeshControls
{ {
//Refinement parameters
wolfExtruded.stl STL file to read maxLocalCells 100000;
{ maxGlobalCells 2000000;
type triSurfaceMesh; nCellsBetweenLevels 3;
name wolf; Name of the surface inside snappyHexMesh ...
...
regions Use this option if you have a STL with multiple patches defined
{ //Explicit feature edge refinement
wolflocal This is the name of the region or surface patch in the STL features Dictionary block
{ (
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 //Surface based refinement
box Name of geometrical entity refinementSurfaces Dictionary block
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 ); } • In the castellatedMeshControls section, we define the global
} • You can add multiple STL files. refinement parameters, explicit feature edge refinement,
//Region-wise refinement surface based refinement, region-wise refinement and the
sphere Name of geometrical entity • If you do not give a name to the surface, it will take the name of the refinementRegions Dictionary block material point.
{ STL file. {
type searchableSphere; Note 1 ... • In this step, we are generating the castellated mesh.
centre (120.0 -100.0 50.0 ); • The geometrical entities are created inside snappyHexMesh. ...
radius 40.0; }
} Note 1: Note 1:
If you want to know what geometrical entities are available, just //Mesh selection The material point indicates where we want to create the mesh,
} misspelled something in the type keyword. locationInMesh (-100.0 0.0 50.0 ); Note 1 that is, inside or outside the body to be meshed.
}
436 437
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary. Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section Castellated mesh controls section
castellatedMeshControls castellatedMeshControls
{ {

// Refinement parameters ...


maxLocalCells 100000; ...
maxGlobalCells 2000000; ...
minRefinementCells 0;
maxLoadUnbalance 0.10; //Surface based refinement
nCellsBetweenLevels 3; Note 1 refinementSurfaces Dictionary block
{
//Local curvature and
//feature angle refinement //wolf was defined in the geometry section
resolveFeatureAngle 30; Note 2 wolf Note 1
{
planarAngle 30;
level (1 1); //Global refinement
allowFreeStandingZoneFaces true;
regions Note 2
{
//Explicit feature edge refinement
Note 1:
features Dictionary block wolflocal Note 3
This parameter controls the transition between cell Note 1:
( {
refinement levels. The surface wolf was defined in the geometry section.
{ level (2 4); Local refinement
file "wolfExtruded.eMesh"; Note 3
Note 2: Note 2:
level 2; patchInfo
This parameter controls the local curvature refinement. The The region wolflocal was defined in the geometry section.
} {
higher the value, the less features it captures. For example
); type wall; Note 4
if you use 100, it will not add refinement in high curvature Note 3:
}
areas. It also controls edge feature snapping, high values Named region in the STL file. This refinement is local.
... }
will not resolve sharp angles in surface intersections. To use the surface refinement in the regions, the local
... }
regions must exist in STL file. We created a pointer to this
... }
Note 3: region in the geometry section.
...
This file is automatically created when you use the utility
} ...
surfaceFeatureExtract. The file is located in the Note 4:
438 } 439
directory constant/triSurface You can only define patches of type wall or patch.

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


Let us explore the snappyHexMeshDict dictionary. Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section Castellated mesh controls section
castellatedMeshControls castellatedMeshControls
{ {

//Surface based refinement ...


refinementSurfaces Dictionary block ...
{ ...

... //Region-wise refinement


... refinementRegions Dictionary block
... {
//This surface or geometrical entity
//was defined in geometry section //This region or geometrical entity
sphere Note 1 //was defined in the geometry section
{
level (1 1); box Note 1
{
faceZone face_inner; Name of faceZone mode inside;
cellZone cell_inner; Name of cellZone levels (( 1 1 ));
}
cellZoneInside inside; Create inner cellZone
}
//faceType internal; Create internal faces from faceZone
Uncomment to create the internal faceZone
} //Mesh selection Note 1:
Note 1: locationInMesh (-100.0 0.0 50.0 ); This region or geometrical entity was created in the geometry section.
} 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; 440 441


Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary. Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section Snap mesh controls section
castellatedMeshControls snapControls
{ {

... //Number of patch smoothing iterations


... //before finding correspondence to surface
... nSmoothPatch 3;

//Region-wise refinement tolerance 2.0;


refinementRegions Dictionary block
{ //- Number of mesh displacement relaxation
//iterations.
//This region or geometrical entity nSolveIter 100; Note 1
//was defined in the geometry section
//- Maximum number of snapping relaxation
box //iterations. Should stop before upon
{ //reaching a correct mesh.
mode inside; nRelaxIter 10; Note 2
levels (( 1 1 ));
} // Feature snapping

} //Number of feature edge snapping iterations.


nFeatureSnapIter 10; Note 3 Note 1:
This point defines where do you want the mesh. The higher the value the better the body fitted mesh. The default value
//Mesh selection Can be internal mesh or external mesh. //Detect (geometric only) features by is 30. If you are having problems with the mesh quality (related to the
locationInMesh (-100.0 0.0 50.0 ); //sampling the surface (default=false). snapping step), try to increase this value to 300. Have in mind that this
• If the point is inside the STL it is an internal mesh. implicitFeatureSnap false; will increase the meshing time.
} • If the point is inside the background mesh and outside the
STL it is an external mesh. // Use castellatedMeshControls::features Note 2:
// (default = true) Increase this value to improve the quality of the body fitted mesh.
explicitFeatureSnap true;
Note 3:
Increase this value to improve the quality of the edge features.
At this point we have a valid mesh (cartesian) multiRegionFeatureSnap false;

} • In this step, we are generating the body fitted mesh.


442 443

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


Let us explore the snappyHexMeshDict dictionary. Let us explore the snappyHexMeshDict dictionary.
Boundary layer mesh controls section Mesh quality controls section
addLayersControls meshQualityControls
{ {
//Global parameters maxNonOrtho 75; Note 1
relativeSizes true;
expansionRatio 1.2; maxBoundarySkewness 20;
finalLayerThickness 0.5;
minThickness 0.01; maxInternalSkewness 4; Note 2

layers Note 1 maxConcave 80;


{
wolf_wall Note 2 minVol 1E-13;
{
nSurfaceLayers 3; //minTetQuality 1e-15;
//Local parameters minTetQuality -1e+30;
//expansionRatio 1.3;
//finalLayerThickness 0.3; minArea -1;
//minThickness 0.1;
} minTwist 0.02;
}
// Advanced settings minDeterminant 0.001;
Note 1:
nGrow 0;
Maximum non-orthogonality angle.
featureAngle 130; Note 3 Note 1: minFaceWeight 0.05;
maxFaceThicknessRatio 0.5; In this section we select the patches where we want to add the
Note 2:
nSmoothSurfaceNormals 1; layers. We can add multiple patches (if they exist). minVolRatio 0.01;
Maximum skewness angle.
nSmoothThickness 10;
minMedianAxisAngle 90; Note 2: minTriangleTwist -1;
• During the mesh generation process, the mesh quality is continuously
maxThicknessToMedialRatio 0.3; This patch was created in the geometry section.
monitored.
nSmoothNormals 3; minFlatness 0.5; • The mesher snappyHexMesh will try to generate a mesh using the
slipFeatureAngle 30; Note 3:
mesh quality parameters defined by the user.
nRelaxIter 5; Specification of feature angle above which layers are collapsed nSmoothScale 4;
• If a mesh motion or topology change introduces a poor quality cell or
nBufferCellsNoExtrude 0; automatically.
face the motion or topology change is undone to revert the mesh back
nLayerIter 50; errorReduction 0.75;
to a previously valid error free state.
nRelaxedIter 20; • In this step, we are generating the boundary layer mesh. }
} 444 445
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary. Let us generate the mesh of the wolf dynamics logo.
Mesh debug and write controls sections
debugFlags • This tutorial is located in the directory:
(
// write intermediate meshes • $PTOFC/101SHM/M101_wolf
mesh

// write current mesh intersections as .obj files


intersections
• In this case we are going to generate a body fitted mesh with boundary layer. This is an
// write information about explicit feature edge external mesh.
// refinement
featureSeeds
• Before generating the mesh take a look at the dictionaries and files that will be used.
// write attraction as .obj files
attraction • These are the dictionaries and files that will be used.
// write information about layers • system/snappyHexMeshDict
layerInfo
); • system/surfaceFeatureExtractDict

writeFlags
• system/meshQualityDict
(
// write volScalarField with cellLevel for • At the end of the dictionary you will find the sections: debugFlags • system/blockMeshDict
// postprocessing and writeFlags
scalarLevels • constant/triSurface/wolfExtruded.stl
• By default they are commented. If you uncomment them you will
// write cellSets, faceSets of faces in layer enable debug information. • constant/triSurface/wolfExtruded.eMesh
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.
); • The file wolfExtruded.eMesh is generated after using the utility
surfaceFeatureExtract, which reads the dictionary surfaceFeatureExtractDict.
446 447

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


Let us generate the mesh of the wolf dynamics logo. Let us generate the mesh of the wolf dynamics logo.

• To generate the mesh, in the terminal window type: • 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.
1. $> foamCleanTutorials In this case, snappyHexMesh automatically saved the intermediate steps.
2. $> blockMesh • Before running the simulation, remember to transfer the solution from the
3. $> surfaceFeatureExtract latest mesh to the directory constant/polyMesh, in the terminal type:
4. $> snappyHexMesh
5. $> checkMesh –latestTime 1. $> cp 3/polyMesh/* constant/polyMesh
2. $> rm –rf 1
• To visualize the mesh, in the terminal window type: $> rm –rf 2
3.
• $> paraFoam $> rm –rf 3
4.
5. $> checkMesh –latestTime
• Remember to use the VCR controls in paraView/paraFoam to visualize the
mesh intermediate steps.
448 449
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo. 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
• If you want to avoid the additional steps of transferring the final mesh to the conditions in the directory 0.
directory constant/polyMesh by not saving the intermediate steps, you • Let us talk about the constant/polyMesh/boundary file,
can proceed as follows: • First at 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
• $> snappyHexMesh –overwrite the domain is specified.
• The base type boundary condition is the actual surface patch where we are going to apply
a primitive type boundary condition (or numerical boundary condition).
• When you proceed in this way, snappyHexMesh automatically saves the • The primitive type boundary condition assign a field value to the surface patch (base
final mesh in the directory constant/polyMesh. type).
• Have in mind that you will not be able to visualize the intermediate steps. • You define the numerical type patch (or the value of the boundary condition), in the
directory 0 or time directories.
• Also, you will not be able to restart the meshing process from a saved state • The name and base type of the patches was defined in the dictionaries blockMeshDict
(castellated or snapped mesh). and snappyHexMeshDict.
• You can change the name if you do not like it. Do not use strange symbols or white
• Unless it is strictly necessary, from this point on we will not save the
spaces.
intermediate steps. • You can also change the base type. For instance, you can change the type of the patch
450 maxY from wall to patch. 451

Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh


The constant/polyMesh/boundary file The constant/polyMesh/boundary file
Number of surface patches
18 9 In the list bellow there must be 9 patches 18 9 Name
19 ( 19 ( Name and type of the surface patches
20 minX definition. 20 minX
21 { 21 { • The name and base type of the patch is given by the user.
22 type wall; 22 type wall; Type
23 inGroups 1(wall); 23 inGroups 1(wall);
24 nFaces 400; 24 nFaces 400; • In this case the name and base type was assigned in the
25 startFace 466399; wolf_wall 25 startFace 466399;
dictionaries blockMeshDict and snappyHexMeshDict.
26 } maxY 26 }
27 maxX 27 maxX
28 { 28 {
nFaces • You can change the name if you do not like it. Do not use
29 type wall; 29 type wall;
30 inGroups 1(wall); 30 inGroups 1(wall); startFace strange symbols or white spaces.
31 nFaces 400; 31 nFaces 400;
32 startFace 466799; 32 startFace 466799;
• You can also change the base type. For instance, you can
33 } minZ 33 }
34 minY 34 minY change the type of the patch maxY from wall to patch.
35 { 35 {
36 type empty; 36 type empty;
37 inGroups 1(wall); 37 inGroups 1(wall);
38 nFaces 400; 38 nFaces 400;
39 startFace 467199; 39 startFace 467199; nFaces and startFace keywords
40 } 40 }
41 maxY
minX maxX 41 maxY • Unless you know what you are doing, you do not
42 { 42 {
43 type wall; 43 type wall; need to change this information.
44 inGroups 1(wall); 44 inGroups 1(wall);
45
46
nFaces
startFace
400;
467599;
45
46
nFaces
startFace
400;
467599;
• Basically, this is telling you the starting face and ending face
47 } 47 } of the patch.
48 minZ maxZ 48 minZ
49 { 49 {
50 type wall; 50 type wall; • This information is created automatically when generating
51
52
inGroups
nFaces
1(wall);
400;
51
52
inGroups
nFaces
1(wall);
400;
the mesh or converting the mesh.
53 startFace 467999; 53 startFace 467999;
54 } 54 }
sphere
minY
sphere_slave
452 453
Mesh generation using snappyHexMesh Mesh generation using snappyHexMesh
The constant/polyMesh/boundary file Cleaning the case directory

55 maxZ
• When generating the mesh using OpenFOAM®, it is extremely important to
Name and type of the surface patches
56
57
{
type wall; start from a clean case directory.
58 inGroups 1(wall); • The name and base type of the patch is given by the user.
59 nFaces 400;
60 startFace 466399;
• In this case the name and base type was assigned in the
61
62
}
wolf_wall
Name
dictionaries blockMeshDict and snappyHexMeshDict.
• To clean all the case directory, in the terminal type:
63 {
64 type wall; Type
• You can change the name if you do not like it. Do not use
65
66
inGroups
nFaces
1(wall);
400;
strange symbols or white spaces.
• $> foamCleanTutorials
67 startFace 466799;
68 }
69 sphere
nFaces • You can also change the base type. For instance, you can
70
71
{
type empty; startFace change the type of the patch maxY from wall to patch. • To only erase the mesh information, in the terminal type:
72 inGroups 1(wall);
73 nFaces 400;


74 startFace 467199;
75
76
}
sphere_slave nFaces and startFace keywords
$> foamCleanPolyMesh
77 {
78 type wall; • Unless you know what you are doing, you do not
79
80
inGroups
nFaces
1(wall);
400; need to change this information. • If you are planning to start the meshing from a previous saved state, you do
81 startFace 467599;
82
83 )
}
• Basically, this is telling you the starting face and ending face not need to clean the case directory.
of the patch.
• This information is created automatically when generating • Before proceeding to compute the solution, remember to always check the
the mesh or converting the mesh.
quality of the mesh.

454 455

Roadmap 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
1. Meshing preliminaries and introduce a few advanced features.
2. What is a good mesh? • This case is located in the directory $PTOFC/101SHM/M1cyl

3. Mesh quality assessment in OpenFOAM®


4. Mesh generation using blockMesh.
5. blockMesh guided tutorials.
6. Mesh generation using snappyHexMesh.
7. snappyHexMesh guided tutorials.
8. Mesh conversion
9. Geometry and mesh manipulation utilities
456 457
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement.

• Meshing with snappyHexMesh.


• Meshing case 1. 3D Cylinder (external mesh), with
feature edge refinement.

$PTOFC/101SHM/M1_cyl/C1 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.
• From this point on, please follow me.
• In the left figure there is no need to use edge refinement as there are no sharp angles.
• We are all going to work at the same pace.
• In the mid figure we used edge refinement to resolve the sharp angles.
• Remember, $PTOFC is pointing to the path where you • In the right figure we did not use edge refinement, therefore we did not resolve well the sharp
unpacked the tutorials. angles.

458 459

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement. 3D Cylinder with edge refinement.
• How do we control curvature refinement and enable edge refinement?
• In the file snappyHexMeshDict, look for the following entry: How resolveFeatureAngle works?
castellatedMeshControls
{
angle < resolveFeatureAngle
...
If angle is more than resolveFeatureAngle
No curvature refinement
...
... the adjacent STL faces will be marked for
refinement
//Local curvature and
//feature angle refinement angle
resolveFeatureAngle 30; To control curvature refinement

...
...
...

//Explicit feature edge refinement resolveFeatureAngle


features
( STL
{
To enable and
file “surfacemesh.eMesh";
control edge
level 0;
refinement level
}
);

... 0: mark the whole surface for refinement


... 180: do not mark any STL face for refinement
...

} 460 461
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement. 3D Cylinder with edge refinement.
• How do we control surface refinement?
How resolveFeatureAngle works? • In the file snappyHexMeshDict, look for the following entry:

angle > resolveFeatureAngle


castellatedMeshControls
If angle is more than resolveFeatureAngle
Curvature refinement {
the adjacent STL faces will be marked for ...
refinement ...
...
angle
//Surface based refinement
refinementSurfaces
{
banana_stlSurface To control surface refinement.
{ The first digit controls the global
surface refinement level and the second
resolveFeatureAngle level (2 4); digit controls the curvature refinement
STL } level, according to the angle set in the
} entry resolveFeatureAngle

...
...
...
0: mark the whole surface for refinement
180: do not mark any STL face for refinement }

462 463

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement. 3D Cylinder with edge refinement.
• How do we create refinement regions? • How do we create refinement regions?
• In the file snappyHexMeshDict, look for the following entry: • In the file snappyHexMeshDict, look for the following entry:

castellatedMeshControls
geometry {
{ ...
... ...
... ...
...
refinementRegions
refinementBox Name of refinement region { Name of the region
{ refinementBox created in the geometry section
type searchableBox; Geometrical entity type. {
min ( -2 -2 -2); This is the zone where we mode inside; Type of refinement (inside,
max ( 2 2 2); want to apply the refinement levels ((1e15 1)); outside, or distance mode)
} }
}
... Refinement level
Dimensions of geometrical entity ...
...
... ... Distance from the surface
}; ... A large value covers the whole region
}
464 465
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement. 3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 0 Explicit feature edge refinement level 0 Explicit feature edge refinement level 0 Explicit feature edge refinement level 4
resolveFeatureAngle 110 resolveFeatureAngle 60 resolveFeatureAngle 60 resolveFeatureAngle 60
Surface based refinement level (2 2) Surface based refinement level (2 2) Surface based refinement level (2 2) Surface based refinement level (2 2)

• To control edges capturing you can decrease the value of resolveFeatureAngle. • To control edges refinement level, you can change the value of the explicit feature
• Be careful, this parameter also controls curvature refinement, so if you choose a low edge refinement level.
value you also will be adding a lot of refinement on the surface.
466 467

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement. 3D Cylinder with edge refinement.

Effect of various parameters on edge capturing and surface refinement Effect of various parameters on edge capturing and surface refinement

Explicit feature edge refinement level 6 Explicit feature edge refinement level 0 Explicit feature edge refinement level 0 Explicit feature edge refinement level 4
resolveFeatureAngle 5 resolveFeatureAngle 5 resolveFeatureAngle 60 resolveFeatureAngle 60
Surface based refinement level (2 4) Surface based refinement level (2 4) Surface based refinement level (2 4) Surface based refinement level (2 2)

• To control edges refinement level, you can change the value of the explicit feature • To control surface refinement level, you can change the value of the surface based
edge refinement level. refinement level.
• The first digit controls the global surface refinement level and the second digit
468
controls the curvature refinement level. 469
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement. 3D Cylinder with edge refinement.
• Let us explore the dictionary surfaceFeatureExtractDict used by the
Effect of various parameters on edge capturing and surface refinement utility surfaceFeatureExtract.
• This utility will extract surface features (sharp angles) according to an angle
criterion (includedAngle).

Name of the STL. Features edges


surfacemesh.stl The STL file is located
{ in constant/triSurface

extractionMethod extractFromSurface;

extractFromSurfaceCoeffs
{
Angle criterion
includedAngle 150;
to extract features
}
Explicit feature edge refinement level 0 Explicit feature edge refinement level 0
resolveFeatureAngle 60 resolveFeatureAngle 5 subsetFeatures
{
Surface based refinement level (2 4) Surface based refinement level (2 4) nonManifoldEdges yes;
openEdges yes;
}
• To control surface refinement due to curvature together with control based surface If you want to save
writeObj yes;
refinement level, you can change the value of resolveFeatureAngle, and surface the .obj files Features edges

based refinement level }

470 471

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement. 3D Cylinder with edge refinement.
• Let us explore the dictionary surfaceFeatureExtractDict used by the • If you want to have a visual representation of the feature edges, you can use
utility surfaceFeatureExtract. paraview/paraFoam.
• Just look for the filter Feature Edges.
• This utility will extract surface features (sharp angles) according to an angle • Have in mind that the angle you need to define in paraview/paraFoam is the complement of the
criterion (includedAngle). angle you define in the dictionary surfaceFeatureExtractDict

Name of the STL. If angle is less than includedAngle


surfacemesh.stl The STL file is located this feature will be marked
{ in constant/triSurface

extractionMethod extractFromSurface;
angle
extractFromSurfaceCoeffs
{
Angle criterion
includedAngle 150;
to extract features
} STL
subsetFeatures includedAngle
{
nonManifoldEdges yes;
openEdges yes;
} Mark edges whose adjacent surface normals
are at an angle less than includedAngle
writeObj yes; If you want to save
the .obj files 0: selects no edges
} 180: selects all edge

472 473
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement. 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. • Let us generate the mesh, in the terminal window type:
• These are the dictionaries and files that will be used.
1. $> foamCleanTutorials
• system/snappyHexMeshDict
2. $> surfaceFeatureExtract
• system/surfaceFeatureExtractDict
• system/meshQualityDict 3. $> blockMesh
• system/blockMeshDict 4. $> snappyHexMesh –overwrite
• constant/triSurface/surfacemesh.stl 5. $> checkMesh –latestTime
• constant/triSurface/surfacemesh.eMesh 6. $> paraFoam

• The file surfacemesh.eMesh is generated after using the utility surfaceFeatureExtract, • In step 2 we extract the sharp angles from the geometry.
which reads the dictionary surfaceFeatureExtractDict.
• The utility surfaceFeatureExtract, will save a set of *.obj files with the captured edges. • In step 3 we generate the background mesh.
These files are located in the directory constant/extendedFeatureEdgeMesh. You can • In step 4 we generate the body fitted mesh. Have in mind that as we use the
use paraview to visualize the *.obj files.
option –overwrite, we are not saving the intermediate steps.
• In step 5 we check the mesh quality.
474 475

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer.

• Meshing with snappyHexMesh.


• Meshing case 2. 3D Cylinder (external mesh), with
feature edge refinement and boundary layer.

$PTOFC/101SHM/M1_cyl/C2

• From this point on, please follow me.


• We are all going to work at the same pace. Your final mesh should looks like this one
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
476 477
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.
• How do we enable boundary layer? • How do we enable boundary layer?
• In the file snappyHexMeshDict, look for the following entry: • In the file snappyHexMeshDict, look for the section addLayersControls:

addLayersControls
{

//Global parameters
relativeSizes true;
castellatedMesh true; //or false expansionRatio 1.2;
finalLayerThickness 0.5;
Set this parameter to snap true; //or false minThickness 0.1;
true if you want to
enable boundary layer
addLayers true; //or false layers
meshing { Name of the surface or user-defined
banana_stlSurface patch where you want to add the
... {
nSurfaceLayers 3;
boundary layer mesh.

... }
}
...
// Advanced settings

...
...
...

478 479

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.
• How do we control boundary layer collapsing?
• In the file snappyHexMeshDict, look for the section addLayersControls: Effect of different parameters on the boundary layer meshing

addLayersControls
{

...
...
...

// Advanced settings
nGrow 0;
featureAngle 130; Increase this value to avoid BL relativeSizes true relativeSizes false
collapsing 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)
}

480 481
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing 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.
• When the option relativeSizes is false, we give the actual thickness of the layers.
• Also, it is quite difficult to set a desired thickness of the first layer.
• This option requires a lot user intervention but it guarantees a uniform boundary layer and the
482 desired layer thickness. 483

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing Effect of different parameters on the boundary layer meshing

relativeSizes true relativeSizes true relativeSizes true relativeSizes true


expansionRatio 1.2 expansionRatio 1.2 expansionRatio 1.2 expansionRatio 1.2
finalLayerThickness 0.5 finalLayerThickness 0.5 finalLayerThickness 0.5 finalLayerThickness 0.5
minThickness 0.1 minThickness 0.1 minThickness 0.1 minThickness 0.1
featureAngle 130 featureAngle 130 featureAngle 130 featureAngle 30
nSurfaceLayers 3 nSurfaceLayers 3 nSurfaceLayers 3 nSurfaceLayers 3
Surface based refinement level (2 4) Surface based refinement level (2 2) Surface based refinement level (2 2) 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. • To avoid boundary layer collapsing close to the corners, we can increase the value of the
boundary layer parameter featureAngle.
• Nevertheless, we still do not have control on the desired thickness of the first layer. 484 485
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.

Effect of different parameters on the boundary layer meshing • To generate the mesh, in the terminal window type:

1. $> foamCleanTutorials
2. $> surfaceFeatureExtract
3. $> blockMesh
4. $> snappyHexMesh -overwrite
5. $> checkMesh –latestTime
6. $> paraFoam
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.
486 487

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.

• At the end of the meshing process you will get the following information • If you want to visualize the boundary layer thickness, you can enable
regarding the boundary layer meshing: writeFlags in the snappyhexMeshDict dictionary,

...
patch faces layers overall thickness ...
...
[m] [%]

----- ----- ------ --- --- writeFlags


(
banana_stlSurface 4696 3 0.0569 95.9 scalarLevels; // write volScalarField with cellLevel for postprocessing
layerSets; // write cellSets, faceSets of faces in layer
layerFields; // write volScalarField for layer coverage
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). 488 489
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer. 3D Cylinder with edge refinement and boundary layer.

• Then you can use paraview/paraFoam to visualize the boundary layer • After creating the mesh and if you do not like the inflation layer or you want to
coverage. 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 snappyHeshMesh -overwrite.
Boundary layer thickness and number of layers
• 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.

The yellow surface represent the BL coverage


490 491

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer.
• Meshing with snappyHexMesh.
• Remember, before restarting the meshing you will need to modify the • Meshing case 3. 3D Cylinder (external mesh), with
snappyHexMeshDict dictionary as follows:
feature edge refinement and boundary layer, using a
castellatedMesh false; STL file with multiple surfaces.
snap false;
addLayers true; $PTOFC/101SHM/M1_cyl/C3

• At this point, you can restart the meshing process by typing in the terminal,
• $> snappyHexMesh
• From this point on, please follow me.
• By the way, you can restart the boundary layer mesh from a previous mesh • We are all going to work at the same pace.
with a boundary layer. • Remember, $PTOFC is pointing to the path where you
• So in theory, you an add one layer at a time, this will give you more control unpacked the tutorials.
but it will require more manual work and some scripting.
492 493
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file 3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces. 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. • When you use a STL with multiple surfaces, you have more control over the meshing process.
• Loading multiple STLs is equivalent to using a STL with multiple surfaces. • In this case, we were able to use different refinement parameters in the lateral and central
494
surface patches of the cylinder. 495

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer, using a STL file 3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces. with multiple surfaces.
• How do we assign different names to different surface patches? • How do we refine user defined surface patches?
• In the file snappyHexMeshDict, look for the following entry: • In the file snappyHexMeshDict, look for the following entry:
geometry castellatedMeshControls
{ {
surfacemesh.stl ...
{ ...
type triSurfaceMesh; ...
name stlSurface; refinementSurfaces
{
regions level (2 2); Global refinement level
{ regions
patch0 Named region in the STL file {
{ patch0 Local surface patch
name surface0; User-defined patch name {
} This is the name you need to use when level (2 2); Local refinement level
setting the boundary layer meshing patchInfo
patch1 {
{ type wall; Type of the patch.
name surface1; } This information is optional
} }
patch2 ...
{ ...
name surface2; ...
} }
} }
} ...
... ...
... ...
... }
} 496 497
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file 3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces. with multiple surfaces.
• How do we control curvature refinement on surface patches? • How do we control curvature refinement on surface patches?
• In the file snappyHexMeshDict, look for the following entry: • In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
... castellatedMeshControls
... {
refinementSurfaces
{
level (2 2); Global refinement level ...
regions ...
{
patch0 Local surface patch ...
{
level (2 4); Local curvature refinement (in red)
patchInfo
//Local curvature and
{ //feature angle refinement The default value is 30.
type wall; resolveFeatureAngle 60; Using a higher value will capture
} less features.
}
... ...
...
...
...
} ...
}
...
... }
...
}
498 499

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer, using a STL file 3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces. with multiple surfaces.
• How do we control boundary layer meshing on the surface patches?
• Let us first create the STL file with multiple surfaces.
• In the file snappyHexMeshDict, look for the following entry: • In the directory geo, you will find the original STL file.
addLayersControls • In the terminal type:
{

//Global parameters
relativeSizes true;
1. $> cd geo
expansionRatio 1.2;
Global BL parameters
finalLayerThickness 0.5; 2. $> surfaceAutoPatch geo.stl output.stl 130
minThickness 0.1;
layers
{ 3. $> cp output.stl ../constant/triSurface/surfacemesh.stl
“surface.*” POSIX wildcards are permitted
{ 4. $> cd ..
nSurfaceLayers 5;
}
surface0 Local surface patch 5. $> paraview
{
nSurfaceLayers 3;
expansionRatio 1.0;
Local BL parameters
• The utility surfaceAutoPatch will read the original STL file (geo.stl), and it will find the
finalLayerThickness 0.25;
minThickness 0.1; patches using an angle criterion of 130 (similar to the angle criterion used with the utility
}
}
surfaceFeatureExtract). It writes the new STL geometry in the file output.stl.
//Advanced settings • 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
...
} 500
patches, this utility will automatically find the patches according to an angle criterion. 501
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file 3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces. with multiple surfaces.

• If you open the file output.stl, you will notice that there are three • The new STL file is already in the constant/triSurface directory.
surfaces defined in the STL file. The different surfaces are defined in by the • To generate the mesh, in the terminal window type:
following sections:
1. $> foamCleanTutorials
solid patch0
… Surface patch 1 • The name of the solid sections are 2. $> surfaceFeatureExtract
automatically given by the utility
endsolid patch0 3. $> blockMesh
surfaceAutoPatch.
4. $> snappyHexMesh -overwrite
solid patch1
• The convention is as follows: patch0, 5. $> checkMesh –latestTime
… Surface patch 2
patch1, pathc2, … patchN.
endsolid patch1

• If you do not like the names, you can • To visualize the mesh, in the terminal window type:
solid patch2
change them directly in the STL file.
… Surface patch 3 6. $> paraFoam
endsolid patch2

502 503

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


3D Cylinder with edge refinement and boundary layer, using a STL file 3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces. with multiple surfaces.

• This case is ready to run using the solver simpleFoam. But before running, • This case is ready to run with simpleFoam.
you will need to set the boundary and initial conditions. • If you are in a hurry and you do not want to create/edit the files 0/U, 0/p,
• You will need to manually modify the file constant/polyMesh/boundary constant/polyMesh/boundary, follow these steeps to run the case:
• Remember:
1. $> cp 0_org/* 0
• Base type boundary conditions are defined in the file boundary located
in the directory constant/polyMesh. 2. $> cp system/boundary_org constant/polyMesh/boundary

• Primitive or numerical type boundary conditions are defined in the field 3. $> renumberMesh –overwrite
variables files located in the directory 0 or the time directory from which 4. $> simpleFoam > log | tail –f log
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.
504 505
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
2D Cylinder
• Meshing with snappyHexMesh.
• Meshing case 4. 2D Cylinder (external mesh).

$PTOFC/101SHM/M1_cyl/C4

From 3D To 2D

• From this point on, please follow me. • To generate a 2D mesh using snappyHexMesh, we need to start from a 3D. After all,
snappyHexMesh is a 3D mesher.
• We are all going to work at the same pace.
• To generate a 2D mesh (and after generating the 3D mesh), we use the utility
• Remember, $PTOFC is pointing to the path where you extrudeMesh.
unpacked the tutorials. • The utility extrudeMesh works by projecting a face into a mirror face. Therefore,
506
the faces need to parallel. 507

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


2D Cylinder 2D Cylinder

Geometry width
• How do we create the 2D mesh?
FACE 1
• After generating the 3D mesh, we use the utility extrudeMesh.
The utility extrudeMesh works by
projecting FACE 1 into FACE 2.
• This utility reads the extrudeMeshDict,
Therefore, the faces need to be
parallel.
constructFrom patch;
FACE 2 Background mesh width
sourceCase “.”
sourcePatches (minZ); Name of source patch

exposedPatchName maxZ; Name of the mirror patch


• 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 extrudeModel linearNormal
by the faces of the background mesh. nLayers 1; Number of layers to use in the linear extrusion.
As this is a 2D case we must use 1 layer
• In this case, the input geometry will be cut by the two lateral patches of the
linearNormalCoeffs
background mesh.
{
Thickness of the extrusion.
• If you want to take advantage of symmetry in 3D, you can cut the geometry in half thickness 1;
It is highly recommended to use a value of 1
using one of the faces of the background mesh. }

mergeFaces false;
508 509
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
2D Cylinder

• To generate the mesh, in the terminal window type: • Meshing with snappyHexMesh.
1. $> foamCleanTutorials • Meshing case 5. Mixing elbow (internal mesh)
2. $> blockMesh
3. $> snappyHexMesh –overwrite
$PTOFC/101SHM/M2_mixing_elbow
4. $> extrudeMesh
5. $> checkMesh –latestTime
6. $> paraFoam
• From this point on, please follow me.
• Remember, the utility extrudeMesh (step 4) reads the dictionary
• We are all going to work at the same pace.
extrudeMeshDict, which is located in the directory system.
• Also remember to set the empty patches in the dictionary boundary and in the
• Remember, $PTOFC is pointing to the path where you
boundary conditions. unpacked the tutorials.
510 511

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


Mixing elbow. 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
...
...
Your final mesh should looks like this one }
512 513
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
Mixing elbow. Mixing elbow.
• In this case we are going to generate a body fitted mesh with edge
refinement and boundary layer meshing.
• At this point, we are going to work in parallel (but you can work in serial as
• This is an internal mesh. well).
• These are the dictionaries and files that will be used. • To generate the mesh, in the terminal window type:
• system/snappyHexMeshDict
1. $> foamCleanTutorials
• system/surfaceFeatureExtractDict
2. $> surfaceFeatureExtract
• system/meshQualityDict
3. $> blockMesh
• system/blockMeshDict
4. $> decomposePar
• constant/triSurface/surfacemesh.stl
5. $> mpirun -np 4 snappyHexMesh –parallel –overwrite
• constant/triSurface/surfacemesh.eMesh
6. $> mpirun -np 4 checkMesh –parallel –latestTime
7. $> reconstructParMesh -constant
• The file surfacemesh.eMesh is generated after using the utility
8. $> paraFoam
surfaceFeatureExtract, which reads the dictionary
surfaceFeatureExtractDict.
514 515

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


Mixing elbow. Mixing elbow.
• So what did we do? • After running checkMesh, you will get the following information regarding the patch
• Step 4: we distribute the mesh among the processors we want to use. names:
• Step 5 and 6: we run in parallel.
Patch Faces Points Surface topology
• Step 7: we put back together the decomposed mesh. mixing_elbow_inlet1 1264 1297 ok (non-closed singly connected)
pipe 38884 41118 ok (non-closed singly connected)
• Step 8: we visualize the reconstructed mesh. mixing_elbow_inlet2 314 337 ok (non-closed singly connected)
mixing_elbow_outlet 1264 1297 ok (non-closed singly connected)

• Notice that the utility blockMesh does not run in parallel.


• Remember to set the keyword numberOfSubdomains in the dictionary decomposeParDict • Sometimes you can get empty patches.
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 Patch Faces Points Surface topology
minX 0 0 ok (empty)
equal to 4. maxX 0 0 ok (empty)
minY 0 0 ok (empty)
• To run the simulation and after reconstructing the mesh, you will need to transfer the boundary maxY 0 0 ok (empty)
and initial conditions information to the decomposed mesh, minZ 0 0 ok (empty)
maxZ 0 0 ok (empty)
• $> decomposePar –fields mixing_elbow_inlet1 1264 1297 ok (non-closed singly connected)
pipe 38884 41118 ok (non-closed singly connected)
• Or you can force to decompose everything as follows, mixing_elbow_inlet2 314 337 ok (non-closed singly connected)
mixing_elbow_outlet 1264 1297 ok (non-closed singly connected)
• $> decomposePar –force
516 517
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
Mixing elbow. Mixing elbow.
• Empty patches are no problem, they remain from the background mesh.
• The mesh used in the previous case was a STL with multiple surfaces.
• 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 • In you do not create the regions in the geometry section of the dictionary
snappyHexMeshDict, snappyHexMesh will automatically assign the names of the
parallel):
surface patches as follows:
• $> createPatch -overwrite system/surfaceFeatureExtractDict


• mixing_elbow_outlet …
• The surface patch pipe was created in the geometry section of the dictionary
snappyHexMeshDict. • mixing_elbow_inlet1 geometry
{
surfacemesh.stl

• The patches mixing_elbow_outlet, mixing_elbow_inlet1 and • mixing_elbow_inlet2 {


type triSurfaceMesh;
mixing_elbow_inlet2 were created automatically by snappyHexMesh. name mixing_elbow;
regions
{
• You have the choice of giving the names of the patches yourself or letting pipe NOTE 1
{
snappyHexMesh assign the names automatically. NOTE 2 name pipe;
}
• Remember, when creating the boundary layer mesh, these are the names you need }
}
to use to assign the layers. 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.

518 519

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


Mixing elbow. Mixing elbow.

• The mesh used in the previous case was a STL with multiple surfaces. • 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 • In the directory geometry, you fill find the file
snappyHexMeshDict, snappyHexMesh will automatically assign the names of the
mixing_pipe_onesurface.stl, this STL has one single surface.
surface patches as follows:
constant/triSurfaceSurfacemesh.stl
• Try to use this STL file to generate the mesh.
• mixing_elbow_outlet • You will notice that the final mesh has only one patch, namely
solid outlet
• mixing_elbow_inlet1 …

mixing_elbow (or whatever name you chose).

• mixing_elbow_inlet2 solid outlet • Also, it is not possible to have local control on the mesh refinement and
solid inlet1

boundary layer meshing.


solid inlet1
• You will also face the conundrum that as there is only one surface patch, it is
solid inlet2
not possible to assign boundary conditions.



solid inlet2

520 521
snappyHexMesh guided tutorials 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
• Meshing with snappyHexMesh.
• The option -overwrite, will copy the new mesh in the directory • Meshing case 6. Ahmed body (external mesh)
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. $PTOFC/101SHM/M3_CSTR
• The angle criterion is similar to that of the utility surfaceFeatureExtract.
• 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. • From this point on, please follow me.
• Remember, autoPatch will manipulate the mesh located in the directory • We are all going to work at the same pace.
constant/polyMesh. • Remember, $PTOFC is pointing to the path where you
• FYI, autoPatch does not un in parallel. unpacked the tutorials.
522 523

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh
Inner region (rotating mesh)

Impeller

http://www.wolfdynamics.com/training/meshing/image5.gif

• In this case we are going to use multiple STL and eMesh files. • We are going to work with sliding grids (the impeller will be rotating), therefore we
• Each color in the figure above represents a different STL. need to divide the mesh in two regions, one fix region and one rotating region.

• Working with multiple STL is no different from working with a single STL, we just need • To split the mesh in two regions we are going to use another STL file (the green
to read all the STLs. surface), plus a few utilities to manipulate the mesh.

• When working with multiple STL we have more control on the local refinement. • We will show how to setup conforming patches between regions.
524 525
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh
• In this case we are going to generate a body fitted mesh with two regions and using multiple • At this point, we are going to work in parallel.
STL files.
• To generate the mesh, in the terminal window type:
• For simulation purposes, one of the regions will be in motion.
• This is an internal mesh.
• These are the dictionaries and files that will be used. 1. $> foamCleanTutorials
• system/snappyHexMeshDict 2. $> foamCleanPolymesh
• system/meshQualityDict
• system/surfaceFeatureExtractDict 3. $> surfaceFeatureExtract
• system/decomposeParDict
4. $> blockMesh
• system/blockMeshDict
• constant/triSurface/impeller.stl 5. $> decomposePar
• constant/triSurface/impeller.eMesh
• constant/triSurface/inner_volume.stl 6. $> mpirun -np 4 snappyHexMesh –parallel –overwrite
• constant/triSurface/inner_volume.eMesh $> mpirun -np 4 checkMesh –parallel –latestTime
7.
• constant/triSurface/shaft.stl
• constant/triSurface/shaft.eMesh 8. $> reconstructParMesh -constant
• constant/triSurface/sparger.stl
• constant/triSurface/sparger.eMesh 9. $> paraFoam
• constant/triSurface/vesel.stl
• constant/triSurface/vesel.eMesh
526 527

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh

• Let us take a look at the dictionary surfaceFeatureExtractDict. • Let us take a look at the geometry section of the dictionary snappyHexMeshDict.
• Notice that we are reading multiple STL files.
• Notice that we are reading multiple STL files.
geometry
{
vessel.stl STL file to read.
vessel.stl Name of the STL. {
{ type triSurfaceMesh;
… Edge detection parameters. name vessel; Name of the surface inside snappyHexMesh.
}
Use regions if you have a STL regions
sparger.stl
with multiple patches defined.
{ {
This is the name of the region or surface
… inlet
patch in the STL file .
} User-defined patch name. {
shaft.stl Note: This is the final name of the name inlet;
{ patch. }
… An individual eMesh file will be generated outlet
} for each individual STL. That is: {
inner_volume.stl name outlet;
{ }
… vessel.stl → vessel.eMesh }
} sparger.stl → sparger.eMesh }
impeller.stl inner_volume.stl Define every single STL that
shaft.stl → shaft.eMesh you want to use.
{ Inner_volume.stl → inner_volume.eMesh {
… type triSurfaceMesh;
}
impeller.stl → impeller.eMesh name inner_volume;
}


}
528 529
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh
• Let us take a look at the castellatedMeshControls section of the dictionary • Let us take a look at the castellatedMeshControls section of the dictionary
snappyHexMeshDict. snappyHexMeshDict.
• Notice that we are reading multiple eMesh files. • In this block we define the cellZone and faceZone, as follows,

castellatedMeshControls
{
... castellatedMeshControls
... {
... ...
...
//Explicit feature edge refinement ...
features
( //Surface based refinement Using the surface inner_volume we create a
{ inner_volume mesh zone that we will use at a later time to
Define every single eMesh file that (
file ”vessel.eMesh"; split the whole mesh in two regions.
level 0; you want to use. level (1 1);
}
{
Define every single eMesh file that
cellZone cell_inner_volume; Name of the cellZone.
file ”shaft.eMesh";
you want to use.
level 0; faceZone face_inner_volume; Name of the faceZone.
}
... cellZoneInside insidePoint; Use an inner point to define location of the zone
...
... insidePoint (50 0 100); Location of the insidePoint.
); The point is located inside the surface
); ...
inner_volume, therefore the new zone is
} ...
... created inside the surface selected.
}

530 531

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh

• Using paraFoam let’s take a look at the newly created zone. • To visualize the zones in paraFoam you will need to enable the option
Include Zones
• Then select the mesh parts cell_inner_volume and face_inner_volume.
face_inner_volume cell_inner_volume

1. 2.
532 533
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh

• At this point and if you run checkMesh, you will get the following • So far we only generated the mesh.
information: • The next step will consist in splitting the mesh in two regions.
• $> checkMesh
• Let us now create the two regions.
… • We will use the following dictionaries and files:

Checking topology… • system/createBafflesDict


Boundary definition OK.
Cell to face addressing OK. • system/createPatchDict
Point usage OK.
UPPER triangular ordering OK. • system/topoSetDict
Face vertices OK.
Number of regions: 1 (OK).

… • The utility createBaffles, reads the dictionary createBafflesDict.

• The utility createPatch, reads the dictionary createPatchDict.
• As you can see we only have one region, but we are interested in having • The utility topoSet, reads the dictionary topoSetDict.
two regions.
534 535

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh

• The utility createBaffles, reads the dictionary createBafflesDict. • To create the two regions we proceed as follows (notice that we are going to
• With this utility we create the interface patches between the fix zone and the work in serial from now on)
rotating zone.

1. $> createBaffles –overwrite


baffles
{
rotating
2. $> mergeOrSplitBaffles –split –overwrite
Name of the baffle group
{
type faceZone;
zoneName face_inner_volume;
Use faceZone
Face to use to construct the AMI patches.
3. $> createPatch –overwrite
The nanme was defined in snappyHexMeshDict
patches
{ 4. $> splitMeshRegions –makeCellZones –overwrite
master Parameters for the master patch

Boundary condition
{
name AMI1; Name of the master patch (user defined) 5. $> splitMeshRegions –detectOnly
type cyclicAMI;
for sliding grids matchTolerance 0.0001;
neighbourPatch AMI2;
transform noOrdering;
Neighbour patch (slave patch or AMI2) 6. $> transformPoints –scale ‘(0.01 0.01 0.01)’
}
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 noOrdering;
}
}
}
} The master and slave patches
share a common face 536 537
snappyHexMesh guided tutorials snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh CSTR – Continuous stirring tank reactor mesh
• So what did we do?
• At this point and if you run checkMesh, you will get the following information:
• Step 1:
• $> checkMesh
• Splits the mesh in regions using the baffles (faceZone), created during the meshing
stage. …

• We also create the cyclicAMI patches AMI1 and AMI2. …
Checking topology…
• At this point we have two regions and one zone. However, the two regions are stich Boundary definition OK.
together via the patches AMI1 and AMI2. Cell to face addressing OK.
Point usage OK.
• Step 2: topologically split the patches AMI1 and AMI2. As we removed the link between UPPER triangular ordering OK.
Face vertices OK.
AMI1 and AMI2, the regions are free to move. *Number of regions: 2
The mesh has multiple regions which are not connected by any face.
• Step 3 (optional): gets rid of zero faced patches if hey exist. These are the patches <<Writing region information to ”0/cellToRegion”
remaining from the base mesh, as they are empty, we do not need them. <<Writing region 0 with 136187 cells to cellSet region0
<<Writing region 1 with 67682 cells to cellSet region1
• Step 4 (optional): …

• Splits mesh into multiple zones. It will create automatically the sets and zones. …
• At this point we have two regions and two zones.
• Step 5 (optional): just to show the regions and names. • As you can see, we now have two regions.
• Step 6 (optional): scales the mesh. • At this point the mesh is ready to use.
538 • You can visualize the mesh (with all the sets and zones) using paraFoam. 539

snappyHexMesh guided tutorials snappyHexMesh guided tutorials


Ahmed body

• Meshing with snappyHexMesh.


• Meshing case 7. Ahmed body (external mesh)

$PTOFC/101SHM/M4_ahmed

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you • At this point, we all have a clear idea of how snappyHexMesh works.
unpacked the tutorials. • If not, please raise your hand.
• So let us go free styling and let us play around with this case.
540 541
snappyHexMesh guided tutorials Roadmap
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. 1. Meshing preliminaries
• You can find our YouTube channel in the following link:
https://www.youtube.com/channel/UCNNBm3KxVS1rGeCVUU1p61g 2. What is a good mesh?
• In these videos, we show a few extra features and some tips and tricks to take the most out of
snappyHexMesh. 3. Mesh quality assessment in OpenFOAM®
• 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 4. Mesh generation using blockMesh.
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 5. blockMesh guided tutorials.
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 6. Mesh generation using snappyHexMesh.
refinement levels, choose in which surfaces you want to add the boundary layers, and choose
how many layers you want to add. 7. snappyHexMesh guided tutorials.
• Final advices:
• If you are working with a complicated geometry, add one layer at a time. 8. Mesh conversion
• Use paraFoam/paraview to get visual references.
• Always check the quality of your mesh.
9. Geometry and mesh manipulation utilities
542 543

Mesh conversion Mesh conversion


• In the directory $FOAM_UTILITIES (use the alias util to go there) you will find the
following sub-directories containing the source code for the utilities available in the
OpenFOAM® installation (version 5.x):

• OpenFOAM® gives users a lot of flexibility when it comes to meshing. • mesh


• miscellaneous
• You are not constrained to use OpenFOAM® meshing tools. • parallelProcessing

• To convert a mesh generated with a third party software to OpenFOAM® • postProcessing


polyMesh format, you can use the OpenFOAM® mesh conversion utilities. • preProcessing
• surface
• If your format is not supported, you can write your own conversion tool.
• thermophysical
• By the way, many of the commercially available meshers can save the mesh
in OpenFOAM® polyMesh format or in a compatible format. • In the sub-directory mesh you will find the source code for the mesh utilities included
in the OpenFOAM® installation.

544 545
Mesh conversion Mesh conversion
• Let us visit the mesh directory. In the terminal type: • In the directory $FOAM_UTILITIES/mesh/conversion you will find the following
• $> util mesh conversion utilities:

• $> cd mesh
• ansysToFoam • kivaToFoam
• $> ls –al
• cfx4ToFoam • mshToFoam
• datToFoam • netgenNeutralToFoam
• In this directory you will find the directories containing the source code for the • fluent3DMeshToFoam • Optional/ccm26ToFoam
following mesh utilities
• fluentMeshToFoam • plot3dToFoam
• advanced
• foamMeshToFluent • sammToFoam
• conversion
• foamToStarMesh • star3ToFoam
• generation
• foamToSurface • star4ToFoam
• Manipulation
• gambitToFoam • tetgenToFoam
• gmshToFoam • vtkUnstructuredToFoam
• In the directory conversion you will find the source code for the mesh conversion
• ideasUnvToFoam • writeMeshObj
utilities. Let us visit this directory, in the terminal type:
• $> cd conversion
• $> ls -al
546 547

Mesh conversion Mesh conversion

• Let us convert to OpenFOAM® format a mesh


• In the directory $PTOFC/mesh_conversion_sandbox you
will find a few meshes generated using the most popular third
generated using Salome, you will find this case in the
party mesh generation applications (in our opinion). directory:
• Feel free to play with these meshes.
$PTOFC/mesh_conversion_sandbox/M1_mixing_elbow_salome
• 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 • From this point on, please follow me.
name and type of the surface patches according to • We are all going to work at the same pace.
what you would like to do. • Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
548 549
Mesh conversion Mesh conversion
Case 1. Mixing elbow (internal mesh). Case 1. Mixing elbow (internal mesh).

• Remember to export the mesh in UNV format in Salome. • ideasUnvToFoam output.


• Then use the utility ideasUnvToFoam to convert the mesh to OpenFOAM® native
format. Create time

• In the terminal window type: Processing tag:2411


Starting reading points at line 3.
Read 31136 points.

Processing tag:2412

1. $> foamCleanTutorials 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
2. $> foamCleanPolyMesh Read 151064 cells and 20572 boundary faces. Internal cells and boundary faces read
Processing tag:2467
3. $> ideasUnvToFoam ../../meshes_and_geometries/salome_elbow3d/Mesh_1.unv 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.
4. $> checkMesh For group 3 named inlet2 trying to read 78 patch face indices.
For group 4 named outlet trying to read 358 patch face indices.

5. $> paraFoam 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

• Remember to always check the file boundary after converting the mesh.
inlet1 358
inlet2 78 Boundary patches detected
outlet 358

End

550 551

Mesh conversion Mesh conversion


Case 1. Mixing elbow (internal mesh). Case 1. Mixing elbow (internal mesh).
• checkMesh output. • checkMesh output.

Mesh stats Checking patch topology for multiply connected surfaces...


points: 31136 Patch Faces Points Surface topology
faces: 312414 pipe 19778 9938 ok (non-closed singly connected)
internal faces: 291842 inlet1 358 200 ok (non-closed singly connected)
cells: 151064 inlet2 78 50 ok (non-closed singly connected)
faces per cell: 4 outlet 358 200 ok (non-closed singly connected)
boundary patches: 4
point zones: 0 Checking geometry...
face zones: 0 Overall domain bounding box (0 -0.414214 -0.5) (5 5 0.5)
cell zones: 0 Mesh has 3 geometric (non-empty/wedge) directions (1 1 1)
Mesh has 3 solution (non-empty) directions (1 1 1)
Overall number of cells of each type: Boundary openness (-1.0302e-17 -6.17232e-17 -1.77089e-16) OK.
hexahedra: 0 Max cell openness = 2.32045e-16 OK.
prisms: 0 Max aspect ratio = 4.67245 OK.
wedges: 0 Minimum face area = 0.000286852. Maximum face area = 0.010949. Face area magnitudes OK.
pyramids: 0 Min volume = 2.74496e-06. Max volume = 0.00035228. Total volume = 6.75221. Cell volumes OK.
tet wedges: 0 Mesh non-orthogonality Max: 54.2178 average: 15.1295
tetrahedra: 151064 Non-orthogonality check OK.
polyhedra: 0 Face pyramids OK.
Max skewness = 0.649359 OK.
Checking topology... Coupled point location match (average 0) OK.
Boundary definition OK.
Cell to face addressing OK. Mesh OK. Everything is OK
Point usage OK.
Upper triangular ordering OK. End
Face vertices OK.
Number of regions: 1 (OK).

552 553
Mesh conversion Mesh conversion
Case 1. Mixing elbow (internal mesh). Case 1. Mixing elbow (internal mesh).
• The boundary file. • The boundary file.

4 Number of boundary patches 4


( (
pipe
{
Name of the boundary patches pipe
{
type
nFaces
patch;
19778;
type
nFaces
patch;
19778;
Base type of the boundary patches
startFace 291842; • In this case, the utility recognized the startFace 291842;
} }
inlet1 name of the boundary patches. inlet1 • In this case, the utility automatically
{ {
type patch;
• If you do not like the names feel free to type patch; assigned the base type patch to all
nFaces 358; nFaces 358;
startFace 311620; change them. startFace 311620; boundary patches.
} }
inlet2
{ • Remember, do not use spaces of inlet2
{
• Feel free to change the base type
type patch;
strange symbols. type patch; according to your needs.
nFaces 78; nFaces 78;
startFace 311978; startFace 311978;
} } • In this case, it will be wise to change
outlet
{
outlet
{
the base type of patch pipe to wall.
type patch; type patch;
nFaces 358; nFaces 358;
startFace 312056; startFace 312056;
} }
) )

554 555

Mesh conversion Mesh conversion


Case 1. Mixing elbow (internal mesh). Case 1. Mixing elbow (internal mesh).

• Let us convert the tetrahedral mesh to a general polyhedral mesh.


• To do so we use the utility polyDualMesh.
• In the terminal window type:

1. $> polyDualMesh 30 –concaveMultiCells –overwrite –noFunctionObjects

2. $> checkMesh
3. $> paraFoam

• The utility polyDualMesh only works with tetrahedral meshes

556 Tetrahedrons Polyhedrons 557


Roadmap Geometry and mesh manipulation utilities

1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM® • First at all, by mesh manipulation we mean modifying a valid
4. Mesh generation using blockMesh. OpenFOAM® mesh.
5. blockMesh guided tutorials. • These modifications can be scaling, rotation, translation,
6. Mesh generation using snappyHexMesh. mirroring, topological changes, mesh refinement and so on.

7. snappyHexMesh guided tutorials.


8. Mesh conversion
9. Geometry and mesh manipulation utilities
558 559

Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES (use the alias util to go there) you will find the • Let us visit the mesh directory. In the terminal type:
following sub-directories containing the source code for the utilities available in the • $> util
OpenFOAM® installation (version 5.x):
• $> cd mesh
• mesh • $> ls –al
• miscellaneous
• parallelProcessing • In this directory you will find the directories containing the source code for the
following mesh utilities
• postProcessing
• advanced
• preProcessing
• conversion
• surface
• generation
• thermophysical
• manipulation

• In the sub-directory mesh you will find the source code for the mesh utilities in the
OpenFOAM® installation. • In the directory manipulation you will find the source code for the mesh
manipulation utilities. Let us visit this directory, in the terminal type:
• $> cd manipulation
• $> ls -l
560 561
Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES/mesh/manipulation you will find the • Inside each utility directory you will find a *.C file with the same name as
following mesh manipulation utilities: the directory. This is the main file, where you will find the top-level source
• attachMesh • orientFaceZone code and a short description of the utility.
• autoPatch • polyDualMesh • For instance, in the directory checkMesh, you will find the file
• checkMesh • refineMesh checkMesh.C, which is the source code of the utility checkMesh. In the
• createBaffles • renumberMesh source code you will find the following description:
• createPatch • rotateMesh
Checks validity of a mesh.
• deformedGeom • setSet
• flattenMesh • setsToZones Usage
• insideCells • singleCellMesh - checkMesh [OPTION]

• mergeMeshes • splitMesh \param -allGeometry \n


Checks all (including non finite-volume specific) geometry
• mergerOrSplitBaffles • splitMeshRegions
\param -allTopology \n
• mirrorMesh • stitchMesh
Checks all (including non finite-volume specific) addressing
• moveDynamicMesh • subsetMesh
\param -meshQuality \n
• moveEngineMesh • topoSet Checks against user defined (in \a system/meshQualityDict) quality settings
• moveMesh • transformPoints \param -region \<name\> \n
• objToVTK • zipUpMesh Specify an alternative mesh region.

562 Take your time and dig into each directory to get a complete description of each utility. 563

Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
• In OpenFOAM® it is also possible to manipulate the geometries in STL format. • Let us visit the surface directory. In the terminal type:
• In the directory $FOAM_UTILITIES (use the alias util to go there) you will find the • $> util
sub-directories containing the source code for the utilities available in the • $> cd surface
OpenFOAM® installation (version 5.x):

• mesh • In this directory you will find the directories containing the source code for the surface
manipulation utilities.
• miscellaneous
• parallelProcessing
• postProcessing • Let us see what is inside this directory, in the terminal type:
• preProcessing • $> ls -al
• surface
• thermophysical

• In the sub-directory surface you will find the source code for the surface
manipulation utilities in the OpenFOAM® installation.

564 565
Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES/surface you will find the following surface • Inside each utility directory you will find a *.C file with the same name as
manipulation utility sub-directories: the directory. This is the main file, where you will find the top-level source
• surfaceAdd • surfaceMeshExport code and a short description of the utility.
• surfaceAutoPatch • surfaceMeshImport • For instance, in the directory surfaceTransformPoints, you will find the
• surfaceBooleanFeatures • surfaceMeshInfo file surfaceTransformPoints.C, which is the source code of the utility
• surfaceCheck • surfaceMeshTriangulate surfaceTransformPoints. In the source code you will find the following
• surfaceClean • surfaceOrient description:
• surfaceCoarsen • surfacePointMerge
• surfaceConvert • surfaceRedistributePar Transform (scale/rotate) a surface.
• surfaceFeatureConvert • surfaceRefineRedGreen Like transformPoints but for surfaces.
• surfaceFeatureExtract • surfaceSplitByPatch The rollPitchYaw option takes three angles (degrees):
• surfaceFind • surfaceSplitByTopology - roll (rotation about x) followed by
• surfaceHookUp • surfaceSplitNonManifolds - pitch (rotation about y) followed by
• surfaceInertia • surfaceSubset
- yaw (rotation about z)
• surfaceLambdaMuSmooth • surfaceToPatch
The yawPitchRoll does yaw followed by pitch followed by roll.
• surfaceMeshConvert • surfaceTransformPoints
• surfaceMeshConvertTesting
566 Take your time and dig into each directory to get a complete description of each utility. 567

Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• Let us do some surface manipulation. • We will now manipulate a STL geometry. In the terminal type:

• For this we will use the ahmed body tutorial located in 1. $> foamCleanTutorials
the directory: 2. $> surfaceMeshInfo ./constant/triSurface/ahmed_body.stl
3. $> surfaceCheck ./constant/triSurface/ahmed_body.stl
$> surfaceTransformPoints -rollPitchYaw '(0 0 15)’
$PTOFC/mesh_quality_manipulation/M5_ahmed_body_transform 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
• From this point on, please follow me. 7. ./constant/triSurface/ahmed_body.stl
• We are all going to work at the same pace. 8.
$> surfaceOrient ./constant/triSurface/ahmed_body_wrong_normals.stl
out.stl ‘(1e10 1e10 1e10)’
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
568 569
Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM® Geometry manipulation in OpenFOAM®
• In step 2 we use the utility surfaceMeshInfo to get general information about the STL (such • Pay particular attention to step 8.
as number of faces and so on). • We already have seen that snappyHexMesh computes surface angles using the surface
• In step 3 we use the utility surfaceCheck to check the STL file. normals as a reference, so it is extremely important to have the normals oriented in the same
• In step 4 we use the utility surfaceTransformPoints to rotate the STL. We read in the STL way and preferably outwards.
./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
ahmed_body_wrong_normals.stl STL after orienting all normals in the same
this point is outside the STL all normals will be oriented outwards, if the point is inside the STL direction.
all normals will be oriented inwards.
570 571

Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• To plot the normals in paraview/paraFoam you can use the filter Normal Glyphs • We will now do some mesh manipulation.
Select the Normal Glyphs from the filter menu

• For this we will use the heated body tutorial located in


the directory:
Apply the Normal Glyphs
filter to the STL

$PTOFC/mesh_quality_manipulation/M7_cylinder_transform

Uncheck this option

Scale the vectors to fit the screen


• From this point on, please follow me.
• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
572 573
Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Mesh manipulation in OpenFOAM® Mesh manipulation in OpenFOAM®
• We will now manipulate a mesh. In the terminal type: • 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
1. $> foamCleanTutorials by a factor of '(0.01 0.01 0.01)'.
2. $> blockMesh • In step 5 we use the utility transformPoints to translate the mesh. We translate
the mesh by the vector '(0 0 1)'.
3. $> transformPoints -rollPitchYaw '(0 0 90)'
• In step 6 we use the utility createPatch to rename the patches of the mesh. This
4. $> transformPoints -scale '(0.01 0.01 0.01)' utility reads the dictionary system/createPatchDict. Instead of using the utility
5. $> transformPoints -translate '(0 0 1)' createPatch we could have modified the boundary file directly.
6. $> createPatch -noFunctionObjects –overwrite • This case is ready to run using the solver buoyantBoussinesqPimpleFoam.

7. $> checkMesh
8. $> paraFoam

574 575

Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Mesh manipulation in OpenFOAM® Mesh manipulation in OpenFOAM®

Original mesh Transformed 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

576 577
Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Mirroring a mesh in OpenFOAM®
• Let us mirror a mesh.
• For this we will use the wing body tutorial located in
the directory:

$PTOFC/mesh_quality_manipulation/M1_wingbody

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you Original mesh/domain Mirrored mesh/domain
unpacked the tutorials.
578 579

Geometry and mesh manipulation utilities Geometry and mesh manipulation utilities
Mirroring a mesh in OpenFOAM® Mirroring a mesh in OpenFOAM®
• We will mirror a mesh. In the terminal type: • Step 4, will create the cellSet that we will use with subsetMesh. It reads the
dictionary system/topoSetDict
• In step 5, we use the set newcells created with topoSet to create a new polyMesh.
1. $> foamCleanTutorials The new polyMesh will not contain the unusedPoints.
2. $> fluent3DMeshToFoam ../../meshes_and_geometries/fluent_wingbody/ascii.msh • It steps 4 and 5 we simply removed faulty sets.
3. $> checkMesh • In step 6, we mirror the mesh after removing some faulty sets. The utility
$> topoSet –dict system/topoSetDict1 mirrorMesh will read the dictionary mirrorMeshDict located in the directory
4.
system. In this dictionary we define the base point for the mirror plane and the
5. $> subsetMesh newcells -overwrite vector normal to the mirror plane.
6. $> mirrorMesh –noFunctionObjects
7. $> checkMesh
8. $> paraFoam

580 581
Roadmap

Module 4
1. Running in parallel - Running in a cluster
Running in parallel using a job scheduler

582 583

Running in parallel Running in parallel


• First at all, to know how many processors/cores you have available in your computer, • OpenFOAM® does not take advantage of hyper threading technology (HT).
type in the terminal: • HT is basically used by the OS to improve multitasking performance.
• $> lscpu
• This is what we have in the workstation of the previous example:
• The output for this particular workstation is the following: • 24 virtual cores (hyper threaded)
Architecture: x86_64
• 12 physical cores
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:
Thread(s) per core:
0-23
2
• To take full advantage of the hardware, we use the maximum number of physical
Core(s) per socket:
Socket(s):
6
2
Number of threads per core (hyper threading) cores (12 physical cores in this case) when running in parallel.
NUMA node(s): 2
Vendor ID: GenuineIntel Number of cores per socket or physical
• If you use the maximum number of virtual cores, OpenFOAM® will run but it will be
CPU family:
Model:
6
44
processor slower in comparison to running with the maximum number of physical cores (or even
Model name:
Stepping:
Intel(R) Xeon(R) CPU
2
X5670 @ 2.93GHz
Number of sockets (physical processors)
less cores).
CPU MHz: 1600.000
CPU max MHz: 2934.0000 • Same rule applies when running in clusters/super computers, so always read the
CPU min MHz:
BogoMIPS:
1600.0000
5851.91 hardware specifications to know the limitations.
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


584 585
Running in parallel Running in parallel
Why use parallel computing? Speed-up and scalability example
• 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.
• In the context of high performance computing (HPC), there are two common metrics that measure the scalability
• Save money: of the application:
• Strong scaling (Amdahl’s law): which is defined as how the solution time varies with the number of
In theory, throwing more resources at a task will shorten its time to completion, with potential cost processors for a fixed problem size (number of cells in CFD)
savings. Parallel computers can be built from cheap, commodity components.
• 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
• Limits to serial computing: processors).
Both physical and practical reasons pose significant constraints to simply building ever faster serial • In this example, when we reach 12 cores inter-processor communication slow-downs the computation. But if we
computers (e.g, transmission speed, CPU clock rate, limits to miniaturization, hardware cooling). 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
586 MPI library. 587

Running in parallel Running in parallel


• The method of parallel computing used by OpenFOAM® is known as domain Some facts about running OpenFOAM® in parallel:
decomposition, in which the geometry and associated fields are broken into pieces
and distributed among different processors. • 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).

Shared memory architectures – Workstations and portable computers • We have been able to run in parallel up to 14000 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.
Distributed memory architectures – Clusters and super computers • And of course, to run in parallel you need the hardware.
588 589
Running in parallel Running in parallel
To run OpenFOAM® in parallel you will need to: Domain Decomposition in OpenFOAM®
• The mesh and fields are decomposed using the decomposePar utility.
• Decompose the domain. • 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.
To do so we use the decomposePar utility. You also need the dictionary
decomposeParDict which is located in the system directory. • 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.
• 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 numberOfSubdomains 128; Number of subdomains
of the decomposed domain. method scotch; Decomposition method

• Additionally, you might want to reconstruct (put back together) the


decomposed domain.
• In this example, we are subdividing the domain in 128 subdomains, therefore we
This is done by using the reconstrucPar utility. You do not need a should have 128 physical cores available.
dictionary to use this utility.
• The main goal of domain decomposition is to minimize the inter-processors
590 communication and the processor workload. 591

Running in parallel Running in parallel


Domain Decomposition Methods Running in parallel – Gathering all together
• These are the decomposition methods available in OpenFOAM® 5.x
• hierarchical The information inside the
directories polyMesh/ and
• manual 0/ is decomposed using the
utility decomposePar
• metis
• multiLevel decomposePar
• 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

processor0 processor1 processor2 processor3


• If you want more information about each decomposition method, just read
the source code:
• $WM_PROJECT_DIR/src/parallel/decompose/ • Inside each processorN directory you will have the mesh information, boundary conditions,
initial conditions, and the solution for that processor.
592 593
Running in parallel Running in parallel
Running in parallel – Gathering all together Running in parallel – Gathering all together
• After decomposing the mesh, we can run in parallel using MPI. • 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

$> mpirun –np <NPROCS> <application/utility> –parallel • When you reconstruct the case, you glue together
all the information contained in the decomposed
case.
• The number of processors to use or <NPROCS>, needs to be the same as the • All the information (mesh, boundary conditions,
number of partitions (numberOfSubdomains). initial conditions, and the solution), is transfer to
• Do not forget to use the flag –parallel. the original case folder (polyMesh and time
solution directories).
594 595

Running in parallel Running in parallel


Running in parallel – Gathering all together Kelvin Helmholtz instability in a coarse mesh
• Summarizing, to run in parallel we proceed in the following way:

1. $> decomposePar Processors Clock time (seconds)


Mesh size
in x, y, and z directions
2. $> mpirun –np <NPROCS> <application/utility> –parallel
1 955 800 X 160 X 1
3. $> reconstructPar
2 564 800 X 160 X 1

4 333 800 X 160 X 1

• You can do the post-processing and visualization on the decomposed case 8 234 800 X 160 X 1
or reconstructed case. We are going to address this later on.
12 244 800 X 160 X 1

• If you are doing remeshing or using AMR you will need to use
reconstructParMesh before reconstrucPar. Volume fraction
www.wolfdynamics.com/wiki/kelvin_helmholtz/ani1.gif

596 You will find this case in the directory: $PTOFC/parallel/kelvin_helmholtz 597
Running in parallel Running in parallel
Comparison of the Kelvin Helmholtz instability in a coarse and fine mesh 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.

Cells 200 X 40 X 1 Cells 3200 X 640 X 1 • In step 2, we use paraFoam to visualize the reconstructed case.

598 599

Running in parallel Running in parallel


Visualization of a parallel case Visualization of a parallel case

• An alternative way to visualize the solution, is by proceeding in the following • Both of the previous methods are valid.
way • When we use the option –builtin with paraFoam, we have the option to
• $> paraFoam –builtin work on the decomposed case directly.
• That is to say, we do not need to reconstruct the case.
• The option –builtin let us post-process the decomposed case directly. • But wait, there is a third option.
• Remember, you will need to select on the object inspector the Decomposed • The third option consist in post-processing each decomposed domain
Case option. 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.

600 601
Running in parallel Running in parallel
Decomposing big meshes Do all utilities run in parallel?
• One final word, the utility decomposePar does not run in parallel. So, it is • At this point, you might be wondering if all solvers/utilities run in parallel.
not possible to distribute the mesh among different computing nodes to do
• To know what solvers/utilities do not run in parallel, in the terminal type:
the partitioning in parallel.
• $> find $WM_PROJECT_DIR -type f | xargs grep –sl ‘noParallel’
• Paradoxically, the utilities used to decompose the domain and reconstruct the
• If you need to partition big meshes, you will need a computing node with domain do not run in parallel.
enough memory to handle the mesh. We have been able to decompose
• Another important utility that does not run in parallel is blockMesh. So to generate
meshes with up to 500.000.000 elements, but we used a computing node big meshes with blockMesh you need to use a big fat computing node.
with 512 gigs of memory.
• Another important utility that does not run in parallel by default is paraFoam.
• To compile paraFoam with MPI support, in the file makeParaView4 (located in the
• For example, in a computing node with 16 gigs of memory, it is not possible directory $WM_THIRD_PARTY_DIR), set the option withMPI to true,
to decompose a mesh with 30.000.000. You will need to use a computing • withMPI = true
node with at least 32 gigs of memory.
• While you are working with the file makeParaView4, you might consider enabling
Python support,
• Same applies for the utility reconstructPar. • withPYTHON = true

602 603

Running in parallel Running in parallel


• To launch a job in a cluster with PBS, you will need to write a small shell script where
Running in a cluster using a job scheduler you tell to the job scheduler the resources you want to use and what you want to do.
• Running OpenFOAM® in a cluster is similar to running in a normal • Ask the system administrator about how to write these scripts.
workstation with shared memory.
#!/bin/bash
• The only difference is that you will need to launch your job using a job #
scheduler. # Simple PBS batch script that reserves 16 nodes and runs a
# MPI program on 128 processors (8 processor on each node)
• Common job schedulers are: # The walltime is 24 hours !
#
• Terascale Open-Source Resource and Queue Manager (TORQUE). #PBS -N openfoam_simulation //name of the job
#PBS -l nodes=16,walltime=24:00:00 //max resources and execution time
• Simple Linux Utility for Resource Management (SLURM). #PBS -m abe -M joel.guerrero@unige.it //send an email as soon as the job
//is launch or terminated
• Portable Batch System (PBS).
cd PATH_TO_DIRECTORY //go to this directory
• Sun Grid Engine (SGE).
• Maui Cluster Scheduler. decomposePar //decompose the case

• BlueGene LoadLeveler (LL). mpirun –np 128 pimpleFoam -parallel > log //run parallel solver

• Ask your system administrator the job scheduler installed in your system.
Hereafter we will assume that you are using PBS. The green lines are not PBS comments, they are comments inserted in this slide. PBS comments use the number
sign (#).
604 605
Running in parallel Running in parallel
• To launch your job you need to use the qsub command (part of the PBS job • Finally, remember to always plan how you will use the resources available.
scheduler). The command qsub will send your job to queue. • For example, if each computing node has 8 gigs of memory available and 8 cores.
You will need to distribute the work load in order not to exceed the maximum
resources available per computing node.
• $> qsub script_name
• So if you are running a simulation that requires 32 gigs of memory, the following
options are valid:
• Remember, running in a cluster is no different from running in your
• Use 4 computing nodes and ask for 32 cores. Each node will use 8 gigs of
workstation or portable computer. The only difference is that you need to
memory and 8 cores.
schedule your jobs.
• Use 8 computing nodes and ask for 32 cores. Each node will use 4 gigs of
memory and 4 cores.
• Depending on the system current demand of resources, the resources you • Use 8 computing nodes and ask for 64 cores. Each node will use 4 gigs of
request and your job priority, sometimes you can be in queue for hours, even memory and 8 cores.
days, so be patient and wait for your turn. • But the following options are not valid:
• Use 2 computing nodes. Each node will need 16 gigs of memory.
• Remember to always double check your scripts. • Use 16 computing nodes and ask for 256 cores. The maximum number of cores
for this job is 128.

606 607

Roadmap

1. Sampling with the postProcess utility


2. Probing with the postProcess utility

Module 5 3. On-the-fly postprocessing – functionObjects and the


postProcess utility
The postprocess utility – Sampling – Probing 4. Field manipulation
– On-the-fly postprocessing – Field 5. Co-processing
manipulation – Coprocessing – Data 6. Data conversion
7. foamLog
conversion

608 609
Sampling with the postProcess utility Sampling with the postProcess utility
• OpenFOAM® provides the postProcess utility to sample field data for
plotting.
• The sampling locations are specified in the a dictionary located in the case
• Let us do some sampling.
system directory. You can give any name to the input dictionary, hereafter • For this we will use the 3D pipe case, which you will
we are going to name it sampleDict.
find in the directory:
• During the sampling, inside the case directory a new directory named
postProcessing, will be created. In this directory, the sampled values are
stored. $PTOFC/postprocessing/pipe/
• 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 • From this point on, please follow me.
case directory and according to the application syntax. • We are all going to work at the same pace.
• A final word, this utility does not do the sampling while the solver is running. • Remember, $PTOFC is pointing to the path where you
It does the sampling after you finish the simulation. unpacked the tutorials.
610 611

Sampling with the postProcess utility Sampling with the postProcess utility
Laminar flow in a straight pipe – Re = 600 Laminar flow in a straight pipe – Re = 600

Velocity magnitude at the outlet Pressure contours at the wall

Mesh and domain


612 613
Sampling with the postProcess utility Sampling with the postProcess utility
Laminar flow in a straight pipe – Re = 600 Laminar flow in a straight pipe – Re = 600

Surface type and location Coarse and fine surfaces

Point and lines where we want to sample

614 615

Sampling with the postProcess utility Sampling with the postProcess utility
Laminar flow in a straight pipe – Re = 600 What are we going to do?

• We will simulate a laminar flow in a straight pipe (Re = 600).


• We will use this case to introduce the sampling utility postProcess.
• We will introduce the utility topoSet, used to do topological modifications
on the mesh.
• We will use this utility to run functionObjects a-posteriori.
• We will compare the numerical solution with the analytical solution.
• To find the numerical solution we will use the solver pisoFoam.
• 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.
We can also sample in arbitrary surface

616 617
Sampling with the postProcess utility Sampling with the postProcess utility
Running the case Running the case

• Let us run the simulation and do some sampling. In the terminal type: • In step 4 we use the utility topoSet to do mesh topological manipulation.
This utility will read the dictionary topoSetDict located in the system
$> foamCleanTutorials
directory. Later on, we will talk about what are we doing in this step.
1.
$> blockMesh
• In step 5 we run the simulation and save the log file.
2.
$> checkMesh
• In step 6 we use the postProcess utility. By using the option –func we
3.
specify to do the sampling according to the dictionary
4. $> topoSet system/sampleDict1. We sample the latest saved solution.
5. $> pisoFoam | tee log • In step 7 we use the postProcess utility. By using the option –func we
6. $> postProcess -func sampleDict1 -latestTime specify to do the sampling according to the read dictionary
7. $> postProcess -func sampleDict2 -latestTime system/sampleDict2. We sample the latest saved solution.
8. $> gnuplot gnuplot/gnuplot_script • In step 8 we use the gnuplot script gnuplot/gnuplot_script to plot the
sampled fields. Feel free to take a look at the script and to reuse it.
9. $> paraFoam
• Finally, in step 9 we visualize the solution.

• Do not erase the solution, we are going to use it in the next sections.
618 619

Sampling with the postProcess utility Sampling with the postProcess utility
The sampleDict dictionary The sampleDict1 dictionary
Sample sets (points and lines).
• Let us visit the sampleDict dictionaries. Format of the output file, raw format is a generic format that can be
read by many applications. The file is human readable (ascii
• This dictionary is located in the directory system. 17
18
type sets;
format).
19 setFormat raw;

• The sampleDict file contains several entries to be set according to the


20
21 interpolationScheme cellPointFace;
Interpolation method at the solution level (location of the
22 interpolation points).
user needs. 24
25
fields
(
26 U
Fields to sample.
• You can set the following entries, 27
28 );
p

29

• The choice of the interpolationScheme. 30


31
sets
(
32
Name of the output file
• The format of the line data output. 33
34
s1
{
35 type midPointAndFace; Sample method from the solution to the line.
• The format of the surface data output. 40
41
axis
start
z;
(0 0 0); Location of the sample line. We define start and end point, and the
42 end (0 0 0.22);
axis of the sampling.
• The fields to be sample.
43 }
44
45 s2 Name of the output file
46 {
• The sub-dictionaries that controls each sampling operation. 47
49
type
axis
midPointAndFace;
x;
Sample method from the solution to the line.
50 start (-0.002 -0.002 0.2); Location of the sample line. We define start and end point, and the
• In these sub-dictionaries you can set the name, type and 51
52 }
end ( 0.002 0.002 0.2); axis of the sampling.

geometrical information of the sampling operation. 53


Note:
Use the banana method to know all the options
• In this case, in the dictionary sampleDict1 we are sampling points and available.
lines, and in the dictionary sampleDict2 we are sampling surfaces. 620 621
Sampling with the postProcess utility Sampling with the postProcess utility
The sampleDict1 dictionary The sampleDict2 dictionary
Sample surfaces.
53 Format of the output file, raw format is a generic format that
54 somePoints Name of the output file can be read by many applications. The file is human readable
55 { 17 type surfaces;
56 type cloud; Sample a cloud of points 18 (ascii format).
57 axis xyz; 19 surfaceFormat raw;
20
58 points
21 interpolationScheme cell;
Interpolation method at the solution level (location of the
59 (
60 (0 0 0.05) 22 interpolation points).
61 (0 0 0.1) 26 fields
62 (0 0 0.15)
Location of the sample points. 27 (
28 U
63 (0 0 0.2)
29 p Fields to sample.
64 );
65 } 30 );
66 ); 31
67 32 surfaces
The sampled information is always saved in the directory 33 (
34 surf1 Name of the output file
35 {
postProcessing/sampleDict1 36 type plane;
37 normalVector (0 0 1); Surface sampling method. In this case we are using an
As we are sampling the latest solution (0.1), the sampled data 38 basePoint (0 0 0.1); infinite plane.
39 }
will be located in the directory: 40
41 surf2 Name of the output file
postProcessing/sampleDict1/0.1 42 {
43 type cuttingPlane;
44 planeType pointAndNormal;
45 pointAndNormalDict
46 {
The files s1_p.xy, s2_p.xy, s1_U.xy, s2_U.xy, 47 basePoint (0 0 0.1); Surface sampling method. In this case we are using a cutting
somePoints_p.xy, and somePoints_U.xy located in the 48
49 }
normalVector (0 0 1);
plane. The interpolate option means that we interpolate the
directory postProcessing/sampleDict1/0.1 contain the 50 cell centered values to the surface triangulation.
51 interpolate true;
sampled data. Feel free to open the output files using your 52 }
favorite text editor. 53

622 623

Sampling with the postProcess utility Sampling with the postProcess utility
The sampleDict2 dictionary The output files

53
Name of the output file
54
55
surf3
{ • The output format of the point sampling (cloud) is as follows:
56 type sampledTriSurfaceMesh; Surface sampling method. In this case we are using a STL
57 surface surface2.stl;
58 source cells; file, the file is always located in the directory
59
60 interpolate true;
constant/triSurface. Scalars
61 }
62
63 surf4 Name of the output file
64 { #POINT_COORDINATES (X Y Z) SCALAR_VALUE
65 type sampledTriSurfaceMesh; Surface sampling method. In this case we are using a STL
66 surface surface3.stl; 0 0 0.05 13.310995
file, the file is always located in the directory
67
68
source insideCells;
constant/triSurface. 0 0 0.1 19.293817
69 interpolate false; …
70 }
71 ); The sampled information is always saved in the directory
postProcessing/sampleDict2
As we are sampling the latest solution (0.1), the sampled data Vectors
will be located in the directory:
postProcessing/sampleDict2/0.1
#POINT_COORDINATES (X Y Z) VECTOR_COMPONENTS (X Y Z)
The files p_surf1.raw, p_surf2.raw, p_surf3.raw, 0 0 0.05 0 0 2.807395
p_surf4.raw, U_surf1.raw, U_surf2.raw, 0 0 0.1 0 0 2.826176
U_surf3.raw, and U_surf4.raw, located in the directory …
postProcessing/sampleDict2/0.1 contain the sampled
data. Feel free to open the output files using your favorite text
editor.
624 625
Sampling with the postProcess utility Sampling with the postProcess utility
The output files The output files

• The output format of the line sampling is as follows: • The output format of the surface sampling is as follows:

Scalars Scalars

#AXIS_COORDINATE SCALAR_VALUE #POINT_COORDINATES (X Y Z) SCALAR_VALUE


0 18.594038 0 0 0.05 13.310995
0.0015 18.249091 0 0 0.1 19.293817
… …

Vectors Vectors

#AXIS_COORDINATE VECTOR_COMPONENTS (X Y Z) #POINT_COORDINATES (X Y Z) VECTOR_COMPONENTS (X Y Z)


0 0 0 1.6152966 0 0 0.05 0 0 2.807395
0.0015 0 0 1.8067536 0 0 0.1 0 0 2.826176
… …

626 627

Sampling with the postProcess utility Sampling with the postProcess utility
• To plot the sampled data using gnuplot we can proceed as follows: • To plot the sampled data using gnuplot we can proceed as follows:
1. gnuplot> set title 'Radial velocity at z=0.2 - Time 0.1 s' 1. gnuplot> set title 'Velocity profile at plane located at z = 0.1 - Time 0.1 s'

2. gnuplot> set xlabel 'Diameter' 2. gnuplot> set xlabel 'X'

3. gnuplot> set ylabel 'Y'


3. gnuplot> set ylabel 'U_z'
4. gnuplot> set zlabel 'U_z'
4. gnuplot> set grid
5. gnuplot> set grid
5. gnuplot> plot [][] 'postProcessing/sampleDict1/0.1/s2_U.xy' u 1:4 w p pt 7 title "Numerical
solution", 2.8265544*(1-x**2/(0.0010606602 )**2) title "Analytical solution" 6. gnuplot> splot [][][] 'postProcessing/sampleDict/0.1/U_surf1.raw' u 1:2:6 pt 7 ps 0.5

628 629
Sampling with the postProcess utility Sampling with the postProcess utility
Creating faceSet and zoneSet The topoSetDict dictionary

• To create sets and zones we use the utility topoSet. 17


18
actions
(
19
• This utility reads the dictionary topoSetDict located in the system directory. 20 { • In this step we are creating a new faceSet from a boxToFace
21 action new; source.
22 name internalfaces;
• The name of the new faceSet is internalFaces.
• faceSet/cellSet and faceZone/cellZone can be used to do modifications to the 23
24
type faceSet;
• The box source encloses the faces we want to tag.
mesh or to apply source terms. 25
26
source boxToFace;
sourceInfo
• We can visualize this set in paraFoam.
27 { • Remember, we can not sample on a faceSet, we need to
• We can only do sampling operations on zoneSets made of a set of faces and/or 28
29 }
box (-1 -1 0.098) (1 1 0.1); convert it to a faceZone.
cells, therefore, if we have a faceSet/cellSet we need to convert it to a 30
31
}

faceZone/cellZone. 32
33
{
action new;
34 name internalfacepatch;
• In this step we convert the faceSet internalFaces, to a
• Creating an internal faceZone is particularly important if we are interested in 35
36
type faceZoneSet;
faceZone.
computing the mass flow in an internal surface, as sampledSurface does not work 37
38
source setToFaceZone;
sourceInfo
• The name of new faceZone is internalfacepatch.
• At this point, we can use this faceZone to do sampling.
with surfaceScalarFields, therefore we need to use a faceZone. Alternatively, we 39
40
{
faceSet internalfaces; • We can visualize this zone in paraFoam.
can compute the mass flow in paraFoam/paraView or we can use the
41 }
42 }
43
areaNormaIntegrate operation on the sampleSurface.
• Let us create an internal faceZone and a cellZone and let us compute the mass flow
and do some sampling on these sets.
Note:
Use the banana method to know all the options
available.
630 631

Sampling with the postProcess utility Sampling with the postProcess utility
The topoSetDict dictionary • Let us create an internal faceZone and a cellZone and let us compute the mass flow
and do some sampling on these sets.
44 {
45 action new; • In this step we are creating a new cellSet from a boxToCell
46 name internalcells; source.
47
48
type cellSet;
• The name of the new cellSet is internalCells. 1. $> topoSet
49 source boxToCell; • The box source encloses the cells we want to tag.
50
51
sourceInfo
{
• We can visualize this set in paraFoam. 2. $> pisoFoam -postProcess -dict system/functionobject3 –latestTime
52 box (-1 -1 0.096) (1 1 0.1); • Remember, we can not sample on a cellSet, we need to
53
54 }
} convert it to a cellZone. 3. $> pisoFoam -postProcess -dict system/functionobject4 -latestTime
55
56 {
57 action new;
58 name internalcells;
59 type cellZoneSet;
60 • In this step we convert the cellSet internalcells, to a cellZone.
61
62
source setToCellZone;
sourceInfo • The name of new cellZone is internalcells. • In step 1 we use the utility topoSet to create the new faceZone and cellZone.
63 { • At this point, we can use this cellZone to do sampling.
64
65 }
set internalcells;
• We can visualize this set in paraFoam. • In step 2 we run a functionObject a-posteriori. In this functionObject we compute:
66 }
67
68 );
• Mass flow in a sampledSurface.
• Mass flow in a faceZone.
• In step 3 we run a functionObject a-posteriori. In this functionObject we compute:
• Volume integral in a cellZone.
Note:
Use the banana method to know all the options
available.
632 633
Sampling with the postProcess utility Sampling with the postProcess utility
Visualizing the newly created sets and zones The functionobject3 dictionary
17 functions
18 {
19
21 surface1_massflow
22 {
23 type surfaceRegion;
24 functionObjectLibs ("libfieldFunctionObjects.so");
25 enabled true;
26
27 writeControl timeStep;
28 writeInterval 1;
Check the option Include Sets cellZone - In white 29
to visualize the sets 30 log true;
31 writeFields false;
32
33 regionType sampledSurface;
34 Name dummy;
35
36 sampledSurfaceDict
37 {
38 type sampledTriSurfaceMesh;
39 surface surface1.stl;
Check the option Include Zones 40 source cells;
41 interpolate false;
to visualize the zones 42 }
43
54
55
operation
fields
areaNormalIntegrate;
• Compute mass flow using areaNormalIntegrate
faceZone - In red 56 ( operation with the field U.
57 U
58
59
);
• Using the operation sum with the field phi, will not
60 } work because phi is a surfaceScalarField.

Select the sets you want to visualize


(faceSet, faceZone, cellSet or cellZone)
634 635

Sampling with the postProcess utility Sampling with the postProcess utility
The functionobject3 dictionary The functionobject3 dictionary
64 surface2_massflow
65 {
66 type surfaceRegion;
67 functionObjectLibs ("libfieldFunctionObjects.so"); 90 surface3_massflow
68 enabled true; 91 {
69 92 type surfaceRegion;
70 writeControl timeStep; 93 functionObjectLibs ("libfieldFunctionObjects.so");
71 writeInterval 1; 94 enabled true;
72 95
73 log true; 96 writeControl timeStep;
74 writeFields false; 97 writeInterval 1;
75 98
76 regionType faceZone; 99 log true;
77 name internalfacepatch; 100 writeFields false;
78 101
79 operation sum; 102 regionType sampledSurface;
80 fields 103 name dummy;
81 ( 104
82 phi 105 sampledSurfaceDict
83 ); 106 {
84 107 type sampledTriSurfaceMesh;
85 } 108 surface surface2.stl;
109 source cells;
In this case we are using a finer surface therefore we
• Compute mass flow using sum operation with the 110 interpolate true;
111 } enable the option interpolate.
field phi. 112
113 operation areaNormalIntegrate;
• In this case it works because we are sampling on 114 fields

a faceZone.
115
116
(
U
Compute mass flow using areaNormalIntegrate
117 ); operation with the field U.
• The faceZone are internal faces of the mesh. 118
119 }

636 637
Sampling with the postProcess utility Sampling with the postProcess utility
The functionobject3 dictionary The functionobject3 dictionary
123 surface4_massflow 156 plane1_massflow
124 { 157 {
125 type surfaceRegion; 158 type surfaceRegion;
126 functionObjectLibs ("libfieldFunctionObjects.so"); 159 functionObjectLibs ("libfieldFunctionObjects.so");
127 enabled true; 160 enabled true;
128 161
129 writeControl timeStep; 163 writeControl timeStep;
130 writeInterval 1; 164 writeInterval 1;
131 165
132 log true; 166 log true;
133 writeFields false; 167 writeFields false;
134 168
135 regionType sampledSurface; 169 regionType sampledSurface;
136 name dummy; 170 name dummy;
137 171
138 sampledSurfaceDict 172 sampledSurfaceDict
139 { 173 {
140 type sampledTriSurfaceMesh; 174 type plane;
141 surface surface3.stl; 175 normalVector (0 0 1); We sample in a plane.
142 source insideCells; 176 basePoint (0 0 0.1);
143 interpolate true; 177 }
144 } 178
145 180 operation areaNormalIntegrate;
146 operation areaNormalIntegrate; 181 fields
147 fields 182 (
148 ( 183 //phi
149 U Compute mass flow using areaNormalIntegrate 184 U Compute mass flow using areaNormalIntegrate
150
151
);
operation with the field U. 185
186 }
);
operation with the field U.
152 } 188
189 }

638 639

Sampling with the postProcess utility Roadmap


The functionobject4 dictionary
17
18
functions
{
1. Sampling with the postProcess utility
19
22
23
24
cells_fo1
{
type volRegion;
2. Probing with the postProcess utility
25 functionObjectLibs ("libfieldFunctionObjects.so");
26
27
enabled true;
3. On-the-fly postprocessing – functionObjects and the
postProcess utility
28 writeControl timeStep;
29 writeInterval 1;
30
31 log true;
32
33
34
writeFields false; 4. Field manipulation
35 regionType cellZone;
36
37
name internalcells;
5. Co-processing
38 operation volIntegrate;
39
40
41
fields
(
6. Data conversion
42 U Compute volIntegrate of the field U.
43
44
);
7. foamLog
45 }
97
98 }
99

Remember, we can do cellSource and faceSource


sampling only on cellZone/faceZone.

640 641
Probing with the postProcess utility Probing with the postProcess utility
• OpenFOAM® provides the postProcess utility to probe field data for Laminar flow in a straight pipe – Re = 600
plotting.
• The probing locations are specified in the a dictionary located in the case
system directory. You can give any name to the input dictionary, hereafter
we are going to name it probesDict.
• During the probing, inside the case directory a new directory named
postProcessing, will be created. In this directory, the sampled values are
stored.
• This utility can sample only points.
• Data can be written in a range of formats including well-known plotting
packages such as: grace/xmgr, gnuplot and jPlot.
• The probing 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. Probes location

642 643

Probing with the postProcess utility Probing with the postProcess utility
• We hope you did not erase the previous solution because we will use it to play The probesDict dictionary
around with the probeLocations. In the terminal type:

17 type probes;

1. $> postProcess -func probesDict 18


20 fields
21 (
22 p
23 U Fields to sample. The output files will have the name of the fields.
24 );
• This will probe all the saved solutions at the specified locations. It will save time vs. 25
27 probeLocations
quantity of interest. 28
29
(
(0 0 0.025)
30 (0 0 0.050)
31 (0 0 0.075)
32 (0 0 0.10) Probe locations.
33 (0 0 0.125)

• The sampled information is always saved in the directory 34


35
(0 0 0.150)
(0 0 0.175)
36 (0 0 0.20)
• postProcessing/probesDict 37 );

• As we started to sample from time 0, the sample data is saved in the directory
• postProcessing/probesDict/0

• The files p, and U, located in the directory postProcessing/probesDict/0


contain the sampled data. Feel free to open them using your favorite text editor.
644 645
Probing with the postProcess utility Probing with the postProcess utility
The output files The output files

• The output format of the probing is as follows: • The output format of the probing is as follows:

Scalars Vectors

# Probe 0 (0 0 0.025) # Probe 0 (0 0 0.025)


# Probe 1 (0 0 0.05) # Probe 1 (0 0 0.05)
# Probe 2 (0 0 0.075) # Probe 2 (0 0 0.075)
# Probe 3 (0 0 0.1) # Probe 3 (0 0 0.1)
# Probe 0 1 2 3 # Probe 0 1 2 3
# Time # Time
0 0 0 0 0 0 (0 0 0) (0 0 0) (0 0 0) (0 0 0)
0.005 19.1928 16.9497 14.2011 11.7580 0.005 (0 0 2.1927) (0 0 2.1927) (0 0 2.1927) (0 0 2.1927)
0.01 16.6152 14.5294 12.1733 10.0789 0.01 (0 0 2.5334) (0 0 2.5334) (0 0 2.5334) (0 0 2.5334)
… …
… …
… …

646 647

Roadmap On-the-fly postprocessing – functionObjects


• It is possible to perform data extraction/manipulation operations while the
simulation is running by using the functionObjects.
1. Sampling with the postProcess utility
• functionObjects are small pieces of code executed at a regular interval
2. Probing with the postProcess utility without explicitly being linked to the application.
3. On-the-fly postprocessing – functionObjects and the • When using functionObjects, files of sampled data can be written for
postProcess utility plotting and post processing.
• functionObjects are specified in the controlDict dictionary and executed
4. Field manipulation every time step or pre-defined intervals.
5. Co-processing • All functionObjects are runtime modifiable.
6. Data conversion • All the information related to the functionObject is saved in the directory
postProcessing or in the solution directory.
7. foamLog
• It is also possible to execute functionObject after simulation is over, we will
call this running functionObject a-posteriori.

648 649
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects

• Let us revisit the pipe case. Go to the directory:

$PTOFC/postprocessing/pipe

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials. Mesh and domain

650 651

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


What are we going to do? Running the case

• We will use this case to introduce functionObjects. • Let us run the simulation. In the terminal type:
• We will use the utility postProcess, to run functionObjects a-posteriori.
• We will also use the utility postProcess, to compute some quantities in patches.
1. $> foamCleanTutorials
• We will compare the numerical solution with the analytical solution.
2. $> blockMesh
• We will do data cleaning and data analytics using shell scripting. $> checkMesh
3.
• To find the numerical solution we will use the solver pisoFoam. $> topoSet
4.
• After finding the numerical solution we will do some sampling. 5. $> pisoFoam > log &
• At the end, we will do some plotting (using gnuplot or Python) and scientific 6. $> pyFoamPlotWatcher.py log
visualization.
7. $> paraFoam

652 653
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects
Running the case • Let us explore the case directory.
• You will notice that we now have a new directory named postProcessing.
• In step 4 we use the utility topoSet to do mesh topological manipulation.
This utility will read the dictionary topoSetDict located in the system • Inside this directory, you will find many subdirectories pointing to the
directory. Later on, we will talk about what are we doing in this step. functionObject used.
• In step 5 we run the simulation and save the log file. Notice that we are • By the way, we are saving a large amount of information.
sending the job to background.
• This is typical of unsteady simulations, and sometimes it can be too daunting
• In step 6 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. to post-process and analyze the data.
As the job is running in background, we can launch this utility in the same
terminal tab. • To ease the pain of doing data analytics and post-processing, you can use
shell scripting or Python scripting.
• Finally, in step 7 we visualize the solution.
• Hereafter, we are going to address how to use shell scripting.

654 655

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


• Inside the directory postProcessing, you will find the following sub- • Inside each sub-directory you will find the time directory 0, this is the time
directories: directory from which we started to sample using functionObject. Inside
• cells_fo1 • pressureDrop this directory you will find the sampled data.
• cells_fo2 • pressureDrop.region1 • If you start to sample from time 50, you will find the time directory 50.
• field_fo4 • pressureDrop.region2 • If you stop the simulation and restart it, let us say from time 10, you will find
• field_fo4.region1 • probesDict the time directories 0 and 10.
• field_fo4.region2 • probes_fo1
• For line and surface sampling, you will find all the time directories
• forces_object • probes_online
corresponding to the saving frequency. Inside each directory you will find
• inlet_average • sampleDict1 the sampled data.
• inlet_massflow • sampleDict2
• Let us take a look at the general organization of a functionObject.
• inlet_massflow_posteriori • sets_fo2
• innerpatch_massflow • sets_online
• minmaxdomain • surface1_massflow
• outlet_areaNormalIntegrate • surface2_massflow
• outlet_massflow • surface3_massflow
• outlet_massflow_posteriori • surface4_massflow
• outlet_max • surfaces_fo3
• plane1_massflow 656 657
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects
• The functionObject entry in the controlDict dictionary, contains • There are many functionObjects implemented in OpenFOAM®, and
at least the following information: sometimes is not very straightforward how to use a specific functionObject.
• Also, functionObjects can have many options and some limitations.
function_object_name Name of functionObject
• Our best advice is to read the doxygen documentation or the source code to
type function_object_to_use; functionObject to use learn how to use functionObjects.
• The source code of the functionObjects is located in the directory:
functionObjectLibs ("function_object_library.so"); Library to use

enabled true; Turn on/off functionObject $WM_PROJECT_DIR/src/postProcessing/functionObjects


log true; Show on screen the output
of the functionObject

writeControl outputTime;
timeStart 0; Output frequency • Here after we are going to study a few commonly used functionObjects.
timeEnd 20;

//... Keywords and sub-


//functionObject // dictionaries specific to the
//keywords and sub-dictionaries // functionObject
//...

658 659

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


The controlDict dictionary The controlDict dictionary

51 functions • Let us take a look at the bottom of the controlDict 56 minmaxdomain • fieldMinMax functionObject
57 {
52 { dictionary file. 58 type fieldMinMax;
59 • This functionObject is used to compute the
name_of_the_functionObject_dictionary • Here we define functionObjects, which are functions that 60 functionObjectLibs ("libfieldFunctionObjects.so"); minimum and maximum values of the field
61
{
Dictionary with the functionObject entries
will do a computation while the simulation is running. 62 enabled true; variables.
63
}
• In this case, we define the functionObjects in the sub- 64
65
mode component; • The output of this functionObject is saved in
dictionary functions (lines 51-115). 66 writeControl timeStep; ascii format in the file fieldMinMax.dat located
113 #include "functionObject0" 67 writeInterval 1;
in the directory
114
115 }
• Each functionObject we define, has its own name and its 68
69 log true;
compulsory keywords and entries. 70 postProcessing/minmaxdomian/0
71 fields (p U);
• Notice that in line 113 we use the directive include to call an 72 }

external dictionary with the functionObjects definition.


• Remember, the name of the directory where the output
• If you use the include directive, you will need to update the data is saved is the same as the name of the
controlDict dictionary in order to read any modification functionObject (line 56).
done in the included dictionary files.
• By the way, you can give any name to the input files defined
in line 113.

Note:
Use the banana method to know all the options available
for each entry.
660 661
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects
The controlDict dictionary The functionObject0 dictionary

78 field_averages • fieldAverage functionObject 18 inlet_massflow • faceSource functionObject


79 { 19 {
80 type fieldAverage; 20
81 functionObjectLibs ("libfieldFunctionObjects.so"); • This functionObject is used to compute the 21 type surfaceRegion; • This functionObject is used to compute the
82 enabled true; average values of the field variables. 22 functionObjectLibs ("libfieldFunctionObjects.so"); mass flow in a boundary patch.
83 23 enabled true;
84 writeControl outputTime; 24
85 //writeControl timeStep; • The output of this functionObject is saved in the 25 //writeControl outputTime; • In this case, we are sampling the patch inlet.
86 //writeInterval 100; time solution directories. 26 writeControl timeStep;
87 27 writesInterval 1; • We are using the operation sum with the field phi.
88 //cleanRestart true; 28
89 29 log true; This is equivalent to compute the mass flow.
90 timeStart 0.05; 30
91 timeEnd 0.1; 31 writeFields false; • The output of this functionObject is saved in
92 32
93 fields 33 regionType patch; ascii format in the file faceSource.dat located
94
95
(
U
34
35
name inlet;
in the directory
96 { 36 operation sum;
97 mean on; 37 fields postProcessing/inlet_massflow/0
98 prime2Mean on; 38 (
99 base time; 39 phi
100 } 40 );
101 41 }
102 p • Remember, the name of the directory where the output
103 { data is saved is the same as the name of the
104 mean on;
105 prime2Mean on; functionObject (line 18).
106 base time;
107 }
108 );
109 }

Note: Note:
Use the banana method to know all the options available Use the banana method to know all the options available
for each entry. for each entry.
662 663

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


The functionObject0 dictionary The functionObject0 dictionary

45 outlet_massflow • faceSource functionObject 72 probes_online • probes functionObject


46 { 73 {
47 type surfaceRegion; 74 type probes;
48 functionObjectLibs ("libfieldFunctionObjects.so"); • This functionObject is used to compute the 75 functionObjectLibs ("libfieldFunctionObjects.so"); • This functionObject is used to probe field data at
49 enabled true; mass flow in a boundary patch. 76 enabled true; the given locations.
50 77 writeControl outputTime;
51 //writeControl outputTime; 78
52 writeControl timeStep; • In this case, we are sampling the patch outlet. 79 probeLocations • The output of this functionObject is saved in
53 writeInterval 1; 80 ( ascii format in the files p and U located in the
54 • We are using the operation sum with the field phi. 81 (0 0 0)
55 log true; 82 (0 0 0.1) directory
56 This is equivalent to compute the mass flow. 83 (0 0 0.2)
57 writeFields false; 84 ); postProcessing/probes_online/0
58 • The output of this functionObject is saved in 85
59 regionTyp patch; 86 fields
60 Name outlet; ascii format in the file faceSource.dat located 87 (
61
in the directory 88 U
62 operation sum; 89 p • Remember, the name of the directory where the output
63 fields 90 );
64 ( postProcessing/outlet_massflow/0 91 data is saved is the same as the name of the
65
66 );
phi 92 }
functionObject (line 72).
67 }

• Remember, the name of the directory where the output


data is saved is the same as the name of the
functionObject (line 45).

Note: Note:
Use the banana method to know all the options available Use the banana method to know all the options available
for each entry. for each entry.
664 665
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects
The functionObject0 dictionary The functionObject0 dictionary
127 pressureDrop
128 { • fieldValueDelta functionObject 171 innerpatch_massflow • faceSource functionObject
172 {
129 type fieldValueDelta;
173 type surfaceRegion;
130 functionObjectLibs ("libfieldFunctionObjects.so"); • This functionObject is used to compute the 174 functionObjectLibs ("libfieldFunctionObjects.so"); • This functionObject is used to compute the
131 enabled true;
132 difference/average/min/max of two field values. 175 enabled true; mass flow in an inner patch.
176
133 region1
177 writeControl timeStep;
134 { • We are using the operation sum with the field phi. 178 writeInterval 1; • In this case, we are sampling the faceZone
135 writeFields off;
137 type surfaceRegion; This is equivalent to compute the mass flow. 179
180 log true;
internalfacepatch.
138 regionType patch;
181 writeFields false;
139 name inlet; • We are using the operation subtract between the 182 • We are using the operation sum with the field phi.
140
141 operation sum; two field values. 183 regionType faceZone;
142
184 Name internalfacepatch; • The output of this functionObject is saved in
185
143 fields • The output of this functionObject is saved in 186 operation sum; ascii format in the file faceSource.dat located
144 (
145 phi ascii format in the file fieldValueDelta.dat 187
188
fields
(
in the directory
146
147 }
);
located in the directory 189 phi
postProcessing/innerpatch_massflow/0
190 );
148
149 region2 postProcessing/pressureDrop/0 191
192 }
150 {
151 writeFields off;
153 type surfaceRegion; • Remember, the name of the directory where the output
154 regionType patch;
155 name outlet; • Remember, the name of the directory where the output data is saved is the same as the name of the
156
157 operation sum;
data is saved is the same as the name of the functionObject (line 171).
158 functionObject (line 127).
159 fields
160 (
161 phi
162 );
163 } Note: Note:
164 Use the banana method to know all the options available Use the banana method to know all the options available
165 operation subtract;
166 } for each entry. for each entry.
666 667

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


The functionObject0 dictionary The functionObject0 dictionary

197 sets_online • sets functionObject 233 forces_object • forces functionObject


198 { 234 {
199 type sets; 235 type forces;
200 functionObjectLibs ("libfieldFunctionObjects.so"); • This functionObject is used to sample field data 236 functionObjectLibs ("libforces.so"); • This functionObject is used to compute the
201 enabled true; in a line. 237 forces on a patch.
202 writeControl outputTime; 238 //writeControl outputTime;
203 239 writeControl timeStep;
204 interpolationScheme cellPointFace; • The output of this functionObject is saved in 240 writeInterval 1; • In this case, we are sampling the patch walls.
205 setFormat raw; ascii format in the files set1_p.xy and 241
206 242 //// Patches to sample • The output of this functionObject is saved in
207 sets set1_U.xy located in the time directories inside 243 patches ("walls");
208 ( 244 ascii format in the file forces.dat located in
the folder
209
210 set1
245
246
//// Name of fields
pName p;
the time directories inside the folder
211 { postProcessing/sets_online 247 Uname U;
212 type midPointAndFace; 248 postProcessing/forces_object/0
213 249 //// Density
214 axis x; 250 rho rhoInf;
215 start (-0.002 -0.002 0.2); 251 rhoInf 1.;
216 end ( 0.002 0.002 0.2); • Remember, the name of the directory where the output 252
• Remember, the name of the directory where the output
217 }
data is saved is the same as the name of the 253 //// Centre of rotation
218 254 CofR (0 0 0); data is saved is the same as the name of the
219 ); functionObject (line 197). 255 }
220 functionObject (line 233).
221 fields
222 (
223 U
224 p
225 );
226
227 }

Note: Note:
Use the banana method to know all the options available Use the banana method to know all the options available
for each entry. for each entry.
668 669
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects
Running functionObjects a-posteriori • In the directory system, you will find the following functionObjects
dictionaries: functionObject1 , functionObject2 ,
• Sometimes it can happen that you forget to use a functionObject or you functionObject3 , functionObject4, functionObject5 ,
want to execute a functionObject a-posteriori (when the simulation is over). functionObject6.
• The solution to this problem is to use the solver with the option • Try to figure out what we are doing in every functionObject dictionary.
-postProcess. This will only compute the new functionObject, it will not
rerun the simulation. • At this point, let us run each the functionObject a-posteriori. In the terminal
type:
• 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, 1. $> pisoFoam -postProcess -dict system/functionObject1 > log_fo1

2. $> pisoFoam -postProcess -dict system/functionObject2


• $> name_of_the_solver -postProcess –dict dictionary_location
3. $> pisoFoam -postProcess -dict system/functionObject3 –time 0.05:0.1

4. $> pisoFoam -postProcess -dict system/functionObject4 –noZero


• By proceeding in this way you do not need to rerun the simulation, you just
5. $> pisoFoam -postProcess -dict system/functionObject5 -latestTime
compute the new functionObject.
6. $> pisoFoam -postProcess -dict system/functionObject6 -latestTime

670 671

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


• In this step 1, we are reading the dictionary functionObject1 located in Some shell and awk scripting
the directory system (the dictionary file can be located anywhere), and we
• Let us do some shell and awk scripting on the sampled data.
are doing the computation for all the saved solutions. Notice that we are
redirecting the output to a log file. • Let us go to the directory postprocesssing/minmaxdomain/0
• To erase the parentheses in the file fieldMinMax.dat and save the output in the file
• In this step 2, we are reading the dictionary functionObject2 and we are out.txt, type in the terminal:
doing the computation for all saved solutions. • $> cat fieldMinMax.dat | tr -d "()" > out.txt
• In this step 3, we are reading the dictionary functionObject3 and we are
doing the computation for the time range 0.05 to 0.1 • To extract the velocity from the file out.txt, and save the output in the file vel_minmax.txt,
type in the terminal:
• In this step 4, we are reading the dictionary functionObject4 and we are
• $> awk '0 == NR % 2' out.txt > vel_minmax.txt
doing the computation for all the saved solutions, except time zero.
• In this step 5, we are reading the dictionary functionObject5 and we are • To extract the pressure from the file out.txt, and save the output in the file
doing the computation only for he latest save solution. pre_minmax.txt, type in the terminal:

• In this step 6, we are reading the dictionary functionObject6 and we are • $> awk '1 == NR % 2' out.txt > pre_minmax.txt

doing the computation only for he latest save solution.

672 673
On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects
Some shell and awk scripting Some shell and awk scripting
• To erase the header of the file pre_minmax.txt, type in the terminal: • In the directory scripts (located in the top level case directory) you will find the following
• $> awk '{if (NR!=1) {print}}' pre_minmax.txt > tmp scripts that will do some data processing automatically,
• script_cleanfile
• $> mv tmp pre_minmax.txt
• script_cleanforce
• To erase the header of the file vel_minmax.txt, type in the terminal: • script_extractfields
• $> awk '{if (NR!=1) {print}}' vel_minmax.txt > tmp • script_force_coe
• $> mv tmp vel_minmax.txt • script_forces
• To compute the mean value of the seventh column of the file pre_minmax.txt (maximum • script_meanvalues
pressure in this case), type in the terminal: • script_minmax
• $> awk 'NR>=50 && NR { total += $7; count++} END { print • script_probes
“Mean_value ” total/count}' pre_minmax.txt
We are computing the mean value of column 7 starting from row 50 • To run the scripts you need to be inside the scripts directory. In the terminal type,
• To compute the mean value of the seventh column of the file vel_minmax.txt (minimum Z • cd scripts
velocity component in this case), type in the terminal: • sh script_name
• $> awk 'NR>=50 && NR { total += $5; count++} END { print
“Mean_value ” total/count}' vel_minmax.txt • Feel free to reuse them and adapt these scripts according to your needs.
We are computing the mean value of column 7 starting from row 50

674 675

On-the-fly postprocessing – functionObjects On-the-fly postprocessing – functionObjects


Some shell and awk scripting Plotting in gnuplot
• The script script_force_coe will compute the mean value and standard deviation • Let us do some plotting using gnuplot. Type in the terminal (you must be inside the
of the lift and drag coefficients (in this case they are not computed). scripts directory):
• The script script_forces will extract the force components and saved in a clean
file. 1. $> sh script_minmax

• The script script_minmax will extract the minimum and maximum values of the 2. $> gnuplot
field variables.
3. gnuplot> plot [][] 'vel_minmax.txt' u 1:5 w l title "min v_z",
• The script script_probes will extract the information of the probes. '' u 1:11 w l title "max v_z"

We just showed how to compute the average and standard deviation and do some
manipulation of the information saved in the output files, but you can do many things in
an automatic way.

The power of scripting!!!


676 677
On-the-fly postprocessing – functionObjects Roadmap
Plotting in gnuplot

• Let us do some plotting using gnuplot. Type in the terminal (you must be inside the 1. Sampling with the postProcess utility
scripts directory):
2. Probing with the postProcess utility
1. gnuplot> plot [][] '< sed "s/[()]/ /g"
../postProcessing/forces_object/0/forces.dat' u 1:7 w l 3. On-the-fly postprocessing – functionObjects and the
postProcess utility
• In this step we are using sed inside gnuplot to clean the parentheses. If you do not 4. Field manipulation
erase the parentheses in the input file, gnuplot will complain.
5. Co-processing
6. Data conversion
7. foamLog

678 679

Field manipulation Field manipulation


• Hereafter we are going to deal with field manipulation • To get a list of what can be computed using the postProcess utility, type in
• Field manipulation means modifying a field variable or deriving a new field the terminal:
variable using the primitive variables computed during the solution stage. • $> postProcess –list
• We will do the post-processing using the command line interface (CLI), or
non-GUI mode. • The utility postProcess can take many options. To get more information
• The utility postProcess can be used as a single application, e.g., on how to use the utility, type in the terminal:
• $> postprocess –func vorticity • $> postProcess –help
• Or it can be used with a solver using the option –postprocess, e.g., • $> simpleFoam -postProcess –help
• $> simpleFoam -postprocess –func vorticity
• Running the solver with the option –postprocess will only execute the • The options of the solver using the –postProcess flag are the same as the
post-processing and it will let you access data available on the database for options of the utility postProcess.
the particular solver (such as physical properties or turbulence model). • 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.
680 681
Field manipulation Field manipulation
After computing the solution, we can compute derived fields (e.g., Courant number, Mach
• We will now do some field manipulation using the number, density, vorticity, and so on), using the primitive fields (U, p, T)
cylinder mesh. Courant number Mach number
www.wolfdynamics.com/wiki/postprocess/ani_courant.gif www.wolfdynamics.com/wiki/postprocess/ani_mach.gif

• For this we will use the supersonic cylinder tutorial


located in the directory:

$PTOFC/postprocessing/supersonic_cyl/

Density Vorticity Z
www.wolfdynamics.com/wiki/postprocess/ani_rho.gif www.wolfdynamics.com/wiki/postprocess/ani_vortZ.gif

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
682 683

Field manipulation Field manipulation


What are we going to do? Running the case

• We will use this case to introduce the postProcess utility. • Let us do some data manipulation. To run the case, type in the terminal:

• 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 1. $> foamCleanTutorials
access the database of the solver.
2. $> blockMesh
• To find the numerical solution we will use the solver sonicFoam.
3. $> sonicFoam > log.sonicfoam &
• sonicFoam is a transient solver for trans-sonic/supersonic, laminar or turbulent flow
4. $> pyFoamPlotWatcher.py log.sonicfoam
of compressible gas.
5. $> paraFoam
• At the end, we will do some plotting (using gnuplot or Python) and scientific
visualization.

• You do not need to run the simulation until the end time,
• Just run the simulation until 0.2 seconds. We only need a few timesteps to
do the field manipulation.

684 685
Field manipulation Field manipulation
• After finding the solution, we can compute new field variables using the • In step 1 we compute the Mach number. To compute this value, the
primitive variables computed during the solution stage. In the terminal type: postProcess utility needs to access the thermophysicalProperties
dictionary.
1. $> sonicFoam -postProcess -func MachNo • In step 2 we compute the Courant number. To compute this value, the
2. $> sonicFoam -postProcess -func CourantNo postProcess utility needs to access the face fluxes (phi).
3. $> sonicFoam -postProcess -func wallShearStress • In step 3 we compute the wall shear stress. To compute this value, the
postProcess utility needs to access the transport and turbulence
4. $> sonicFoam -postProcess -func 'writeObjects(rho)' -time 0
properties.
5. $> sonicFoam -postProcess -func vorticity
• In step 4 we compute the density (rho) for the initial time (time = 0). To
6. $> postProcess -func vorticity compute this value, the postProcess utility needs to access the simulation
database.
• If the new field variables require information of the simulation database • In steps 5 and 6 we compute the vorticity field, this field is derived from the
(fluxes, turbulence properties, transport properties), you will need to process velocity field. The postProcess utility does not need to access any
as in steps 1-5. particular solver information. Both options will give the same output.
• In the new field variable only requires to use a variable that already exist in
the solution folder, you can proceed as in step 6.

686 687

Field manipulation Field manipulation


• After finding the solution, we can compute new field variables using the • In steps 1-8, all the fields are derived from pre-existing fields. The postProcess
primitive variables computed during the solution stage. In the terminal type: 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
1. $> postProcess -func 'grad(U)' grad(U).
2. $> postProcess -func 'components(U)' • In step 2 we compute the components of the velocity vector U. The components are
saved as Ux, Uy and Uz.
3. $> postProcess -func 'mag(U)'
• In step 3 we compute the magnitude of the velocity vector U. The output is saved as
4. $> postProcess -func 'magSqr(U)'
mag(U).
5. $> postProcess -func 'totalPressureCompressible(rho,U,p)' -noZero
• In step 4 we compute the magnitude squared of the velocity vector U. The output is
6. $> postProcess -func 'div(U)' -time 0.1:0.2 saved as magSqr(U).
7. $> postProcess -func 'mag(grad(U))' -latestTime • 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 0.1:0.2 means save the values between the given range (0.1-0.2).
• 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.
688 689
Field manipulation Roadmap
• We can also use the utility postprocess to compute the average and integral
of a specified field over a patch. In the terminal type:
1. Sampling with the postProcess utility
2. Probing with the postProcess utility
1. $> postProcess -func 'patchAverage(name=in,p)' –latestTime
3. On-the-fly postprocessing – functionObjects and the
2. $> postProcess -func 'patchAverage(name=out,U)' -latestTime
postProcess utility
3. $> postProcess -func 'patchIntegrate(name=in,p)' –latestTime
4. Field manipulation
4. $> postProcess -func 'patchIntegrate(name=out,U)' -latestTime
5. Co-processing
6. Data conversion
• In step 1 we compute the average of p over the patch inlet.
7. foamLog
• In step 2 we compute the average of U over the patch outlet.
• In step 3 we compute the integral of p over the patch inlet.
• In step 4 we compute the integral of U over the patch outlet.

690 691

Co-processing Co-processing
• CFD simulations have the potential to overwhelm any computer with the output • For unsteady and big simulations, co-processing is an alternative if we do
obtained from simulations. not want to overflow the system with tons of data.
• The traditional approach is to run a simulation and save the solution at given time- • By doing co-processing, we can do visualization on-the-fly.
steps or intervals for post processing at a later time.
• In principle, co-processing is similar to doing sampling using
• An alternative way to do post processing, is to extract results (or pretty pictures) while
functionObjects, but when we do co-processing we output pretty pictures
the simulation is running (on-the-fly), this is co-processing.
(e.g., streamlines, iso-surfaces, cut-planes).
• Instead, when we do sampling using functionObject we save data for
GEOMETRY
plotting (we save a quantity of interest).
• An added benefit of co-processing is that results can be immediately
MESH reviewed and problems can be immediately addressed.
• Co-processing requires that you identify what you want to see before
running the simulation. You need to plan everything in advanced.
SOLVER CO-PROCESSING
• In OpenFOAM®, you can output on-the-fly streamlines, cutting planes, iso-
surfaces, near surface fields, forces and force coefficients (they can be
POST-PROCESSING
written into data bins).

692 693
Co-processing Co-processing

• Let us do some co-processing. Go to the directory:

$PTOFC/postprocessing/vespacoarse/

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
Geometry and computational domain
694 695

Co-processing Co-processing
What are we going to do? Running the case

• We will use this case to do co-processing using functionObjects. • In the terminal window type:

• We do not need to generate the mesh or run the simulation for a long time. 1. $> foamCleanTutorials
However, all the dictionaries are included.
3. $> rm –f 0
• The dictionaries to initialize the solution using potentialFoam are also $> cp –r 0_org 0
4.
included
5. $> tar –xzvf constant.tar.gz
• We will run the simulation for 20 iterations and then we will visualize the
6. $> cp system/simplefoam/* system/
solution.
7. $> simpleFoam > log | tail –f log
• In this case, we will use the solver simpleFoam with turbulence modeling,
8. $> paraFoam
and we will run in serial, but feel free to run in parallel.

• In step 5 we uncompress the pre-generated mesh


• In step 6 we copy the dictionaries for the solver simpleFoam.
• In step 7 we run the solver simpleFoam.
696 697
Co-processing Co-processing
The controlDict dictionary The cuttingPlane dictionary
49 functions • Let us take a look at the bottom of the controlDict • In this dictionary we define the cutting planes.
50 (
dictionary file.
51
53 #include "readFields"
• Remember, we need to know the location of the cutting
54 #include "streamLines" • We define the functionObjects in the sub-dictionary planes a-priori.
55 #include "cuttingPlane"
56 #include "wallBoundedStreamLines" functions (lines 49-89).
57 #include "./system/files/isoSurface" 1 cuttingPlane Name of the functionObject
58 #include "forceCoeffs" • In this case, instead of defining inline the 2 {
88
89 ); functionObject, we are using the directive include. 3
4
type surfaces;
functionObjectLibs ("libsampling.so");
5
• In the directory system you will find the dictionaries files 6 //writeControl outputTime;
7
readFields, streamLines, cuttingPlane, 9 writeControl timeStep; Saving frequency. Can be different from
wallBoundedStreamLines, and forceCoeffs. 10 writeInterval 5;
the saving frequency of the solution
11
• In the directory system/files you will find the 12
13 surfaceFormat vtk; Fields to sample and sample format.
dictionary file isoSurface. 14 fields ( p U k omega);
VTK format can be visualize in paraFoam/paraview
15
16 interpolationScheme cellPoint;
• If you use the include directive, you will need to update 17
the controlDict dictionary in order to read any 18 surfaces
19 (
modification done in the included dictionary files. 20 xNormal Name of the plane
21 {
• By the way, you can give any name to the input files 22
23
type
planeType
cuttingPlane;
pointAndNormal;
defined in lines 53-58. 24 pointAndNormalDict
25 {
26 basePoint (0 0 0); Plane type and plane location
27 normalVector (1 0 0);
28 }
29 interpolate true;
30 }

698 699

Co-processing Co-processing
The cuttingPlane dictionary The cuttingPlane dictionary output
31 • Planes sampled using functionObjects.
32 yNormal Name of the plane
33
34
{
type cuttingPlane;
• Each plane contains the information of the fields sampled (U, p, k and omega).
35 planeType pointAndNormal;
36 pointAndNormalDict
37 {
38 basePoint (0 0 0);
39 normalVector (0 1 0); Plane type and plane location
40 }
41 interpolate true;
42 }
43
44 zNormal Name of the plane
45 {
46 type cuttingPlane;
47 planeType pointAndNormal;
48 pointAndNormalDict
49 {
50 basePoint (0 0 1);
51 normalVector (0 0 1); Plane type and plane location
52 }
53 interpolate true;
54 }
55
56
57
);
• The output of this functionObject is saved in the
58 } directory postProcessing/cuttingPlane
• In this directory, you will find many time directories
with the sampled data.
• Inside each directory you will find a series of files
with the VTK extension, you can open these files
in paraFoam/paraview
700 701
Co-processing Co-processing
The streamLines dictionary The streamLines dictionary
• In this dictionary we define the streamlines. 38
39 // Seeding method. See the sampleSets in sampleDict.
• Remember, we need to know the location from where to 40 seedSampleSet uniform; Seed type
41
release the streamlines a priori. 42 uniformCoeffs
43 {
44 type uniform; Options related to the seeding of the streamlines
1 streamLines Name of the functionObject 45 axis x; //distance;
2 { 46
3 type streamLine; 48 start (-1 0 0);
4 49 end (-1 0 1.6);
5 //writeControl outputTime; 50 nPoints 20;
6 51 }
7 52 }
8 writeControl timeStep; Saving frequency. Can be different from
9 writeInterval 5;
10
the saving frequency of the solution
11
12 setFormat vtk;
13
14 // Velocity field to use for tracking.
15 UName U; Velocity field used to compute the streamlines
16
17 // Tracked forwards (+U) or backwards (-U)
• The output of this functionObject is saved in the
18 trackForward true; directory
19
20 //Names of fields to sample. Mustcontain velocity field! postProcessing/sets/streamLines
21 fields (U p); Fields to sample
22 • In this directory, you will find many time directories
23 // Steps particles can travel before being removed
24 lifeTime 10000; with the sampled data.
25
• Inside each directory you will find a series of files
with the VTK extension, you can open these files
in paraFoam/paraview

702 703

Co-processing Co-processing
The streamLines dictionary output The system/files/isoSurface dictionary
• Streamlines sampled using functionObjects. • In this dictionary we define the iso-surfaces.
• Each streamlines contains the information of the fields sampled (U and p). • Remember, we need to know the value of the iso-
surface a priori.

2 isoSurface Name of the functionObject


3 {
4 type surfaces;
5 functionObjectLibs ("libsampling.so");
6
10 writeControl timeStep; Saving frequency. Can be different from
11 writeInterval 10;
12
the saving frequency of the solution
13 surfaceFormat vtk;
14 fields ( p U k omega); Fields to sample
15
16 interpolationScheme cellPoint;
17
19 surfaces
20 (
21
22 constantIso Name of the iso-surface
23 {
24 // Iso surface for constant values.
25 // Triangles guaranteed not to cross cells.
26 type isoSurfaceCell;
27 isoField p; Field used to create the iso-surface
28 isoValue 30;
29 interpolate false;
and its value
30 regularise false;
33 }
34

704 705
Co-processing Co-processing
The system/files/isoSurface dictionary The system/files/isoSurface dictionary output
35 interpolatedIso Name of the iso-surface
• Iso-surfaces sampled using functionObjects.
36 {
37
38
// Iso surface for interpolated values only
type isoSurface;
• Each iso-surface contains the information of the fields sampled (U, p, k and omega).
39 isoField p; Field used to create the iso-surface
40 isoValue 80;
41 interpolate true;
and its value
48
49 }
50
62
63 );
64
65
66 }

• The output of this functionObject is saved in the


directory postProcessing/isoSurface
• In this directory, you will find many time directories
with the sampled data.
• Inside each directory you will find a series of files
with the VTK extension, you can open these files
in paraFoam/paraview

706 707

Roadmap 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).
1. Sampling with the postProcess utility
• You can convert the solution obtained with OpenFOAM® to many third party formats
2. Probing with the postProcess utility by using OpenFOAM® data conversion utilities.

3. On-the-fly postprocessing – functionObjects and the • If you are looking for a specific format and it is not supported, you can write your own
conversion tool.
postProcess utility
• In the directory $FOAM_UTILITIES/postprocessing/dataConversion, you will
4. Field manipulation find the source code of the following data conversion utilities:

5. Co-processing • foamDataToFluent • foamToTecplot360


6. Data conversion • foamToEnsight • foamToTetDualMesh
• foamToEnsightParts • foamToVTK
7. foamLog
• 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
708 709
Data conversion Roadmap
ASCII ↔ Binary conversion
• Another utility that might come in handy, specially when dealing with
large meshes is foamFormatConvert.
1. Sampling with the postProcess utility
17
18
application icoFoam; • This utility converts the mesh and field variables into ascii or binary 2. Probing with the postProcess utility
19 startFrom startTime; format.
20
21
22
startTime 0; • In order to manually edit the boundary file and the field variables 3. On-the-fly postprocessing – functionObjects and the
23
24
stopAt endTime; dictionaries (initial and boundary conditions), they must be in ascii
format.
postProcess utility
25 endTime 50;

4. Field manipulation
26
27 deltaT 0.01; • After editing these files, we can convert them into binary format.
28
29 writeControl runTime;
• Working in binary format can significantly reduce data parsing and
30
31
32
writeInterval 1; dimension of the files (specially for large meshes). 5. Co-processing
33 purgeWrite 0;
• The drawback is that the files are not human readable anymore.
34
35 writeFormat binary;
6. Data conversion
36 • To convert ascii files into binary files, just type in the terminal:
37
38
39
writePrecision 8;

writeCompression off;
• $> foamFormatConvert 7. foamLog
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
710 711

foamLog foamLog
• During execution, OpenFOAM® writes values of residuals, number of • By default, the files are presented in two-column format of time and the
iterations, and so on, on the standard output (terminal). extracted values.
• It is possible to extract this information with the foamLog utility, provided the • You can plot each file by using gnuplot or your favorite plotting tool.
standard output has been written to a log file. • Depending of your case setup, you will find the following files:
• To extract the information, type in the terminal
contCumulative_0 Time
• $> foamLog log_file_name contGlobal Ux
contLocal UxFinalRes

• All the information extracted from the log file is saved in the directory logs CourantMax UxIters
CourantMean Uy
• To plot this info we can use gnuplot, grace, xmgr, octave, qtiPlot, Python,
executionTime UyFinalRes
jPlot (just to name a few).
p UyIters
pFinalRes Uz
pFinalRes_0 UzFinalRes
pIters UzIters
Separator
712 713
foamLog foamLog
• Let us analyze the log file of the previous tutorial. In the terminal type: • This is a screenshot on my workstation. This is a plot of the pressure initial
and final residuals using gnuplot. You can plot any of the output files
1. $> foamLog log generated by foamLog.
2. $> cd logs
3. $> ls -al
4. $> gnuplot

• Let us plot the extracted data using gnuplot. In the terminal type:

1. gnuplot> plot [][] ‘CourantMax_0’ u 1:2 w l

2. gnuplot> plot [][] ‘pIters_3’ u 1:2 w l

3. gnuplot> set logscale y

4. gnuplot> plot [][] ‘pFinalRes_3’ u 1:2 w l, ‘p_3’ u 1:2 w l

5. gnuplot> plot [][] ‘Uz_0’ u 1:2 w l

714 715

Roadmap

1. Finite Volume Method: A Crash Introduction

Module 6 2.
3.
On the CFL number
Numerical playground
Finite volume method overview 4. Linear solvers in OpenFOAM®
5. Pressure-Velocity coupling in OpenFOAM®
6. Unsteady and steady simulations
7. Understanding residuals
8. Boundary and initial conditions

716 717
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
• Before continuing, we want to remind you that this a brief introduction to the FVM. • Let us use the general transport equation as the starting point to explain the FVM,
• 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.
• We want to solve the general transport equation for the transported quantity in a • As consequence of the previous requirement, all dependent variables are assumed
given domain, with given boundary conditions BC and initial conditions IC. to vary linearly around a point P in space and instant t in time,
• This is a second order equation. 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.
• By the way, 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.

Profile assumptions using Taylor expansions around point P (in space) and point t (in time)

718 719

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
• Let us divide the solution domain into a finite number of arbitrary control volumes or • In the FVM, a lot of overhead goes into the data book-keeping of the domain information.
cells, such as the one illustrated below. • We know the following information of every control volume in the domain:
• Inside each control volume the solution is sought. • 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 control volumes can be of any shape (e.g., tetrahedrons, hexes, prisms,
pyramids, dodecahedrons, and so on). • The vector from the centroid P of to the centroid N of is named d.
• We also know all neighbors of the control volume .
• The only requirement is that the elements need to be convex and the faces that made
up the control volume need to be planar. • The control volume faces are labeled f, which also denotes the face center.
• The location where the vector d intersects a face is .
• We also know which control volumes are internal and which control volumes lie on
• The face area vector point outwards from the control volume, is located at the face
the boundaries.
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.

720 721
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
• In the control volume illustrated, the centroid P is given by, • Let us recall the Gauss or Divergence theorem,

• In the same way, the centroid of face f is given by


where is a closed surface bounding the control volume and
represents an infinitesimal surface element with associated normal pointing
outwards of the surface , and

• Finally, we assume that the values of all variables are computed and stored in the • The Gauss or Divergence theorem simply states
centroid of the control volume and that they are represented by a piecewise that the outward flux of a vector field through a
constant profile (the mean value), 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.
• This is known as the collocated arrangement.
• All the previous approximations are at least second order accurate.
722 723

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
• Let us use the Gauss theorem to convert the volume integrals into surface integrals, • 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 where we have approximated the integrant


volume integrals into surface integrals by means of the mid point rule, which is
second order accurate

Gauss theorem:

• At this point the problem reduces to interpolating somehow the cell centered values
(known quantities) to the face centers.

724 725
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
• Integrating in space each term of the general transport equation and by using Gauss • Integrating in space each term of the general transport equation and by using Gauss
theorem, yields to the following discrete equations for each term theorem, yields to the following discrete equations for each term

Diffusive term: Gradient term:

By using Gauss theorem we convert where we have approximated the integrant where we have approximated the centroid gradients by using the Gauss theorem.
volume integrals into surface integrals by means of the mid point rule, which is This method is second order accurate
second order accurate

Gauss theorem: Gauss theorem:

726 727

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
• Integrating in space each term of the general transport equation and by using Gauss • Using the previous equations to evaluate the general transport equation over all the
theorem, yields to the following discrete equations for each term control volumes, we obtain the following semi-discrete equation

Source term:

This approximation is exact if is either constant or varies linearly within the control
volume; otherwise is second order accurate. where is the convective flux and is the
Sc is the constant part of the source term and Sp is the non-linear part
diffusive flux.

Gauss theorem: • 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.

728 729
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be • By looking the figure below, the face values appearing in the convective flux can be
computed as follows, computed as follows,

• This type of interpolation scheme is known as linear interpolation or central • This type of interpolation scheme is known as upwind differencing and it is first order
differencing and it is second order accurate. accurate.
• However, it may generate oscillatory solutions (unbounded solutions). • This scheme is bounded (non-oscillatory) and diffusive.
730 731

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be • To prevent oscillations in the SOU, we add a gradient or slope limiter function .
computed as follows,

• 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.,

• 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. • By adding a well designed limiter function , we get a high resolution (second
• For highly convective flows or in the presence of strong gradients, this scheme is order accurate), and bounded scheme. This is a TVD scheme.
oscillatory (unbounded). 732 733
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes Interpolation of the convective fluxes – TVD schemes
• A TVD scheme, is a second order accurate scheme that does not create new local undershoots and/or
overshoots in the solution or amplify existing extremes (high resolution).
• Let us see how the superbee, minmod and vanleer TVD schemes behave in a
• The choice of the limiter function dictates the order of the scheme and its boundedness. High resolution numerical schemes killer test case:
schemes falls in the blue area and low resolution schemes falls in the grey area. • The oblique double step profile in a uniform vector field (pure convection).
• The drawback of the limiters is that they reduce the accuracy of the scheme locally to first order, when
(sharp gradient, opposite slopes). However, this is justify when it serves to suppress oscillations. • By the way, this problem has an exact solution.
• The various limiters have different switching characteristics and are selected according to the particular
problem and solution scheme. No particular limiter has been found to work well for all problems, and a
particular choice is usually made on a trial and error basis.
• The Sweby diagram (Sweby, 1984), gives the necessary and sufficient conditions for a scheme to be TVD.

UD = upwind
SOU = second order upwind
CD = central differencing
D = downwind

734 735

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Linear and non-linear limiter functions Interpolation of the convective fluxes – Linear and non-linear limiter functions
• Let us see how the superbee, minmod and vanleer TVD schemes behave in a • Comparison of linear upwind method (2nd order) and upwind method (1st order).
numerical schemes killer test case. • The upwind method is extremely stable and non-oscillatory. However is highly
• The oblique double step profile in a uniform vector field (pure convection). diffusive.

SuperBee - Compressive Minmod - Diffusive vanLeer - Smooth


• On the other side, the linear upwind method is accurate but oscillatory in the
presence of strong gradients.

Upwind – 1st order Linear Upwind – 2nd order SuperBee – TVD

736 737
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Linear and non-linear limiter functions Interpolation of the convective fluxes – Unstructured meshes
• Let us see how the linear and non-linear limiter functions compare. • All higher-order schemes we have seen so far assume line structure (figure A).
• That is, the cell centers PP, P, and N are all aligned.
• In unstructured meshes, it is not straightforward to use the previous schemes, as the cell center
PP is not aligned with the vector connecting cells P and N (figure B).
• Higher-order schemes for unstructured meshes are an area of active research and new ideas
continue to emerge.

738 739

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Unstructured meshes Interpolation of convective fluxes in a skew mesh
• A simple way around this problem is to redefine • In the case of a skew mesh (as the one in the figure), we should introduce a correction in order to maintain
higher-order schemes in terms of gradients at the second order accuracy and avoid unboundedness when computing gradients.
control volume P. • One way of doing this is by using an iterative approach for computing successively better approximations to
the gradients.
• For example, using the gradient of the cells, we can
compute the face values as follows, • We can do a linear reconstruction of the cell and face gradients using compact stencils as follows.

1.

Upwind →

Central difference → 2.

Second order upwind differencing →


+
Correction for
3. interpolated
face gradient

• Notice that in this new formulation the cell PP does not appear any more. Initial approximations

• The problem now turns in the accurate evaluation of the gradients at the cell and face centers.
This can be done using Gauss method as previously explained.

740 741
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Interpolation of diffusive fluxes in a orthogonal mesh Interpolation of diffusive fluxes in a non-orthogonal mesh
• By looking the figures below, the face values appearing in the diffusive flux in an • By looking the figures below, the face values appearing in the diffusive flux in a non-
orthogonal mesh can be computed as follows, orthogonal mesh ( ) can be computed as follows,

• This is a central difference approximation of the first order derivative. This type of
approximation is second order accurate. • This type of approximation is second order accurate but involves a larger truncation
error. It also uses a larger numerical stencil, which make it less stable.
742 743

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Correction of diffusive fluxes in a non-orthogonal mesh Mesh induced errors
• By looking the figures below, the face values appearing in the diffusive flux in a non- • In order to maintain second order accuracy, and to avoid unboundedness, we need to correct
orthogonal mesh ( ) can be computed as follows. non-orthogonality and skewness errors.
• Using the over-relaxed approach, the diffusive fluxes can be corrected as follow, • The ideal case is to have an orthogonal and non skew mesh, but this is the exception rather
than the rule.

Over-relaxed approach

Orthogonal and non skew mesh Non-orthogonal and non skew mesh

744 Orthogonal and skew mesh Non-orthogonal and skew mesh 745
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Temporal discretization Temporal discretization
• Using the previous equations to evaluate the general transport equation over all the • Now, we evaluate in time the semi-discrete general transport equation
control volumes, we obtain the following semi-discrete equation,

where is the convective flux and is the


diffusive flux.
• At this stage, we can use any time discretization scheme, e.g., Crank-Nicolson, euler
• After spatial discretization, we can proceed with the temporal discretization. By implicit, forward euler, backward differencing, adams-bashforth, adams-moulton.
proceeding in this way we are using the Method of Lines (MOL).
• It should be noted that the order of the temporal discretization of the transient term
• The main advantage of the MOL method, is that it allows us to select numerical does not need to be the same as the order of the discretization of the spatial terms.
approximations of different accuracy for the spatial and temporal terms. Each Each term can be treated differently to yield different accuracies. As long as the
term can be treated differently to yield to different accuracies. individual terms are at least second order accurate, the overall accuracy will also be
second order.
746 747

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Linear system solution So, what does OpenFOAM® do?
• After spatial and temporal discretization and by using equation • 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
in every control volume of the domain, a system of linear algebraic equations for • Boundary conditions and initials conditions. This information is contained in the directory 0
the transported quantity is assembled, • 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, etc. This information is
contained in the directories constant and/or system
• 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 and
maximum CFL number). This information is set in the system/controlDict dictionary.
• Additionally, we may set sampling and functionObjects for post-processing. This information is
• This system can be solved by using any iterative or direct method. contained in the specific dictionaries contained in the directory system/
748 749
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Where do we set all the discretization schemes in OpenFOAM®? Time discretization schemes
ddtSchemes • The fvSchemes dictionary contains the information related to • There are many time discretization schemes available in OpenFOAM®.
{ the discretization schemes for the different terms appearing in
default backward;
}
the governing equations. • You will find the source code in the following directory:

gradSchemes
• The discretization schemes can be chosen in a term-by-term • $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/ddtSchemes
{ basis.
default Gauss linear;
grad(p) Gauss linear; • The keyword ddtSchemes refers to the time discretization.
} • These are the time discretization schemes that you will use most of the times:
• The keyword gradSchemes refers to the gradient term
divSchemes discretization. • steadyState: for steady state simulations (implicit/explicit).
{
default none; • The keyword divSchemes refers to the convective terms • Euler: time dependent first order (implicit/explicit), bounded.
div(phi,U) Gauss linear; discretization.
} • backward: time dependent second order (implicit), bounded/unbounded.
• The keyword laplacianSchemes refers to the Laplacian terms
laplacianSchemes • CrankNicolson: time dependent second order (implicit), bounded/unbounded.
discretization.
{
default Gauss linear orthogonal; • The keyword interpolationSchemes refers to the method used
}
to interpolate values from cell centers to face centers. It is • First order methods are bounded and stable, but diffusive.
interpolationSchemes unlikely that you will need to use something different from
{ • Second order methods are accurate, but they might become oscillatory.
linear.
default linear;
• At the end of the day, we always want a second order accurate solution.
} • The keyword snGradSchemes refers to the discretization of
snGradSchemes
the surface normal gradients evaluated at the faces. • If you keep the CFL less than one when using the Euler method, numerical diffusion is not that
{
• Remember, if you want to know the options available for each much (however, we advise you to do your own benchmarking).
default orthogonal;
} keyword you can use the banana method.
750 751

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Time discretization schemes Convective terms discretization schemes
• The Crank-Nicolson method as it is implemented in OpenFOAM®, uses a blending factor. • 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
ddtSchemes
{
default CrankNicolson ; • 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.
• Setting to 0 is equivalent to running a pure Euler scheme (robust but first order accurate). • vanLeer: TVD, second order accurate, bounded.

• By setting the blending factor equal to 1 you use a pure Crank-Nicolson (accurate but • limitedLinear: second order accurate, unbounded, but more stable than pure linear.
oscillatory, formally second order accurate). Recommended for LES simulations (kind of similar to the Fromm method).

• 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. • First order methods are bounded and stable but diffusive.
• A blending factor of 0.9 is safe to use for most applications. • Second order methods are accurate, but they might become oscillatory.
• At the end of the day, we always want a second order accurate solution.
752 753
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Convective terms discretization schemes Gradient terms discretization schemes
• When you use linearUpwind for div(phi,U), you need to tell OpenFOAM® how to compute the • There are many gradient discretization schemes available in OpenFOAM®.
velocity gradient or grad(U): • 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:
gradSchemes
• Gauss
{
• leastSquares
grad(U) cellMDLimited Gauss linear 1.0;
}
• To avoid overshoots or undershoots when computing the gradients, you can use gradient
limiters.
divSchemes
{ • Gradient limiters increase the stability of the method but add diffusion due to clipping.
div(phi,U) Gauss linearUpwind grad(U); • You will find the source code in the following directory:
} • $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/gradSchemes/limitedGradSchemes
• These are the gradient limiter schemes available in OpenFOAM®:
• cellLimited, cellMDLimited, faceLimited, faceMDLimited

• Same applies for scalars (e.g. k, epsilon, omega, T)


• All of the gradient discretization schemes are at least second order accurate.
754 755

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Gradient terms discretization schemes Gradient terms discretization schemes
• These are the gradient limiter schemes available in OpenFOAM®: • The gradient limiter implementation in OpenFOAM®, uses a blending factor .

It can be any method

cellMDLimited Less diffusive


cellLimited gradSchemes
{
faceMDLimited default cellMDLimited Gauss linear ;
faceLimited }
More diffusive

Gradient limiter scheme

• Cell limiters will limit cell-to-cell values.


• Setting to 0 is equivalent to turning off the gradient limiter. You gain accuracy but the solution
• Face limiters will limit face-to-cell values. might become unbounded.
• The multi-directional (dimensional) limiters (cellMDLimited and faceMDLimited), will apply the • By setting the blending factor equal to 1 the limiter is always on. You gain stability but you give
limiter in each face direction separately. up accuracy (due to gradient clipping).
• The standard limiters (cellLimited and faceLimited), will apply the limiter to all components of • If you set the blending factor to 0.5, you get the best of both worlds.
the gradient.
• You can use limiters with all gradient discretization schemes.
• The default method is the Minmod.
756 757
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes Laplacian terms discretization schemes
• There are many Laplacian terms discretization schemes available in OpenFOAM®. • The limited method uses a blending factor .
• You will find the source code in the following directory: Surface normal gradients discretization

• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/snGradSchemes
Only option
laplacianSchemes
{
• These are the Laplacian terms discretization schemes that you will use most of the times: default Gauss linear limited ;
• orthogonal: mainly limited for hexahedral meshes with no grading (a perfect mesh). }
Second order accurate, bounded on perfect meshes, without non-orthogonal
corrections.
Interpolation method of the diffusion coefficient
• corrected: for meshes with grading and non-orthogonality. Second order accurate,
bounded depending on the quality of the mesh, with non-orthogonal corrections. • Setting to 1 is equivalent to using the corrected method. You gain accuracy, but the solution
• limited: for meshes with grading and non-orthogonality. Second order accurate, might become unbounded.
bounded depending on the quality of the mesh, with non-orthogonal corrections.
• By setting the blending factor equal to 0 is equivalent to using the uncorrected method. You
• uncorrected: usually used on bad quality meshes with grading and non-orthogonality. give up accuracy but gain stability.
Second order accurate, without non-orthogonal corrections. Stable but more diffusive
• If you set the blending factor to 0.5, you get the best of both worlds. In this case, the non-
than the limited and corrected methods.
orthogonal contribution does not exceed the orthogonal part. You give up accuracy but gain
stability.

758 759

Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes Laplacian terms discretization schemes
• The limited method uses a blending factor . • The surface normal gradients terms usually use the same method as the one chosen for the
Surface normal gradients discretization Laplacian terms.
• For instance, if you are using the limited 1 method for the Laplacian terms, you can use the
laplacianSchemes Only option same method for snGradSchemes:
{
default Gauss linear limited ;
}
laplacianSchemes
{
Interpolation method of the diffusion coefficient
default Gauss linear limited 1;
}
• For meshes with non-orthogonality less than 75, you can set the blending factor to 1.
snGradSchemes
• For meshes with non-orthogonality between 75 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 default limited 1;
definitely want to use that mesh, you can set the blending factor to 0.333, 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).

760 761
Finite Volume Method: A Crash introduction Finite Volume Method: A Crash introduction
What method should I use? A very accurate but oscillatory numerics
ddtSchemes • This setup is recommended for most of ddtSchemes • If you are looking for more accuracy, you can use
{ {
default CrankNicolson 0;
the cases. default backward;
this method.
} }
gradSchemes • It is equivalent to the default method you will find in gradSchemes • In overall, this setup is second order accurate but
{ commercial solvers. { oscillatory.
default cellLimited Gauss linear 1; default Gauss leastSquares;
grad(U) cellLimited Gauss linear 1; • In overall, this setup is second order accurate and } • Use this setup with LES simulations or laminar
} divSchemes
divSchemes
fully bounded. { flows with no complex physics, and meshes with
{ default none; overall good quality.
default none;
• According to the quality of your mesh, you will need div(phi,U) Gauss linear;
div(phi,U) Gauss linearUpwindV grad(U); to change the blending factor of the div(phi,omega) Gauss linear; • Use this method with good quality meshes.
div(phi,omega) Gauss linearUpwind default; laplacianSchemes and snGradSchemes div(phi,k) Gauss linear;
div(phi,k) Gauss linearUpwind default; div((nuEff*dev(T(grad(U))))) Gauss linear;
keywords. }
div((nuEff*dev(T(grad(U))))) Gauss linear;
laplacianSchemes
}
laplacianSchemes
• To keep temporal diffusion to a minimum, use a CFL {
{ number less than 2. }
default Gauss linear limited 1;
default Gauss linear limited 1;
interpolationSchemes
} • If during the simulation the turbulence quantities {
interpolationSchemes
{
become unbounded, you can safely change the default linear;
}
default linear; discretization scheme to upwind. After all, snGradSchemes
}
snGradSchemes
turbulence is diffusion. {
default limited 1;
{
}
default limited 1;
}

762 763

Finite Volume Method: A Crash introduction Roadmap


A very stable but too diffusive numerics
ddtSchemes • If you are looking for extra stability, you can use this
{
method.
1. Finite Volume Method: A Crash Introduction
default Euler;
}
gradSchemes • This setup is very stable but too diffusive.
{
default
grad(U)
cellLimited Gauss linear 1;
cellLimited Gauss linear 1;
• This setup is first order in space and time.
2. On the CFL number
}
• You can use this setup to start the solution in the
divSchemes
{
presence of bad quality meshes or strong 3. Numerical playground
default none;
discontinuities.
div(phi,U)
div(phi,omega)
Gauss upwind;
Gauss upwind;
• Remember, you can start using a first order method 4. Linear solvers in OpenFOAM®
div(phi,k) Gauss upwind; and then switch to a second order method.
}
div((nuEff*dev(T(grad(U))))) Gauss linear;
• Start robustly, end with accuracy. 5. Pressure-Velocity coupling in OpenFOAM®
laplacianSchemes
{
default Gauss linear limited 0.5;
6. Unsteady and steady simulations
}
interpolationSchemes
{ 7. Understanding residuals
default linear;
}
snGradSchemes
{
8. Boundary and initial conditions
default limited 0.5;
}

764 765
On the CFL number On the CFL number
• First at all, what is the CFL or Courant number? • Let us talk about the CFL number condition.
• In one dimension, the CFL number is defined as, • The CFL number condition is the maximum allowable CFL number a numerical
scheme can use.
• For the N dimensional case, the CFL number condition becomes,

• The CFL number is a measure of how much information ( ) traverses a


computational grid cell ( ) in a given time-step ( ).
• The CFL number is a necessary condition to guarantee the stability of the numerical
scheme. • To get a better idea of the importance of the CFL number condition, let us talk about
• But not all numerical schemes have the same stability requirements. explicit and implicit methods.

• By doing a linear stability study, we can find the stability requirements of each • Explicit and implicit methods are approaches used for obtaining the approximate
numerical scheme (but this is out of the scope of this lecture). numerical solution of time-dependent ODEs and PDEs.
• Explicit and implicit methods have different stability requirements.
• Also, the implementation details are different.
766 767

On the CFL number On the CFL number


Explicit methods Implicit methods Explicit methods Implicit methods
• For a given variable, the unknown value in each • For a given variable, the unknown value in each • Explicit methods are conditionally stable. • Implicit numerical methods are unconditionally
cell is computed using a relation that includes cell is computed using a relation that includes stable.
• They have a constraint on the maximum
only existing values. Therefore, each unknown both existing and unknown values from
allowable CFL number (CFL number condition). • In other words, they are not constrained to the
will appear in only one equation in the system neighboring cells. Therefore each unknown will
CFL number condition.
and the equations for the unknown value in appear in more than one equation in the • If you choose a CFL number larger than the
each cell can be solved one at a time to give the system, and these equations must be solved maximum allowable by the explicit method, your • However, the fact that you are using a numerical
unknown quantities. simultaneously to give the unknown quantities. numerical solution will become unstable and it method that is unconditionally stable, does not
will diverge. mean that you can choose a time step of any
• In the figure, N is the current time level. We do • In the figure, N is the current time level. We do
size.
not know the solution in this level. not know the solution in this level. • Usually, the maximum allowable CFL number is
limited to 1.0. • The time-step must be chosen in such a way
• N – 1 is the previous time level, where we know • N – 1 is the previous time level, where we know
that it resolves the time-dependent features,
the solution in all control volumes. the solution in all control volumes. • Some explicit methods have a CFL condition
and it maintains the solver stability.
of 0.5, and some of them can go up to 2.0
• When we use implicit methods, we need to
• In OpenFOAM® you will find explicit solvers
assemble a large system of equations.
(last time we checked there was only one
solver). • The memory requirements of implicit methods
are much higher than those of explicit methods.
• In OpenFOAM®, most of the solvers are
implicit.

768 769
On the CFL number On the CFL number
Some facts of explicit and implicit methods The CFL number for dummies
• For the same CFL number, the time-step of explicit methods is usually an order of magnitude lower than the • I like to see the CFL number as follows,
time-step required for implicit methods.
• This means that they are approximately ten times slower than implicit methods.
• Explicit methods are extremely accurate, but they have terrible time steps constraints.
• The memory requirements are really low and they are extremely easy to parallelize.
• Explicit methods perform really well in GPUs.
• Also, explicit methods are extremely fast (clock time per iteration), and easy to implement • It is an indication of the amount of information that
• In order to arrive to a converged solution you will need to perform a lot of iterations. This is mainly related to the
propagates through one cell (or many cells), in one
time step constraint.
• If you are interested in using large time steps (large CFL number) you will need to use implicit methods.
time-step.
• Due to the fact that implicit methods let you use large time steps, you can arrive to a converge solution much
faster than with explicit methods.
• Also, implicit methods tend to be more stable than explicit methods.
• It is highly advisable that you choose a time step in such a way that it resolves the temporal scales. • By the way, and this is extremely important, the CFL condition is a necessary
• If you use large time steps with implicit methods, it is likely that you will need to increase the cell count in order condition for stability (and hence convergence).
to maintain the accuracy of the solution, and this translates in an increased computational cost.
• But it is not always sufficient to guarantee stability.
• 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. • Other properties of the discretization schemes that you should observe are:
• But as we are often interested in the unsteadiness of the solution, we usually use a CFL number in the order of conservationess, boundedness, transportiveness, and accuracy.
1.0
• The CFL number is not a magical number!
770 771

On the CFL number On the CFL number


How to control the CFL number How to control the CFL number

application pimpleFoam; • You can control the CFL number by changing the mesh cell application pimpleFoam; • The option adjustTimeStep will automatically adjust the time
size or changing the time-step size. step to achieve the maximum desired courant number
startFrom latestTime; startFrom latestTime;
(maxCo) or time-step size (maxDeltaT).
startTime 0; • The easiest way is by changing the time-step size. startTime 0;
• When any of these conditions is reached, the solver will stop
stopAt endTime; • If you refine the mesh, and you would like to have the same stopAt endTime;
scaling the time-step size.
endTime 10; CFL number as the base mesh, you will need to decrease the endTime 10;

deltaT 0.0001;
time-step size. deltaT 0.0001;
• To use these features, you need to turn-on the option
adjustTimeStep.
writeControl runTime; • On the other side, if you coarse the mesh and you would like writeControl runTime;

writeInterval 0.1;
to have the same CFL number as the base mesh, you will writeInterval 0.1;
• Remember, the first time step of the simulation is done using
need to increase the time-step size. the value defined with the keyword deltaT and then it is
purgeWrite 0; purgeWrite 0;
automatically scaled (up or down), to achieve the desired
• The keyword deltaT controls the time-step size of the
writeFormat ascii; writeFormat ascii; maximum values (maxCo and maxDeltaT).
simulation (0.0001 seconds in this generic case).
writePrecision 8; writePrecision 8;
• It is recommended to start the simulation with a low time-step
• If you use a solver that supports adjustable time-step
writeCompression off; writeCompression off;
in order to let the solver scale-up the time-step size.
(adjustTimeStep), you can set the maximum CFL number
timeFormat general; timeFormat general;
and maximum allowable time-step using the keywords • If you want to change the values on-the-fly, you need to turn-
timePrecision 6;
maxCo and maxDeltaT, respectively. timePrecision 6;
on the option runTimeModifiable.
runTimeModifiable yes; runTimeModifiable yes;
• The feature adjustTimeStep is only present in the PIMPLE
adjustTimeStep yes; adjustTimeStep yes;
family solvers, but it can be added to any solver by modifying
maxCo 2.0; maxCo 2.0; the source code.
maxDeltaT 0.001; maxDeltaT 0.001;

772 773
On the CFL number Roadmap
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. 1. Finite Volume Method: A Crash Introduction
Courant Number mean: 0.10863988 max: 0.73950028
deltaT = 0.001 Current time-step
Courant number (mean and maximum values) 2. On the CFL number
Time = 30.000289542261612 Simulation time

PIMPLE: iteration 1 One PIMPLE iteration (outer loop), this is equivalent to PISO 3. Numerical playground
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
4. Linear solvers in OpenFOAM®
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
5. Pressure-Velocity coupling in OpenFOAM®
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
6. Unsteady and steady simulations
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
7. Understanding residuals
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
8. Boundary and initial conditions
yPlus yplus output:
patch square y+ : min = 0.44603573, max = 6.3894913, average = 2.6323389
writing field yPlus
774 775

Numerical playground Numerical playground


• We will not run this case, this is a visual and mental exercise
only.

Merry-go-round: • You will find this case in the directory


Pure convection of a passive scalar in a vector $PTOFC/101FVM/pureConvection
field – One dimensional tube.
• 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 focus our brain.

776 777
Numerical playground Numerical playground
Pure convection of a scalar in a vector field – One dimensional tube. • 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

U = zeroGradient
T = zeroGradient

U = (1 0 0) U = zeroGradient
T=1 T = zeroGradient

(0 0 0) (1 0 0)
U = zeroGradient
T = zeroGradient www.wolfdynamics.com/wiki/pureconvection/xani2.gif

Initial conditions
U = (1 0 0)
T=0

778 779

Numerical playground Numerical playground


Comparison of different spatial discretization schemes. Comparison of different spatial discretization schemes. Comparison of different gradient limiters. Comparison of different gradient limiters.
Euler in time – 100 cells – CFL = 0.1 Euler in time – 100 cells – CFL = 0.1 Linear upwind in space – Euler in time – 100 cells – Linear upwind in space – Euler in time – 100 cells –
Linear limiter functions on the Sweby diagram. Non-linear limiter functions on the Sweby diagram. CFL 0.1 CFL 0.1

780 781
Numerical playground Numerical playground
Comparison of different temporal discretization Comparison of Crank Nicolson blending factor using Comparison of Crank Nicolson blending factor using Comparison of Crank Nicolson blending factor using
schemes and gradient limiters. cellLimited leastSquares 0.5 gradient limiter. cellLimited leastSquares 0.5 gradient limiter. cellMDLimited Gauss linear 1.0 gradient limiter.
Linear upwind in space – 100 cells – CFL 0.1 Linear upwind in space – 100 cells – CFL 0.1 Linear upwind in space – 100 cells – CFL 0.1 Linear upwind in space – 100 cells – CFL 0.1

782 783

Numerical playground Numerical playground


• This case was for your eyes and brain only, but we encourage you to reproduce all
Comparison of different time-step size (different CFL Comparison of different mesh sizes. the previous results,
number). Linear upwind in space – Euler in time
Linear upwind in space – Euler in time – 100 cells • 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.

784 785
Numerical playground Numerical playground
• We will not run this case, this is a visual and mental exercise
only.
• You will find this case in the directory
Slide:
$PTOFC/101FVM/laplace
2D Laplace equation in a square domain.
• 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 focus our brain.

786 787

Numerical playground Numerical playground


2D Laplace equation in a square domain 2D Laplace equation in a square domain
• This case consist of one domain and three different element types.

Domain

Detailed section view

788 Hexahedral mesh Triangular mesh Polyhedral mesh 789


Numerical playground Numerical playground
2D Laplace equation in a square domain 2D Laplace equation in a square domain

• We will study the influence of the element type on the gradients computation.
A B
• We will study the influence of the gradSchemes method and laplacianSchemes gradSchemes:
method on the solution. Gauss linear

laplacianSchemes:
Gauss linear orthogonal

A. Hexahedral mesh
B. Triangular mesh
This problem has the following C. Polyhedral mesh
analytical solution:
C

T field
790 791

Numerical playground Numerical playground


2D Laplace equation in a square domain 2D Laplace equation in a square domain

A B gradSchemes:
A B gradSchemes:
Gauss linear Gauss linear

laplacianSchemes: laplacianSchemes:
Gauss linear orthogonal Gauss linear limited 1

A. Hexahedral mesh A. Hexahedral mesh


B. Triangular mesh B. Triangular mesh
C. Polyhedral mesh C. Polyhedral mesh

C C

field field
792 793
Numerical playground Numerical playground
2D Laplace equation in a square domain 2D Laplace equation in a square domain

A B gradSchemes:
A B gradSchemes:
Gauss leastSquares Gauss leastSquares

laplacianSchemes: laplacianSchemes:
Gauss linear orthogonal Gauss linear limited 1

A. Hexahedral mesh A. Hexahedral mesh


B. Triangular mesh B. Triangular mesh
C. Polyhedral mesh C. Polyhedral mesh

C C

field field
794 795

Numerical playground Numerical playground


2D Laplace equation in a square domain • 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
Sampling location – Polyhedral mesh 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.

Scalar T
796 797
Numerical playground Numerical playground
Flow in a lid-driven square cavity – Re = 100
Non-orthogonal mesh vs. orthogonal mesh

Swing:
Flow in a lid-driven square cavity – Re = 100
Effect of grading and non-orthogonality on the
accuracy of the solution

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.

• We will use this case to learn how to adjust the numerical schemes according to
mesh non-orthogonality and grading.
798 799

Numerical playground Numerical playground


LaplacianSchemes orthogonal – No corrections LaplacianSchemes limited 1 – Non-orthogonal corrections
Y centerline Y centerline

• And as CFD is not only about pretty colors, we should also And as CFD is not only about pretty colors, we should also
validate the results validate the results
X centerline X centerline

High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin. U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 800 Journal of computational physics, 48, 387-411 (1982) 801
Numerical playground Numerical playground
How to adjust the numerical method to deal with non-orthogonality How to adjust the numerical method to deal with non-orthogonality
17 ddtSchemes • In the dictionary fvSchemes we can enable non- 17 solvers • Additionally, in the dictionary fvSolution we need to
18 { 18 {
19 default backward; orthogonal corrections. 19 p define the number of PISO corrections (nCorrectors) and
20 } 20 { non-orthogonal corrections (nNonOrthogonalCorrectors).
21 • Non-orthogonal corrections are chosen using the 21 solver PCG;
22 gradSchemes 22 preconditioner DIC;
23 { keywords laplacianSchemes and snGradSchemes. 23 tolerance 1e-06; • You need to do at least one PISO correction. Increasing the
24 default Gauss linear; 24 relTol 0; number of PISO correctors will improve the stability and
25 //default cellMDLimited Gauss linear 1; • These are the laplacianSchemes and 38 }
26 39 accuracy of the solution at a higher computational cost.
27 grad(p) Gauss linear; snGradSchemes schemes that you will use most of the 40 pFinal
28
29
}
times: 41
42
{
$p;
• For orthogonal meshes, 1 PISO correction is ok. But as
30 divSchemes 43 relTol 0; most of the time you will deal with non-orthogonal meshes,
31 { • orthogonal: second order accurate, bounded on 44 }
doing 2 PISO corrections is a good choice.
32
33
default
//div(phi,U)
none;
Gauss linearUpwind default;
perfect meshes, without non-orthogonal 45
46 U
34 div(phi,U) Gauss linear; corrections. 47 { • If you are using a method with non-orthogonal corrections
35 } 48 solver smoothSolver;
36 • corrected: second order accurate, bounded 49 smoother symGaussSeidel; (corrected or limited 1-0.5), you need to define the number
37
38
laplacianSchemes
{ depending on the quality of the mesh, with non-
50
51
tolerance
relTol
1e-08;
0;
of non-orthogonal corrections (nNonOrthogonalCorrectors).
39
40
default
//default
Gauss linear orthogonal;
Gauss linear limited 1;
orthogonal corrections. 52
53 }
}
• If you use 0 nNonOrthogonalCorrectors, you are
41
42
}
• limited : second order accurate, bounded
54
55 PISO
computing the initial approximation using central differences
43 interpolationSchemes depending on the quality of the mesh, with non- 56 { (accurate but unstable), with no explicit correction.
44 { 57 nCorrectors 1;
45 default linear; orthogonal corrections. 58 nNonOrthogonalCorrectors 0;
• To take into account the non-orthogonality of the mesh, you
46 } 59 pRefCell 0;
47 • uncorrected: second order accurate, without 60 pRefValue 0; will need to increase the number of corrections (you get
48 snGradSchemes 61 }
49 { non-orthogonal corrections. Stable but more better approximations using the previous correction).
50
51
default
//default
orthogonal;
limited 1;
diffusive than limited and corrected. • Usually 2 nNonOrthogonalCorrectors is ok.
52 }

802 803

Numerical playground Numerical playground


What are we going to do?
• We will now illustrate a few of the discretization schemes available in
OpenFOAM® using a model case. • This is the same case as the one we used during the first tutorial session.

• We will use the lid-driven square cavity case to study the effect of grading • The only difference is that we have modified the mesh a little bit in order to add
grading and non-orthogonality.
and non-orthogonality on the accuracy of the solution
• After generating the mesh, we will use the utility checkMesh to control the quality of
• This case is located in the directory:
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.
$PTOFC/101FVM/nonorthoCavity/
• To find the solution we will use icoFoam.
• 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.
• From this point on, please follow me.
• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
804 805
Numerical playground Numerical playground
Running the case To run the case, follow these steps
• You will find this tutorial in the directory $PTOFC/101FVM/nonorthoCavity • First run the case using the original dictionaries. Did it crash right?
• In the terminal window type: • 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
1. $> foamCleanTutorials more time-steps, right?
2. $> blockMesh • Now increase the number of PISO corrections to 2 (nCorrectors). Did it run?

3. $> checkMesh • 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
4. $> icoFoam | log variables (U and p).
5. $> postProcess -func sampleDict -latestTime • Now set the number of nNonOrthogonalCorrectors to 0. Did it crash right? This is telling us
that the mesh is sensitive to the gradients.
6. $> gnuplot gnuplot/gnuplot_script
• Now change the laplacianSchemes and snGradSchemes to limited 0 (uncorrected). In this
7. $> paraFoam 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?
806 807

Numerical playground Numerical playground


• When it comes to laplacianSchemes and snGradSchemes this is how we
proceed most of the times (a robust setup),

laplacianSchemes
{
Seesaw:
}
default Gauss linear limited 1; PISO
{ Sod’s shock tube.
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.
808 809
Numerical playground Numerical playground
Sod’s shock tube High Purity Photolysis Shock Tube (NASA 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.

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
810 Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose. 811

Numerical playground Numerical playground


Sod’s shock tube Sod’s shock tube

All walls are slip

Boundary conditions and initial conditions Analytical solution


812 813
Numerical playground Numerical playground
Sod’s shock tube Sod’s shock tube
www.wolfdynamics.com/wiki/shocktube/aniT.gif www.wolfdynamics.com/wiki/shocktube/aniU.gif

Pressure field Density field

www.wolfdynamics.com/wiki/shocktube/anip.gif www.wolfdynamics.com/wiki/shocktube/anigt.gif

Velocity magnitude field Temperature field


814 815

Numerical playground Numerical playground


What are we going to do?
• We will now illustrate a few of the discretization schemes available in • Now is your turn.
OpenFOAM® using a severe model case. • You are asked to select the best discretization scheme for the physics involve.
• We will use the Sod’s shock tube case. Remember: accuracy, stability and boundedness.

• This case is located in the directory: • 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.
$PTOFC/101FVM/shockTube/ • You can start using the original dictionaries.
• To find the numerical solution we will use sonicFoam.
• sonicFoam is a transient solver for trans-sonic/supersonic, laminar or turbulent flow
of a compressible gas.
• From this point on, please follow me.
• After finding the numerical solution we will do some sampling.
• We are all going to work at the same pace.
• At the end, we will do some plotting (using gnuplot or Python) and scientific
• Remember, $PTOFC is pointing to the path where you visualization.
unpacked the tutorials.
816 817
Numerical playground Numerical playground
Running the case Running the case
• You will find this tutorial in the directory $PTOFC/101FVM/schockTube • In step 3 we generate the mesh using blockMesh.
• Before running the case, you will need to choose the discretization scheme. • In step 5 and 6 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.
• In the terminal window type:
• In step 7 we initialize the solution using setFields.
1. $> foamCleanTutorials
• In step 8 we run the simulation and save the log file.
2. $> blockMesh
• In step 9 we use the utility foamCalc to compute the magnitude of the velocity vector
3. $> checkMesh U. The output is saved as magU.
4. $> rm –rf 0 • In step 10 we use the utility postProcess to do sampling of the field variables.
5. $> cp –r 0_org 0 • Finally, in step 11 we visualize the solution using paraFoam.
6. $> setFields
7. $> sonicFoam | tee log
8. $> foamCalc mag U
9. $> postProcess -func sampleDict -latestTime
10. $> paraFoam
818 819

Numerical playground Some FVM/CFD references


• As we mentioned earlier this is not a FVM/CFD course, but we highly advise you to take some time and study the theory in depth.
Running the case • There is vast amount of literature in the field of FVM/CFD. We will give you some of our favorite references, which are closed related to what
you will find in OpenFOAM®.
• To plot the analytical solution against the numerical solution, go to the directory • Therefore, we are involuntarily omitting other references which are equally or even more important.
python and run the Python script. • The Finite Volume Method in Computational Fluid Dynamics: An Advanced Introduction With OpenFOAM and Matlab
F. Moukalled, L. Mangani, M. Darwish. 2015, Springer-Verlag
• In the terminal window type: • Finite Volume Methods for Hyperbolic Problems
R. Leveque. 2002, Cambridge University Press
• Computational Gasdynamics
C. Laney. 1998, Cambridge University Press
1. $> cd python • Computational Techniques for Multiphase Flows
G. H. Yeoh, J. Tu. 2009, Butterworth-Heinemann
2. $> python sodschocktube.py • An Introduction to Computational Fluid Dynamics
H. K. Versteeg, W. Malalasekera. 2007, Prentice Hall
• Computational Fluid Dynamics: Principles and Applications
J. Blazek. 2006, Elsevier Science

• The Python script will save four .png files with the solution. • Computational Methods for Fluid Dynamics
J. H. Ferziger, M. Peric. 2001, Springer
• Feel free to explore and adapt the Python script to your needs. • Numerical Heat Transfer and Fluid Flow
S. Patankar. 1980, Taylor & Francis
• Remember, Python must be installed in order to use the script. • A Finite Volume Method for the Prediction of Three-Dimensional Fluid Flow in Complex Ducts
M. Peric. PhD Thesis. 1985. Imperial College, London
• We use Anaconda Python 2.7 • Error analysis and estimation in the Finite Volume method with applications to fluid flows
H. Jasak. PhD Thesis. 1996. Imperial College, London
• Computational fluid dynamics of dispersed two-phase flows at high phase fractions
H. Rusche. PhD Thesis. 2002. Imperial College, London
• High Resolution Schemes Using Flux Limiters for Hyperbolic Conservation Laws
P. K. Sweby SIAM Journal on Numerical Analysis, Vol. 21, No. 5. (Oct., 1984), pp. 995-1011

820 821
Roadmap Linear solvers in OpenFOAM®
• After spatial and temporal discretization and by using equation

1. Finite Volume Method: A Crash Introduction


2. On the CFL number in every control volume of the domain, a system of linear algebraic equations for
the transported quantity is assembled
3. Numerical playground
4. Linear solvers in OpenFOAM®
5. Pressure-Velocity coupling in OpenFOAM®
6. Unsteady and steady simulations
7. Understanding residuals
8. Boundary and initial conditions
• This system can be solved by using any iterative or direct method.
822 823

Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®


Linear solvers Linear solvers
solvers • The equation solvers, tolerances, and algorithms are controlled solvers • In this generic case, to solve the pressure (p) we are using the
{ from the sub-dictionary solvers located in the fvSolution { PCG method with the DIC preconditioner, an absolute tolerance
p p
{
dictionary file. {
equal to 1e-06 and a relative tolerance relTol equal to 0.
solver PCG; solver PCG;
• In the dictionary file fvSolution, and depending on the • The entry pFinal refers to the final pressure correction (notice
preconditioner DIC; preconditioner DIC;
tolerance 1e-06; solver you are using you will find the additional sub- tolerance 1e-06; that we are using macro syntax), and we are using a relative
relTol 0; dictionaries PISO, PIMPLE, and SIMPLE, which will be relTol 0; tolerance relTol equal to 0.
} }
described later.
pFinal pFinal • To solve the velocity field (U) we are using the PBiCGStab
{ • In this dictionary is where we are telling OpenFOAM® how to { method with the DILU preconditoner, an absolute tolerance
$p; crunch numbers. $p; equal to 1e-08 and a relative tolerance relTol equal to 0.
relTol 0; relTol 0;
} • The solvers sub-dictionary specifies each linear-solver that is } • The linear solvers will iterative until reaching any of the
U U
{
used for each equation being solved. {
tolerance values set by the user or reaching a maximum value
solver PBiCGStab; solver PBiCGStab; of iterations (optional entry).
• If you forget to define a linear-solver, OpenFOAM® will let you
preconditioner DILU; preconditioner DILU;
tolerance 1e-08; know what are you missing. tolerance 1e-08; • FYI, solving for the velocity is relative inexpensive, whereas
relTol 0; relTol 0; solving for the pressure is expensive.
} • The syntax for each entry within the solvers sub-dictionary }
} uses a keyword that is the word relating to the variable being } • The pressure equation is particularly important as it governs
solved in the particular equation and the options related to the mass conservation.
PISO linear-solver. PISO
{ { • If you do not solve the equations accurately enough (tolerance),
nCorrectors 2; nCorrectors 2; the physics might be wrong.
nNonOrthogonalCorrectors 1; nNonOrthogonalCorrectors 1;
} } • Selection of the tolerance is of paramount importance.

824 825
Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®
Linear solvers Linear solvers
solvers • The linear solvers distinguish between symmetric matrices and solvers • The linear solvers are iterative, i.e., they are based on reducing
{ asymmetric matrices. { the equation residual over a succession of solutions.
p p
{ • The symmetry of the matrix depends on the structure of the { • The residual is a measure of the error in the solution so that the
solver PCG; solver PCG;
preconditioner DIC;
equation being solved. preconditioner DIC;
smaller it is, the more accurate the solution.
tolerance 1e-06; tolerance 1e-06;
• Pressure is a symmetric matrix and velocity is an asymmetric • More precisely, the residual is evaluated by substituting the
relTol 0; relTol 0;
} matrix. } current solution into the equation and taking the magnitude of
pFinal pFinal the difference between the left and right hand sides (L2-norm).
{ • If you use the wrong linear solver, OpenFOAM® will complain {
$p; and will let you know what options are valid. $p;
relTol 0; relTol 0;
}
• In the following error screen, we are using a symmetric solver }
U for an asymmetric matrix, U
{ {
solver PCG; –> FOAM FATAL IO ERROR : solver PBiCGStab;
• It is also normalized to make it independent of the scale of the
preconditioner DILU; Unknown asymmetric matrix solver PCG preconditioner DILU;
tolerance 1e-08; tolerance 1e-08; problem being analyzed.
relTol 0; relTol 0;
} Valid asymmetric matrix solvers are : }
} }

4
PISO PISO
{
( {
nCorrectors 2; BICCG nCorrectors 2;
nNonOrthogonalCorrectors 1; GAMG nNonOrthogonalCorrectors 1;
} }
P
smoothSolver
) 826 827

Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®


Linear solvers Linear solvers
solvers • Before solving an equation for a particular field, the initial • These are the linear solvers available in OpenFOAM®:
{ residual is evaluated based on the current values of the field.
p
{ • After each solver iteration the residual is re-evaluated. The
solver PCG;
solver stops if either of the following conditions are reached: • GAMG → Multigrid solver
preconditioner DIC;
tolerance 1e-06;
• The residual falls below the solver tolerance, tolerance. • PBiCG → Newton-Krylov solver
relTol 0;
} • The ratio of current to initial residuals falls below the • PBiCGStab → Newton-Krylov solver
pFinal
{ solver relative tolerance, relTol. • PCG → Newton-Krylov solver
$p; • The number of iterations exceeds a maximum number of
relTol 0;
• smoothSolver → Smooth solver
}
iterations, maxIter.
U
• diagonalSolver
• The solver tolerance should represent the level at which the
{
solver PBiCG; residual is small enough that the solution can be deemed
preconditioner DILU; sufficiently accurate.
tolerance
relTol
1e-08;
0; • The keyword maxIter is optional and the default value is 1000.
• You will find the source code of the linear solvers in the following directory:
minIter
maxIter
3;
100; • The user can also define the minimum number of iterations • $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/solvers
} using the keyword minIter. This keyword is optional and the
}
default value is 0.
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
828 829
Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®
Linear solvers Linear solvers
• When using Newton-Krylov solvers, you need to define preconditoners. • As you can see, when it comes to linear solvers there are many options and
• These are the preconditioners available in OpenFOAM®: combinations available in OpenFOAM®.
• DIC • FDIC • diagonal • When it comes to choosing the linear solver, there is no written theory.
• DILU • GAMG • noPreconditioner • It is problem and hardware dependent (type of the mesh, physics involved,
processor cache memory, network connectivity, partitioning method, and so
• You will find the source code in the following directory:
on).
• $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/preconditioners
• Most of the times using the GAMG method (geometric-algebraic multi-grid),
is the best choice for symmetric matrices (e.g., pressure).
• The smoothSolver solver requires the specification of a smoother.
• The GAMG method should converge fast (less than 20 iterations). If it’s
• These are the smoothers available in OpenFOAM®: taking more iterations, try to change the smoother.
• DIC • DILUGaussSeidel • nonBlockingGaussSeidel • And if it is taking too long or it is unstable, use the PCG solver.
• DICGaussSeidel • FDIC • symGaussSeidel
• When running with many cores (more than 1000), using the PCG might be a
• DILU • GaussSeidel better choice.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/smoothers 830 831

Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®


Linear solvers Linear solvers
• For asymmetric matrices, the PBiCGStab method with DILU preconditioner is a good • A few comments on the linear solvers residuals (we will talk about monitoring the
choice. residuals later on).
• The smoothSolver solver with smoother GaussSeidel, also performs very well. • Residuals are not a direct indication that you are converging to the right solution.
• If the PBiCGStab method with DILU preconditioner mysteriously crashed with an • The first time-steps the solution might not converge, this is acceptable.
error related to the preconditioner, use the smoothSolver or change the • Also, you might need to use a smaller time-step during the first iterations to
preconditioner. maintain solver stability.
• But in general the PBiCGStab solver should be faster than the smoothSolver • If the solution is not converging, try to reduce the time-step size.
solver.
• Remember, asymmetric matrices are assembled from the velocity (U), and the
Time = 50
transported quantities (k, omega, epsilon, T, and so on).
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
• Usually, computing the velocity and the transported quantities is inexpensive and fast, 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
so it is a good idea to use a tight tolerance (1e-8) for these fields. time step continuity errors : sum local = 4.0107145e-11, global = -5.0601748e-20, cumulative = 2.637831e-18
ExecutionTime = 4.47 s ClockTime = 5 s
• The diagonal solver is used for back-substitution, for instance, when computing fieldMinMax minmaxdomain output:
density using the equation of state (we know p and T). 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

832 833
Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®
Linear solvers Linear solvers
• So how do we set the tolerances? • For the velocity field (U) and the transported quantities (asymmetric matrices), you
• The pressure equation is particularly important, so we should resolve it accurately. can use the following criterion.
Solving the pressure equation is the expensive part of the whole iterative process. • Solving for these variables is relative inexpensive, so you can start right away with a
• For the pressure equation you can start the simulation with a tolerance equal to 1e-6 tight tolerance
and relTol equal to 0.01. After a while you change these values to 1e-6 and 0.0,
respectively.
Loose tolerance Tight tolerance
• If the solver is too slow, you can change the convergence criterion to 1e-4 and relTol
equal to 0.05. You usually will do this during the first iterations.
U U
{ {
Loose tolerance Tight tolerance solver PBiCGStab; solver PBiCGStab;
preconditioner DILU; preconditioner DILU;
tolerance 1e-8; tolerance 1e-8;
relTol 0.01; relTol 0.0;
p p } }
{ {
solver PCG; solver PCG;
preconditioner DIC; preconditioner DIC;
tolerance 1e-6; tolerance 1e-6;
relTol 0.01; relTol 0.0;
} }

834 835

Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®


Linear solvers Linear solvers
• It is also a good idea to set the minimum number of iterations (minIter) to 3. • When you use the PISO or PIMPLE method, you also have the option to set the
• If your solver is doing too many iterations, you can set the maximum number of tolerance for the final pressure corrector step (pFinal).
iterations (maxIter). • By proceeding in this way, you can put all the computational effort only in the last
• But be careful, if the solver reach the maximum number of iterations it will stop, we corrector step (pFinal).
are talking about unconverged iterations. • For all the intermediate corrector steps, you can use a more relaxed convergence
• Setting the maximum number of iterations is specially useful during the first time- criterion.
steps where the linear solver takes longer to converge. • For example, you can use the following solver and tolerance criterion for all the
• You can set minIter and maxIter in all symmetric and asymmetric linear solvers. intermediate corrector steps (p), then in the final corrector step (pFinal) you tight the
solver tolerance.
p Loose tolerance for p Tight tolerance for pFinal
{
solver PCG;
preconditioner DIC; p pFinal
tolerance 1e-6; { {
relTol 0.01; solver PCG; solver PCG;
minIter 3; preconditioner DIC; preconditioner DIC;
tolerance 1e-4; tolerance 1e-6;
maxIter 100;
relTol 0.05; relTol 0.0;
} } }

836 837
Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®
Linear solvers Linear solvers
• When you use the PISO or PIMPLE method, you also have the option to set the • As we are solving a sparse matrix, the more diagonal the matrix is, the best the
tolerance for the final pressure corrector step (pFinal). convergence rate will be.
• By proceeding in this way, you can put all the computational effort only in the last • So it is highly advisable to use the utility renumberMesh before running the
corrector step (pFinal in this case). simulation.
• For all the intermediate corrector steps (p), you can use a more relaxed convergence
criterion. • $> renumberMesh -overwrite
• If you proceed in this way, it is recommended to do at least 2 corrector steps
(nCorrectors).
• The utility renumberMesh can dramatically increase the speed of the linear solvers,
Courant Number mean: 0.10556573 max: 0.65793603
deltaT = 0.00097959184
Time = 10
specially during the firsts iterations.
PIMPLE: iteration 1
DILUPBiCG: Solving for Ux, Initial residual = 0.0024649332, Final residual = 2.3403547e-09, No Iterations 4 • You will find the source code and the master dictionary in the following directory:
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 • $WM_PROJECT_DIR/applications/utilities/mesh/manipulation/renumberMesh
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 838 839

Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®


Linear solvers On the multigrid solvers
• The idea behind reordering is to make the matrix more diagonally dominant, • The development of multigrid solvers (GAMG in OpenFOAM®), together with the
therefore, speeding up the iterative solver. 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
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.
Matrix structure plot before reordering Matrix structure plot after reordering

Note:
This is the actual pressure matrix from an OpenFOAM® model case 840 841
Linear solvers in OpenFOAM® Linear solvers in OpenFOAM®
On the multigrid solvers tolerances Linear solvers tolerances – Steady simulations
• If you go for the GAMG linear solver for symmetric matrices (e.g., pressure), the • The previous tolerances are fine for unsteady solver.
following tolerances are acceptable for most of the cases. • For extremely coupled problems you might need to have tighter tolerances.
Loose tolerance for p Tight tolerance for pFinal • You can use the same tolerances for steady solvers. However, it is acceptable to use
a looser criterion.
p pFinal
{ { • You can also set the convergence controls based on residuals of fields. The controls
solver GAMG; solver GAMG; are specified in the residualControls sub-dictionary of the dictionary file
tolerance 1e-6; tolerance 1e-6;
relTol 0.01; relTol 0;
fvSolution.
smoother GaussSeidel; smoother GaussSeidel;
nPreSweeps 0; nPreSweeps 0;
nPostSweeps 2; nPostSweeps 2; SIMPLE
cacheAgglomeration on; cacheAgglomeration on; {
agglomerator faceAreaPair; agglomerator faceAreaPair;
nCellsInCoarsestLevel 100; nCellsInCoarsestLevel 100;
nNonOrthogonalCorrectors 2;
mergeLevels 1; mergeLevels 1;
minIter 3; minIter 3; residualControl
} } {
p 1e-4; Residual control for every
U 1e-4; field variable you are solving
NOTE: }
The GAMG parameters are not optimized, that is up to you. }

Most of the times is safe to use the default parameters. 842 843

Linear solvers in OpenFOAM® Roadmap


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 1. Finite Volume Method: A Crash Introduction
IC2 smoothSolver symGaussSeidel NO 2070 2.8271198
2. On the CFL number
IC3 ICCG GAMG NO 255 2.8265538

IC4 GAMG GaussSeidel NO 1471 2.8265538


3. Numerical playground
IC5 PCG GAMG-GaussSeidel NO 302 2.8265538 4. Linear solvers in OpenFOAM®
IC6 GAMG GaussSeidel YES 438 2.8265539
5. Pressure-Velocity coupling in OpenFOAM®
IC7 PCG FDIC YES 213 2.8265535

IC8 PCG GAMG-GaussSeidel YES 283 2.8265538 6. Unsteady and steady simulations
IC9 ICCG GAMG YES 261 2.8265538
7. Understanding residuals
IC10 PCG DIC NO 244 2.8265539
8. Boundary and initial conditions
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) 844 845
Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®
• To solve the Navier-Stokes equations we need to use a solution • Many numerical methods exist to solve the Navier-Stokes equations, just to name a few:
• Pressure-correction methods (Predictor-Corrector type).
approach able to deal with the nonlinearities of the governing
• SIMPLE, SIMPLEC, SIMPLER, PISO.
equations and with the coupled set of equations.
• 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.
• 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.
Additional equations deriving from models, such as, volume fraction,
• However, both methods have been extended and reformulated to solve and operate for a wide
chemical reactions, turbulence modeling, combustion, multi-species, etc.
range of flow conditions beyond their original intent.

846 847

Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®


• Pressure-based methods are the default option in most of CFD solvers (OpenFOAM® • In OpenFOAM®, you will find segregated pressure-based solvers.
included).
• Pressure-based methods are intrinsically implicit. • The following methods are available:
• Two pressure-based solution methods are generally available, namely: • SIMPLE (Semi-Implicit Method for Pressure-Linked Equations)
• Segregated method.
• SIMPLEC (SIMPLE Corrected/Consistent)
• Coupled method.
• In the pressure-based approach the velocity field is obtained from the momentum equations • PISO (Pressure Implicit with Splitting Operators)
(there is some mathematical manipulation involved).
• In the segregated algorithm, the individual governing equations for the primitive variables are
solved one after another. • Additionally, you will find something called PIMPLE, which is an hybrid
• The coupled approach solves the continuity, momentum, and energy equation simultaneously, between SIMPLE and PISO. This method is formulated for very large time-
that is, coupled together. steps and pseudo-transient simulations.
• The segregated algorithm is memory-efficient, since the discretized equations need only be
stored in the memory one at a time.
• However, the solution convergence is relatively slow (in comparison to coupled solvers) as the • You will find the solvers in the following directory:
equations are solved one at a time.
• In OpenFOAM®, you will find segregated pressure-based solvers.
• $WM_PROJECT_DIR/applications/solvers
• But coupled pressure-based solvers are under active development.
848 849
Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®
• In OpenFOAM®, the PISO and PIMPLE methods are formulated for On the origins of the methods
unsteady simulations.
• SIMPLE
• Whereas, the SIMPLE and SIMPLEC methods are formulated for steady • S. V. Patankar and D. B. Spalding, “A calculation procedure for heat, mass and
simulations. momentum transfer in three-dimensional parabolic flows”, Int. J. Heat Mass Transfer,
15, 1787-1806 (1972).
• If conserving time is not a priority, you can use the PIMPLE method for
pseudo transient simulations. • SIMPLE-C
• J. P. Van Doormaal and G. D. Raithby, “Enhancements of the SIMPLE method for
• The pseudo transient PIMPLE method is more stable than the SIMPLE predicting incompressible fluid flows”, Numer. Heat Transfer, 7, 147-163 (1984).
method, but it has a higher computational cost.
• PISO
• Depending on the method and solver you are using, you will need to define • R. I. Issa, “Solution of the implicitly discretized fluid flow equations by operator-
a specific sub-dictionary in the dictionary file fvSolution. splitting”, J. Comput. Phys., 62, 40-65 (1985).

• For instance, if you are using the PISO method, you will need to specify the • PIMPLE
PISO sub-dictionary. • Unknown origins.
• Useful reference:
• And depending on the method, each sub-dictionary will have different • I. E. Barton, “Comparison of SIMPLE and PISO-type algorithms for transient flows, Int.
J. Numerical methods in fluids, 26,459-483 (1998).
entries.

850 851

Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®


Pressure-velocity coupling using Pressure-velocity coupling using
the SIMPLE method the PISO method The SIMPLE sub-dictionary
Initial guess p*, u*, v*, w*
• This sub-dictionary is located in the dictionary file fvSolution.
Initial guess p*, u*, v*, w*
• It controls the options related to the SIMPLE pressure-velocity coupling method.
Compute intermediate velocities
(divergent free)
u*, v*, w*
• The SIMPLE method only makes 1 correction.
Compute intermediate velocities
(divergent free)
• An additional correction to account for mesh non-orthogonality is available when using the
u*, v*, w*
SIMPLE method. The number of non-orthogonal correctors is specified by the
Solve Poisson equation for the
pressure correction p'
nNonOrthogonalCorrectors keyword.
Solve Poisson equation for the
• The number of non-orthogonal correctors is chosen according to the mesh quality. For orthogonal
pressure correction p'
meshes you can use 0, whereas, for non-orthogonal meshes it is recommended to do at least 1
p* = p Correct pressure and velocities
u* = u p** = p* + p'
v* = v u** = u* + u'
w* = w

correction.
v** = v* + v'
w** = w* + w'
p* = p
u* = u
v* = v
w* = w
Correct pressure and velocities • However, it is strongly recommended to do are least 1 non-orthogonal correction.
p = p* + p'
Solve second pressure correction
u = u* + u' equation p''
v = v* + v'
w = w* + w'

Correct pressure and velocities


p*** = p** + p''
u*** = u** + u''
v*** = v** + v''
w*** = w** + w'' SIMPLE
Solve additional transport equations
p = p***
u = u***
{
nNonOrthogonalCorrectors 1;
v = v***
w = w***

Solve additional transport equations }


No Yes
Check convergence STOP

No Yes
Check convergence STOP
852 853
Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary The SIMPLE sub-dictionary
• You can use the optional keyword consistent to enable or disable the SIMPLEC method. • Typical under-relaxation factors for the SIMPLE and SIMPLEC methods.
• This option is disable by default. • Remember the under-relaxation factors are problem dependent.
• In the SIMPLEC method, the cost per iteration is marginally higher but the convergence rate is
better so the number of iterations can be reduce. SIMPLE SIMPLEC
• The SIMPLEC method relaxes the pressure in a consistent manner and additional relaxation of
relaxationFactors relaxationFactors
the pressure is not generally necessary.
{ {
• In addition, convergence of the p-U system is better and still is reliable with less aggressive fields equations
relaxation of the momentum equation. { {
p 0.3; U 0.9;
} k 0.9;
equations omega 0.9;
SIMPLE
{ }
{
U 0.7; }
consistent yes;
k 0.7;
nNonOrthogonalCorrectors 1;
omega 0.7;
}
}
}

854 855

Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®


The SIMPLE sub-dictionary The SIMPLE loop in OpenFOAM®

SIMPLEC
fvVectorMatrix UEqn
• If you are planning to use the SIMPLEC (
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
method, we recommend you to use relaxationFactors );

under-relaxation factors are little bit more {


fields
loose that the commonly recommended solve(UEqn == -fvc::grad(p));
{
values.
p 0.7; fvScalarMatrix pEqn
• If during the simulation you still have }
(
fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
some stability problems, try to reduce all equations );

the values to 0.5. {


p 0.7;
• Remember the under-relaxation factors U = HbyA – rAU*fvc::grad(p);
U 0.7;
are problem dependent.
k 0.7;
• It is also recommended to start the omega 0.7;
simulation with low values (about 0.3), }
and then increase the values slowly up to }
0.7.
856 857
Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®
The PISO sub-dictionary The PISO sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution. • You can use the optional keyword momentumPredictor to enable or disable the momentum
• It controls the options related to the PISO pressure-velocity coupling method. predictor step.

• The PISO method requires at least one correction (nCorrectors). To improve accuracy and • The momentum predictor helps in stabilizing the solution as we are computing better
stability you can increase the number of corrections. approximations for the velocity.
• It is clear that this will add an extra computational cost, which is negligible.
• For good accuracy and stability, it is recommended to use 2 nCorrectors.
• An additional correction to account for mesh non-orthogonality is available when using the PISO • In most of the solvers, this option is enabled by default.
method. The number of non-orthogonal correctors is specified by the • It is recommended to use this option for highly convective flows (high Reynolds number). If you
nNonOrthogonalCorrectors keyword. are working with low Reynolds flow or creeping flows it is recommended to turn it off.
• The number of non-orthogonal correctors is chosen according to the mesh quality. For orthogonal • Remember, when you enable the option momentumPredictor, you will need to define the linear
meshes you can use 0, whereas, for non-orthogonal meshes it is recommended to do at least 1 solvers for the variables .*Final (we are using regex notation).
correction.

PISO
PISO
{
{
momentumPredictor yes;
nCorrectors 2;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
nNonOrthogonalCorrectors 1;
}
}
858 859

Pressure-Velocity coupling in OpenFOAM® Pressure-Velocity coupling in OpenFOAM®


The PISO loop 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.
fvVectorMatrix UEqn
( • The PIMPLE method works very similar to the PISO method. In fact, setting the keyword
);
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
nOuterCorrectors to 1 is equivalent to running using the PISO method.
• The keyword nOuterCorrectors controls a loop outside the PISO loop.
solve(UEqn == -fvc::grad(p)); • To gain more stability, especially when using large time-steps, you can use more outer correctors
(nOuterCorrectors). Have in mind that this will highly increase the computational cost.
fvScalarMatrix pEqn
(
• Also, if you use under-relaxation factors, your solution is not anymore time accurate. You are
fvm::laplacian(rAU, p) == fvc::div(phiHbyA) working in pseudo-transient simulations mode.
);

PIMPLE
U = HbyA – rAU*fvc::grad(p); {
momentumPredictor yes;
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
860 861
Roadmap Unsteady and steady simulations
• A few examples of unsteady applications:
Vortex shedding Buoyant flow
www.wolfdynamics.com/wiki/FVM_uns/ani1.gif www.wolfdynamics.com/wiki/FVM_uns/ani2.gif

1. Finite Volume Method: A Crash Introduction


2. On the CFL number
3. Numerical playground
4. Linear solvers in OpenFOAM®
5. Pressure-Velocity coupling in OpenFOAM®
6. Unsteady and steady simulations
7. Understanding residuals
8. Boundary and initial conditions
Multiphase flow
www.wolfdynamics.com/wiki/FVM_uns/ani3.gif
862 863

Unsteady and steady simulations Unsteady and steady simulations


• A few examples of unsteady applications: • Nearly all flows in nature and industrial applications are unsteady (also
Turbulent flows - SRS Sliding grids – Continuous stirred tank known as transient or time-dependent).
www.wolfdynamics.com/wiki/FVM_uns/ani4.gif reactor
www.wolfdynamics.com/wiki/FVM_uns/ani5.gif • Unsteadiness is due to:
• Instabilities.
• Non-equilibrium initial conditions.
• Time-dependent boundary conditions.
• Source terms.
• Chemical reactions.
• Moving or deforming bodies.
• Turbulence.
• Buoyancy.
• Convection.
• Multiple phases

Marine applications - Sea keeping


www.wolfdynamics.com/wiki/FVM_uns/ani6.gif
864 865
Unsteady and steady simulations Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®? 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 startFrom latestTime; • The controlDict dictionary contains runtime simulation
and maintains solver stability. controls, such as, start time, end time, time step, saving
startTime 0;
• Select the temporal discretization scheme. frequency and so on. Most of the entries are self-explanatory.
stopAt endTime;
• Set the tolerance (absolute and/or relative) of the linear solvers. • This generic case starts from time 0 (startTime), and it will run
endTime 10; up to 10 seconds (endTime).
• Monitor the CFL number.
deltaT 0.0001; • It will write the solution every 0.1 seconds (writeInterval) of
• Monitor the stability and boundedness of the solution. simulation time (runTime).
writeControl runTime;
• Monitor a quantity of interest. • The time step of the simulation is 0.0001 seconds (deltaT).
writeInterval 0.1;
• And of course, you need to save the solution with a given frequency. • It will keep all the solution directories (purgeWrite).
purgeWrite 0;
• Have in mind that unsteady simulations generate a lot of data. • It will save the solution in ascii format (writeFormat) with a
• End time of the simulation?, it is up to you. writeFormat ascii; precision of 8 digits (writePrecision).

• In the controlDict dictionary you need to set runtime parameters and general instructions on how to run the writePrecision 8; • And as the option runTimeModifiable is on (yes), we can
case (such as time step and maximum CFL number). You also set the saving frequency. modify all these entries while we are running the simulation.
writeCompression off;

• In the fvSchemes dictionary you need to set the temporal discretization scheme. timeFormat general;
• In the fvSolution dictionary you need to set the linear solvers. timePrecision 6;
• Also, you will need to set the number of corrections of the velocity-pressure coupling method used (e.g. PISO runTimeModifiable yes;
or PIMPLE), this is done in the fvSolution dictionary.
adjustTimeStep yes;
• Additionally, you may set functionObjects in the controlDict dictionary. The functionObjects are used to maxCo 2.0;
do sampling, probing and co-processing while the simulation is running. maxDeltaT 0.001;
866 867

Unsteady and steady simulations Unsteady and steady simulations


How to run unsteady simulations in OpenFOAM®? How to run unsteady simulations in OpenFOAM®?
startFrom latestTime; • In this generic case, the solver supports adjustable time-step startFrom latestTime; • A word of caution about adjustable time-step (adjustTimeStep).
(adjustTimeStep).
startTime 0; startTime 0; • This option will automatically adjust the time step to achieve the
• The option adjustTimeStep will automatically adjust the time maximum desired courant number (maxCo) or time-step size
stopAt endTime; stopAt endTime;
step to achieve the maximum desired courant number (maxCo) (maxDeltaT).
endTime 10; or time-step size (maxDeltaT). endTime 10;
• If the maxDeltaT condition is not reached, the solver will adapt
deltaT 0.0001; • When any of these conditions is reached, the solver will stop deltaT 0.0001; the time-step to achieve the target maxCo, and as the time-step
scaling the time-step size. is not fixed this might introduce spurious oscillations in the
writeControl runTime; writeControl adjustableRunTime; solution.
• 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 writeInterval 0.1; • It is recommended to use this option at the beginning of the
purgeWrite 0; automatically scaled (up or down), to achieve the desired purgeWrite 0; simulation and as soon as the solution stabilizes try fixed the
maximum values (maxCo and maxDeltaT). time-step.
writeFormat ascii; writeFormat ascii;
• It is recommended to start the simulation with a low time-step in • Also, try to avoid using adjustable time step together with the
writePrecision 8; order to let the solver scale-up the time-step size. writePrecision 8; option adjustableRunTime.
writeCompression off; • The feature adjustTimeStep is only present in the PIMPLE writeCompression off; • The option adjustableRunTime will adjust the time-step to save
family solvers, but it can be added to any solver by modifying the solution at the precise write intervals, and this might
timeFormat general; timeFormat general;
the source code. introduce numerical oscillations due to the fact that the time-step
timePrecision 6; timePrecision 6; is changing.
• 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 runTimeModifiable yes; • Also, the fact that you are using an adaptive time-step can have
(nCorrectors) in PISO/PIMPLE loop. a negative effect when doing signal analysis.
adjustTimeStep yes; adjustTimeStep yes;
maxCo 2.0; maxCo 2.0;
maxDeltaT 0.001; maxDeltaT 0.001;
868 869
Unsteady and steady simulations Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®? How to run unsteady simulations in OpenFOAM®?
ddtSchemes • The fvSchemes dictionary contains the information related to solvers • The fvSolution dictionary contains the instructions of how to
{ {
time discretization and spatial discretization schemes. p
solve each discretized linear equation system.
default backward;
{ • As for the controlDict and fvSchemes dictionaries, the
} • In this generic case we are using the backward method for time
solver PCG;
gradSchemes
discretization (ddtSchemes). preconditioner DIC; parameters can be changed on-the-fly.
{ tolerance 1e-06;
default Gauss linear;
• This scheme is second order accurate but oscillatory. relTol 0; • In this generic case, to solve the pressure (p) we are using the
grad(p) Gauss linear; } PCG method with the DIC precondtioner, an absolute tolerance
• The parameters can be changed on-the-fly.
} equal to 1e-06 and a relative tolerance relTol equal to 0.
pFinal
divSchemes { • The entry pFinal refers to the final pressure correction (notice
{ that we are using macro syntax), and we are using a relative
$p;
default none;
div(phi,U) Gauss linear;
relTol 0; tolerance relTol equal to 0.
}
}
• To solve U and UFinal (U.* using regex), we are using the
laplacianSchemes “U.*” smoothSolver method with an absolute tolerance equal to 1e-
{ { 08 and a relative tolerance relTol equal to 0.
default Gauss linear orthogonal; solver smoothSolver;
} smoother symGaussSeidel; • The solvers will iterative until reaching any of the tolerance
tolerance 1e-08;
values set by the user or reaching a maximum value of
interpolationSchemes relTol 0;
{ } iterations (optional entry).
default linear; }
} PIMPLE • FYI, solving for the velocity is relative inexpensive, whereas
{ solving for the pressure is expensive.
snGradSchemes nOuterCorrectors 1;
{ nCorrectors 2;
default orthogonal; nNonOrthogonalCorrectors 1;
} }
870 871

Unsteady and steady simulations Unsteady and steady simulations


How to run unsteady simulations in OpenFOAM®? How to run unsteady simulations in OpenFOAM®?
solvers • The fvSolution dictionary also contains the PIMPLE and solvers • If you use the PISO method for pressure-velocity coupling, you
{ {
p
PISO sub-dictionaries. p
will need to define the PISO sub-dictionary.
{ {
• The PIMPLE sub-dictionary contains entries related to the • In this generic case we are doing two PISO corrections and one
solver PCG; solver PCG;
preconditioner DIC; pressure-velocity coupling method (the PIMPLE method). preconditioner DIC; orthogonal correction.
tolerance 1e-06; tolerance 1e-06;
relTol 0; • Setting the keyword nOuterCorrectors to 1 is equivalent to relTol 0; • You need to do at least one PISO loop (nCorrectors).
} running using the PISO method. }
• If you are using large time steps (CFL much higher than 1), it is
pFinal
• Remember, you need to do at least one PISO loop pFinal
recommended to do at least 3 correctors steps (nCorrectors) in
{ (nCorrectors). { PISO/PIMPLE loop.
$p; $p;
• To gain more stability, especially when using large time-steps,
relTol 0; relTol 0;
} you can use more outer correctors (nOuterCorrectors). }

• Adding corrections increase the computational cost


“U.*” U
{
(nOuterCorrectors and nCorrectors). {
solver smoothSolver; solver smoothSolver;
• In this generic case, we are using 1 outer correctors
smoother symGaussSeidel; smoother symGaussSeidel;
tolerance 1e-08; (nOuterCorrectors), 2 inner correctors or PISO correctors tolerance 1e-08;
relTol 0; (nCorrectors), and 1 correction due to non-orthogonality relTol 0;
} (nNonOrthogonalCorrectors). }
} }
PIMPLE • If you are using large time steps (CFL much higher than 1), it is PISO
{ {
nOuterCorrectors 1;
recommended to do at least 3 correctors steps (nCorrectors) in nCorrectors 2;
nCorrectors 2; PISO/PIMPLE loop. nNonOrthogonalCorrectors 1;
nNonOrthogonalCorrectors 1; }
}
872 873
Unsteady and steady simulations Unsteady and steady simulations
How to choose the time-step in unsteady simulations and monitor the solution Monitoring unsteady simulations
• Remember, when running unsteady simulations the time-step must be chosen in such a way • When running unsteady simulations, it is highly advisable to monitor a quantity of interest.
that it resolves the time-dependent features and maintains solver stability. • The quantity of interest can fluctuate in time, this is an indication of unsteadiness.

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

874 875

Unsteady and steady simulations Unsteady and steady simulations


Sampling unsteady simulations I am running an unsteady simulations and the QOI does not change
• Remember to choose wisely where to do the sampling. • When you run unsteady simulations, flow variables can stop changing with time. When this
happens, we say we have arrived to a steady state.
• Remember this is the exception rather than the rule.
• If you use a steady solver, you will arrive to the same solution (maybe not), in much less
iterations.

876 877
Unsteady and steady simulations Unsteady and steady simulations
What about steady simulations? What about steady simulations?
• First at all, steady simulations are a big simplification of reality. • You also need to set the under-relaxation factors.
• Steady simulations is a trick used by CFDers to get fast outcomes with results that might be • The under-relaxation factors control the change of the variable .
even more questionable.
• As mentioned before, most of the flows you will encounter are unsteady.
• In steady simulations we made two assumptions:
• We ignore unsteady fluctuations. That is, we neglect the temporal derivative in the • If we are using under-relaxation.
governing equations.
• Under-relaxation is a feature typical of steady solvers using the SIMPLE method.
• We perform time averaging when dealing with stationary turbulence (RANS modeling) • If you do not set the under-relaxation factors, OpenFOAM® will use the default hard-wired
• The advantage of steady simulations is that they require low computational resources, give fast values (1.0 for all field variables or no under-relaxation).
outputs, and are easier to post-process and analyze. • These are the under-relaxation factors commonly used with SIMPLE (industry standard),
• In OpenFOAM® is possible to run steady simulation.
• To do so, you need to use the appropriate solver and use the right discretization scheme. p 0.3;
• As you are not solving the temporal derivative, you do not need to set the time step. However, U 0.7;
you need to tell OpenFOAM® how many iterations you would like to run. k 0.7;
• You can also set the residual controls (residualControl), in the fvSolution dictionary file. omega 0.7;
You set the residualControl in the SIMPLE sub-dictionary. epsilon 0.7;
• If you do not set the residual controls, OpenFOAM® will run until reaching the maximum
number of iterations (endTime). • According to the physics involved you will need to add more under-relaxation factors.
• Finding the right under-relaxation factors involved experience and a lot of trial and error.
878 879

Unsteady and steady simulations Unsteady and steady simulations


What about steady simulations? How to run steady simulations in OpenFOAM®?
• The under-relaxation factors are bounded between 0 and 1. • 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
relaxationFactors to run). You also set the saving frequency.
• In the fvSchemes dictionary you need to set the temporal discretization

0 1 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.
Velocity
• Also, you will need to set the number of corrections of the velocity-pressure
coupling method used (e.g. SIMPLE), this is done in the fvSolution
dictionary.
Stability
• Additionally, you may set functionObjects in the controlDict dictionary.
The functionObjects are used to do sampling, probing and co-processing
• Selecting the under-relaxation factors it is kind of equivalent to selecting the while the simulation is running.
right time step.
880 881
Unsteady and steady simulations Unsteady and steady simulations
How to run steady simulations in OpenFOAM®? How to run steady simulations in OpenFOAM®?
startFrom latestTime; • The controlDict dictionary contains runtime simulation ddtSchemes • The fvSchemes dictionary contains the information related to
controls, such as, start time, end time, time step, saving { time discretization and spatial discretization schemes.
startTime 0; default steadyState;
frequency and so on. Most of the entries are self-explanatory. } • In this generic case and as we are interested in using a steady
stopAt endTime;
• As we are doing a steady simulation, let us talk about iterations gradSchemes
solver, we are using the steadyState method for time
endTime 10000; instead of time (seconds). { discretization (ddtSchemes).
default Gauss linear;
deltaT 1; • This generic case starts from iteration 0 (startTime), and it will grad(p) Gauss linear; • It is not a good idea to switch between steady and unsteady
run up to 10000 iterations (endTime). } schemes on-the-fly.
writeControl runTime;
• It will write the solution every 100 iterations (writeInterval) of divSchemes • For steady state cases, the bounded form can be applied to the
writeInterval 100; simulation time (runTime). { divSchemes, in this case, div(phi,U) bounded Gauss linear.
default none;
purgeWrite 10; • It will advance the solution one iteration at a time (deltaT). div(phi,U) bounded Gauss linear; • This adds a linearized, implicit source contribution to the
}
transport equation of the form,
writeFormat ascii; • It will keep the last 10 saved solutions (purgeWrite).
laplacianSchemes
writePrecision 8; • It will save the solution in ascii format (writeFormat) with a {
default Gauss linear orthogonal;
precision of 8 digits (writePrecision).
writeCompression off; }
• And as the option runTimeModifiable is on (true), we can
timeFormat general; interpolationSchemes
modify all these entries while we are running the simulation. {
timePrecision 6; default linear; • This term removes a component proportional to the continuity
}
runTimeModifiable yes;
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.
882 883

Unsteady and steady simulations Unsteady and steady simulations


How to run steady simulations in OpenFOAM®? How to run steady simulations in OpenFOAM®?
solvers • The fvSolution dictionary contains the instructions of how to solvers • The fvSolution dictionary also contains the SIMPLE sub-
{ {
p
solve each discretized linear equation system. p
dictionary .
{ • As for the controlDict and fvSchemes dictionaries, the {
• The SIMPLE sub-dictionary contains entries related to the
solver PCG; solver PCG;
preconditioner DIC; parameters can be changed on-the-fly. preconditioner DIC; pressure-velocity coupling method (the SIMPLE method).
tolerance 1e-06; tolerance 1e-06;
relTol 0; • In this generic case, to solve the pressure (p) we are using the relTol 0; • Increasing the number of nNonOrthogonalCorrectors
} PCG method with the DIC preconditioner, an absolute tolerance } corrections will add more stability but at a higher computational
equal to 1e-06 and a relative tolerance relTol equal to 0. cost.
U U
{ • To solve U we are using the smoothSolver method with an { • Remember, nNonOrthogonalCorrectors is used to improve
solver smoothSolver; absolute tolerance equal to 1e-08 and a relative tolerance solver smoothSolver; the gradient computation due to mesh quality.
smoother symGaussSeidel; smoother symGaussSeidel;
relTol equal to 0.
tolerance 1e-08; tolerance 1e-08; • In this generic case, we are doing 2 corrections due to non-
relTol 0; • The solvers will iterative until reaching any of the tolerance relTol 0; orthogonality (nNonOrthogonalCorrectors).
} }
} values set by the user or reaching a maximum value of } • The SIMPLE sub-dictionary also contains convergence controls
iterations (optional entry).
based on residuals of fields. The controls are specified in the
SIMPLE SIMPLE
{ {
residualControls sub-dictionary.
nNonOrthogonalCorrectors 2; nNonOrthogonalCorrectors 2;
• The user needs to specify a tolerance for one or more solved
residualControl residualControl fields and when the residual for every field falls below the
{ { corresponding residual, the simulation terminates.
p 1e-4; p 1e-4;
U 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.
884 885
Unsteady and steady simulations Unsteady and steady simulations
How to run steady simulations in OpenFOAM®? Steady simulations vs. Unsteady simulations
• The fvSolution dictionary also contains the
relaxationFactors relaxationFactors sub-dictionary.
• Steady simulations require less computational power than unsteady simulations.
{
fields • The relaxationFactors sub-dictionary which controls under- • They are also much faster than unsteady simulations.
{ relaxation, is a technique used for improving stability when using
p 0.3; • But sometimes they do not converge to the right solution.
}
steady solvers.
equations • They are easier to post-process and analyze (you just need to take a look at the last saved
• Under-relaxation works by limiting the amount which a variable
{
changes from one iteration to the next, either by modifying the solution).
U 0.7;
} solution matrix and source (equations keyword) prior to solving • You can use the solution of an unconverged steady simulation as initial conditions for an
}
for a field or by modifying the field directly (fields keyword). unsteady simulation.
• An optimum choice of under-relaxation factors is one that is
• Remember, steady simulations are not time accurate, therefore we can not use them to
small enough to ensure stable computation but large enough to
move the iterative process forward quickly. compute temporal statistics or compute the shedding frequency
• These are the under-relaxation factors commonly used
(SIMPLE),
fields
{
p 0.3;
}
equations
{
U 0.7;
k 0.7;
omega 0.7;
} 886 887

Roadmap Understanding residuals


• Let us use the vortex shedding case as a model case to demonstrate how to interpret
the residuals.
• We will work with a Reynolds number equal to 20 and 200.
1. Finite Volume Method: A Crash Introduction • If you are interested in reproducing the following results, the case is located in the
directory: $PTOFC/101FVM/cyl_ste_uns/
2. On the CFL number • Before talking about residuals, let us clarify something.
• When we talk about iterations in unsteady simulations, we are talking about the time-
3. Numerical playground step or outer-iterations.
4. Linear solvers in OpenFOAM®
5. Pressure-Velocity coupling in OpenFOAM®
6. Unsteady and steady simulations
1. To arrive to this physical time
7. Understanding residuals
8. Boundary and initial conditions

888 2. We iterate this many times 889


Understanding residuals Understanding residuals
• And we iterate inside each time-step (or outer-iteration), until reaching the • This is a typical residual plot for an unsteady simulation.
linear solver tolerance or maximum number of iterations.

890 891

Understanding residuals Understanding residuals


• This is a typical residual plot for an unsteady simulation. • This is a typical residual plot for an unsteady simulation.
• Ideally, the solution should converge at every time-step. • Remember, residuals are not a direct indication that you are converging to the right
• If the solution is not converging, try to reduce the time-step size. solution.

• The first time-steps the solution might not converge, this is acceptable. • It is better to monitor a quantity of interest.

• Also, you might need to use a smaller time-step during the first iterations to maintain • And by the way, you should get physically realistic values.
solver stability. • To monitor the stability, you can check the minimum and maximum values of the field
• You can also increase the number of maximum inner iterations. variables.

• If the initial residuals fall bellow the convergence criterion, you might say that you • If you have bounded quantities, check that you do not have over-shoots or under-
have arrived to a steady solution. shoots.

892 893
Understanding residuals Understanding residuals
• This is the residual plot of an unsteady • And this is the plot of the number of • Let us study the residual plot of an • Let us study the residual plot of an
solver that reached a steady-state inner-iterations against the number of unsteady solution (or flow), using a steady solution (or flow), using a
behavior. outer-iterations (time-steps). steady solver. steady solver.
• Notice that after a couple of thousands • Notice that after 2000 time-steps, the • Notice that we are making the • In this case, the initial residuals are
iterations the initial residuals and final solution arrives to the convergence distinction between steady solver and falling below the convergence
residuals are the same. criterion (in the linear solvers) in just 1 unsteady solution. criterion (monolithic convergence),
• We are plotting the residuals against iteration (in this case we are setting • Here the initial residuals are not falling hence we have reached a steady-
iterations (or time-steps or outer- minIter equal to 1). (stalled convergence). This is an state.
iterations). indication of an unsteady solution or • In comparison to unsteady solvers,
the wrong numerics. steady solvers require less iterations
to arrive to a converge solution, if they
arrive.

894 895

Understanding residuals Understanding residuals


• For a steady flow (low Reynolds number), let us compare an integral quantity • For an unsteady flow (high Reynolds number), let us compare an integral quantity
computed using a steady solver and the same quantity computed using an unsteady computed using a steady solver and the same quantity computed using an unsteady
solver solver
• As we can see, both quantities are roughly speaking the same. • As we can see, the outcomes are very different.
• In comparison to unsteady solvers, steady solvers require less iterations to arrive to • When the flow is unsteady, steady solvers do not capture well the mean solution.
a converge solution (if they arrive). • On he other hand, unsteady solver captures well the unsteadiness and also is
• Unsteady solvers need to run for longer times in order to get an average solution. possible to average the solution.

896 897
Understanding residuals Understanding residuals
• Finally, let us compare the residuals of • This is the plot of the number of inner- • However, the fact that the first order method converge faster and is less
a first order and a second order iterations against the number of outer- computationally expensive, it does not mean it is better.
numerical scheme. iterations (time-steps).
• As you can see, first order methods highly under-predict the quantity of
• This is the residual plot of an unsteady • As you can see, the first order method
interest.
simulation. is less computationally expensive.
• In this case, the first order method takes more time to onset the instability.
• Both methods are converging to the • However, the fact that the first order
desired tolerance. method converge faster and is less
• Also, the fact that the residuals drops computationally expensive, it does not
faster using a first order methods, mean it is better.
does not mean that they are better.

898 899

Understanding residuals Understanding residuals


• This is the output of all residuals for a • This is the output of all residuals for a • This is the output of the inner-iterations • This is the output of the inner-residual
Reynolds number equal to 200 Reynolds number equal to 20 (steady against the outer-iterations for a against the outer-residuals for a
(unsteady case). case). Reynolds number equal to 200 Reynolds number equal to 20 (steady
(unsteady case). case).
• The jumps are due to the changes in
tolerance introduced while running
the simulation.

900 901
Understanding residuals Roadmap
• This is the output of the aerodynamic • This is the output of the aerodynamic
coefficients for a Reynolds number coefficients for a Reynolds number
equal to 200 (unsteady case). equal to 20 (steady case).
1. Finite Volume Method: A Crash Introduction
2. On the CFL number
3. Numerical playground
4. Linear solvers in OpenFOAM®
5. Pressure-Velocity coupling in OpenFOAM®
6. Unsteady and steady simulations
7. Understanding residuals
8. Boundary and initial conditions

902 903

Boundary conditions and initial conditions Boundary conditions and initial conditions
On the initial boundary value problem (IBVP) A few words about boundary conditions

• First at all, when we use a CFD solver (OpenFOAM® included) to find the • Boundary conditions can be divided into three fundamental mathematical types:
approximate solution of the governing equations, we are solving an Initial • Dirichlet boundary conditions.
Boundary Value Problem (IBVP).
• Neumann boundary conditions.
• In an IBVP, we need to impose appropriate boundary conditions and initial • Robin Boundary conditions.
conditions.
• When we use a Dirichlet boundary condition, we prescribe the value of a
• No need to say that the boundary conditions and initial conditions need to be variable at the boundary.
physically realistic. • When we use a Neumann boundary condition, we prescribe the gradient
• Boundary conditions are a required component of the numerical method, normal to the boundary.
they tell the solver what is going on at the boundaries of the domain. • Robin boundary conditions, are a mixed of Dirichlet boundary conditions and
Neumann boundary conditions.
• You can think of boundary conditions as source terms.
• You can use any of these three boundary conditions in OpenFOAM®.
• Initial conditions are also a required component of the numerical method,
• During this discussion the semantics is not important, that depends of how you
they define the initial state of the problem.
want to call the boundary conditions or how they are named in the solver, i.e., in,
inlet, inflow, velocity inlet, incoming flow and so on.

904 905
Boundary conditions and initial conditions Boundary conditions and initial conditions
A few words about boundary conditions A few words about boundary conditions

• Defining boundary conditions involves: • To define boundary conditions you need to know the location of the
• Determining the boundary condition type. boundaries (where they are in your mesh), and supply the information at the
boundaries.
• Finding the location of the boundary condition in the domain.
• You must know what information is required at the boundaries, you must
• Giving the required physical information.
know the physics involved.

• 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.

906 907

Boundary conditions and initial conditions Boundary conditions and initial conditions
A few words about initial conditions A few words about initial conditions

• Initial conditions can be divided into two groups: • Defining initial conditions involves:
• Uniform initial conditions. • Determining the initial condition type.
• Non-uniform initial conditions. • Finding the location of the initial condition in the domain.
• Giving the required physical information.
• For non-uniform initial conditions, the value used can be obtained from:
• Another simulation, including a solution with different grid resolution. • The choice of the initial conditions depend on:
• A potential solver. • Geometrical considerations.
• Experimental results. • Physics involved.
• A mathematical function • Information available.
• Reduced order models. • Numerical considerations.

• And most important, you need to understand the physics involved.

908 909
Boundary conditions and initial conditions Boundary conditions and initial conditions
A few words about initial conditions A few considerations and guidelines

• For initial conditions, you need to supply the initial information or initial state • Boundary conditions and initial conditions need to be physically realistic.
of your problem. • Poorly defined boundary conditions can have a significant impact on your solution.

• This information can be a uniform value or a non-uniform value. • Initial conditions are as important as the boundary conditions.
• A good initial condition can improve the stability and convergence rate.
• You can apply the initial conditions to the whole domain or zones of the
• On the other hand, unphysical initial conditions can slow down the convergence
domain.
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.
• 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,
specially close to the inlets.
• You need to understand the physics in order to set the right boundary conditions.

910 911

Boundary conditions and initial conditions Boundary conditions and initial conditions
A few considerations and guidelines A few considerations and guidelines
• The required values of the boundary conditions and initial conditions depend on the • Do not force the flow at the outlet, use a zero normal gradient for all flow variables
equations you are solving and physical models used, e.g., except pressure. The solver extrapolates the required information from the interior.
• For incompressible and laminar flows you will need to set only the velocity and • Be careful with backward flow at the outlets (flow coming back to the domain) and
pressure. backward flow at inlets (reflection waves), they required special treatment.
• If you are solving a turbulent compressible flow you will need to set velocity, • If possible, select inflow and outflow boundary conditions such that the flow either goes
pressure, temperature and the turbulent variables. in or out normal to the boundaries.
• For multiphase flows you will need to set the primitives variables for each phase. • Use zero gradient boundary conditions only with incompressible flows and when you
You will also need to initialize the phases. are sure that the flow is fully developed.
• If you are doing turbulent combustion or chemical reactions, you will need to • Outlets that discharge to the atmosphere can use a static pressure boundary
define the species, reactions and primitive and turbulent variables. condition. This is interpreted as the static pressure of the environment into which the
• Minimize grid skewness, non-orthogonality, growth rate, and aspect ratio near the flow exhausts.
boundaries. You do not want to introduce diffusion errors early in the simulation, • Inlets that take flow into the domain from the atmosphere can use a total pressure
specially close to the inlets. boundary condition (e.g. open window).
• Try to avoid large gradients in the direction normal to the boundaries and near inlets • Mass flow inlets produce a uniform velocity profile at the inlet.
and outlets. That is to say, put your boundaries far away from where things are • Pressure specified boundary conditions allow a natural velocity profile to develop.
happening.

912 913
Boundary conditions and initial conditions Boundary conditions and initial conditions
• Inlets and outlets boundary conditions: • Zero gradient and backflow boundary conditions:
• Inlets are for regions where inflow is expected; however, inlets might support • Zero gradient boundary conditions extrapolates the values from the domain.
outflow when a velocity profile is specified. They require no information.
• Pressure boundary conditions do not allow outflow at the inlets. • Zero gradient boundary conditions can be used at inlets, outlets, and walls.
• Velocity specified inlets are intended for incompressible flows. • Backflow boundary conditions provide a generic outflow/inflow condition, with
• Pressure and mass flow inlets are suitable for compressible and incompressible specified inflow/outflow for the case of backflow.
flows. • In the case of a backflow outlet, when the flux is positive (out of domain) it
• Same concepts apply to outlets, which are regions where outflow is expected. 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.

914 915

Boundary conditions and initial conditions Boundary conditions and initial conditions
• On the outlet pressure boundary condition • On the outlet pressure boundary condition
• Some combinations of boundary conditions are very stable and some are less • If you only rely on a QOI and the residuals, you will not see any major difference
reliable. between the two cases with different outlet pressure boundary condition.
• And some configurations are unreliable. • This is very misleading.
• Inlet velocity at the inlet and pressure zero gradient at the outlet. This • However, when you visualize the solution you will realize that something is
combination should be avoided because the static pressure level is not wrong. This is a case where pretty pictures can be used to troubleshoot the
fixed. solution.
• Qualitatively speaking, the results are very different. • Quantitative speaking, the results are very similar.
• This simulation will eventually crash. • However, 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
Residual plot for pressure Quantity of interest – Force coefficient on the body

916 917
Boundary conditions and initial conditions Boundary conditions and initial conditions
• Symmetry boundary conditions: • Location of the outlet boundary condition:
• Symmetry boundary conditions are a big simplification of the problem. However, • Place outlet boundary conditions as far as possible from recirculation zones or
they help to reduce mesh cell count. backflow conditions, by doing this you increase the stability.
• Have in mind that symmetry boundary conditions only apply to planar faces. • Remember, backflow conditions requires special treatment.
Far enough so the flow can be
• To use symmetry boundary conditions, both the geometry and the flow field must Possible backflow Might be OK
considered fully developed

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.

918 919

Boundary conditions and initial conditions Boundary conditions and initial conditions
• Domain dimensions (when the dimensions are not known): • OpenFOAM® distinguish between base type boundary conditions and primitive type
boundary conditions.
• If you do not have any constrain in the domain dimensions, you can use as a general guideline the
dimensions illustrated in the figure, where L is a reference length (in this case, L is the wing chord).
• Always verify that there are no significant gradients normal to any of the boundaries patches. If there Base type boundary conditions Primitive type boundary conditions
are, you should consider increasing the domain dimensions.
• Base type boundary conditions are based on
geometry information (surface patches) or on inter- • Primitive type boundary condition assigns the value
processor communication link (halo boundaries). to the field variables in the given surface patch.
• Base type boundary conditions are defined in the • Primitive type boundary conditions are defined in
file boundary located in the directory the field variables dictionaries located in the
constant/polyMesh directory 0 (e.g. U, p).
• The file boundary is automatically created when • When we talk about primitive type boundary
you generate or convert the mesh. conditions we are referring to Dirichlet, Neumann or
• When you convert a mesh to OpenFOAM® format, Robin boundary conditions.
you might need to manually modify the file • You need to manually create the field variables
boundary. This is because the conversion utilities dictionaries (e.g. 0/U, 0/p, 0/T, 0/k, 0/omega).
do not recognize the boundary type of the original • Remember, if you forget to define a primitive
mesh. boundary condition, OpenFOAM® will complain and
• Remember, if a base type boundary condition is will tell you where and what is the error.
missing, OpenFOAM® will complain and will tell you • Also, if you misspelled something OpenFOAM® will
where and what is the error. complain and will tell you where and what is the
• Also, if you misspelled something OpenFOAM® will error.
complain and will tell you where and what is the
error
920 921
Boundary conditions and initial conditions Boundary conditions and initial conditions
• The following base type and primitive type boundary conditions are • The base type patch can be any of the boundary conditions available in
constrained or paired. OpenFOAM®.
• That is, the type needs to be same in the boundary dictionary and field • Mathematically speaking; they can be Dirichlet, Neumann or Robin
variables dictionaries (e.g. 0/U, 0/p, 0/T, 0/k, 0/omega). boundary conditions.

Base type Primitive type Base type Primitive type

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


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

fixedValue
symmetry symmetry zeroGradient
symmetryPlane symmetryPlane inletOutlet
empty empty slip
patch
wedge wedge totalPressure
supersonicFreeStream
cyclic cyclic
and so on …
processor processor Refer to the doxygen documentation for a list of all numerical
boundary conditions available.

922 923

Boundary conditions and initial conditions Boundary conditions and initial conditions
• The wall base type boundary condition is defined as follows: • To deal with backflow at outlets, you can use the following boundary condition:

Base type Primitive type Base type Primitive type

constant/polyMesh/boundary 0/U 0/p constant/polyMesh/boundary 0/U 0/p

type fixedValue; type inletOutlet;


type fixedValue;
wall zeroGradient patch inletValue uniform (0 0 0);
value uniform (0 0 0); value uniform (0 0 0);
value uniform 0;

• This boundary condition is not contained in the patch base type boundary conditions
• The inletValue keyword is used for the reverse flow.
group, because specialize modeling options can be used on this boundary condition.
• In this case, if flow is coming back into the domain it will use the value set using the
• An example is turbulence modeling, where turbulence can be generated or
keyword inletValue. Otherwise it will use a zeroGradient boundary condition.
dissipated at the walls.

924 925
Boundary conditions and initial conditions Boundary conditions and initial conditions
• Typical boundary conditions are as follows (external aerodynamics), • Typical wall functions boundary conditions are as follows,

Boundary type description Pressure Velocity Turbulence fields Field variable Wall functions – High RE Resolved BL – Low RE

Inlet zeroGradient fixedValue fixedValue nut nut(–)WallFunction* fixedValue 0 or a small number

Outlet fixedValue inletOutlet inletOutlet


k, q, R kqRWallFunction fixedValue 0 or a small number

Wall zeroGradient fixedValue Wall functions* zeroGradient or fixedValue 0 or


epsilon epsilonWallFunction
a small number
Symmetry symmetry symmetry symmetry
omegaWallFunction or
omega omegaWallFunction
fixedValue with a small number
Periodic cyclic cyclic cyclic
zeta – fixedValue 0 or a small number
Empty face (2D) empty empty empty

nuTilda – fixedValue 0 or a small number


Slip wall slip slip slip

* nutkAtmRoughWallFunction, nutkRoughWallFunction, nutkWallFunction,


* Wall functions can be: kqWallFunction, omegaWallFunction, nutkWallFunction, and so on
nutLowReWallFunction, nutURoughWallFunction, nutUSpaldingWallFunction,
(next slide).
nutUTabulatedWallFunction, nutUWallFunction, nutWallFunction.
926 927

Boundary conditions and initial conditions Boundary conditions and initial conditions
• Finally, remember that the name of the base type boundary condition and the name • There are numerous primitive type boundary conditions implemented in
of the primitive type boundary condition needs to be the same, if not, OpenFOAM® OpenFOAM®.
will complain.
• You can find the source code of the numerical boundary conditions in the
• Pay attention to this, specially if you are converting the mesh from another format.
following directory:
• 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,
• $WM_PROJECT_DIR/src/finiteVolume/fields

Base type Primitive type


• The wall boundary conditions for the turbulence models (wall functions), are
located in the following directory:
constant/polyMesh/boundary 0/U 0/p

inlet inlet inlet


• $WM_PROJECT_DIR/src/TurbulenceModels/turbulenceModels
top top top /derivedFvPatchFields/wallFunctions
cylinder cylinder cylinder

sym sym sym


928 929
Boundary conditions and initial conditions Boundary conditions and initial conditions
• To get more information about all the boundary conditions available in OpenFOAM® The constant/polyMesh/boundary dictionary
you can read the Doxygen documentation, just look for the Using OpenFOAM
section at the bottom of the page. • For a generic case, the file boundary is divided as follows
• If you did not compile the Doxygen documentation, you can access the
information online, http://cpp.openfoam.org/v5/ 3 Number of surface patches
(
movingWall
There must be 3 patches definition.
{
type patch;
inGroups 1(patch); movingWall
nFaces 20;
API documentation startFace 760;
} frontAndBack

fixedWalls
{
type wall;
inGroups 1(wall);
nFaces 60;

fixedWalls
startFace 780;

fixedWalls
}

frontAndBack
{
Boundary conditions and type empty;
inGroups 1(empty);
functionObjects documentation nFaces 800;
startFace 840;
} frontAndBack
)

fixedWalls

930 931

Boundary conditions and initial conditions Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary The constant/polyMesh/boundary dictionary

• For a generic case, the file boundary is divided as follows • For a generic case, the file boundary is divided as follows

3 3
( Name and type of the surface patches ( inGroups keyword
movingWall movingWall
{ {
type patch; • The name and type of the patch is given by type patch; • This is optional.
inGroups 1(patch); inGroups 1(patch);
the user.
nFaces 20; nFaces 20; • You can erase this information safely.
startFace 760; startFace 760;
} • You can change the name if you do not like it. } • It is used to group patches during visualization
Do not use strange symbols or white spaces.
fixedWalls fixedWalls in ParaView/paraFoam. If you open this mesh
{ • You can also change the base type. For { in paraFoam you will see that there are two
type wall; type wall;
inGroups 1(wall); instance, you can change the type of the inGroups 1(wall); groups, namely: wall and empty.
nFaces 60; patch movingWall from patch to wall. nFaces 60;
startFace 780; startFace 780; • As usual, you can change the name.
} • When converting the mesh from a third party }
• If you want to put a surface patch in two
format, OpenFOAM® will try to recover the
frontAndBack frontAndBack groups, you can proceed as follows:
{ information from the original format. But it {
type empty; might happen that it does not recognize the type empty; 2(wall wall1)
inGroups 1(empty); inGroups 1(empty);
base type and name of the original format. If
nFaces 800; nFaces 800; In this case the surface patch belongs to the
startFace 840; that is your case, you will need to modify the startFace 840;
} } group wall (which can have another patch)
file manually.
) ) and wall1

932 933
Boundary conditions and initial conditions Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary The constant/polyMesh/boundary dictionary

• For a generic case, the file boundary is divided as follows • For a generic case, the file boundary is divided as follows

3 3
Remember
( (
movingWall movingWall
{ { Boundary patches that are not recognize or
type patch; type patch; assigned to a patch are grouped automatically in
inGroups 1(patch); inGroups 1(patch);
nFaces 20; nFaces and startFace keywords nFaces 20;
a default group named defaultFaces of type
startFace 760; startFace 760; empty.
} }
• Unless you know what you are For instance, if a boundary patch does not have a
fixedWalls
doing, you do not need to change fixedWalls type and a name, they will be grouped as follows:
{ {
type wall; this information. type wall;
inGroups 1(wall); inGroups 1(wall);
nFaces 60; • Basically, this is telling you the nFaces 60; defaultFaces
{
startFace 780; starting face and ending face of the startFace 780;
type empty;
} }
patch. inGroups 1(empty);
frontAndBack frontAndBack nFaces 800;
{ • This is created automatically when { startFace 840;
}
type empty; generating the mesh or converting type empty;
inGroups 1(empty); inGroups 1(empty);
nFaces 800;
the mesh. nFaces 800;
startFace 840; startFace 840;
} }
And as usual, you can manually change the name
) ) and type.

934 935

Boundary conditions and initial conditions Boundary conditions and initial conditions
The 0/U dictionary The 0/p dictionary

• For a generic case, the primitive type BC are assigned as follows (U), • For a generic case, the primitive type BC are assigned as follows (p),
movingWall
dimensions [0 1 -1 0 0 0 0]; type fixedValue; dimensions [0 2 -2 0 0 0 0]; movingWall
value uniform (1 0 0); type zeroGradient;
internalField uniform (0 0 0); internalField uniform 0;

boundaryField frontAndBack boundaryField frontAndBack


{ type empty; { type empty;
value uniform (0 0 0);

type zeroGradient;
movingWall movingWall
{ {
type fixedValue;

type fixedValue; type zeroGradient;


value uniform (0 0 0);

value uniform (1 0 0); }

type zeroGradient;

fixedWalls
}
fixedWalls

fixedWalls
type fixedValue;

fixedWalls {
{ type zeroGradient;

fixedWalls
fixedWalls

type fixedValue; }
value uniform (0 0 0);
} frontAndBack
{
frontAndBack type empty;
{ frontAndBack } frontAndBack
type empty; }
type empty; type empty;
}
}
fixedWalls fixedWalls
type fixedValue; type zeroGradient;
value uniform (0 0 0);

936 937
Roadmap

1. Programming in OpenFOAM®. Building blocks.


2. codeStream – Highlights
3. Implementing boundary conditions using
Module 7 codeStream
4. Solution initialization using codeStream
Basic programming in OpenFOAM® – 5. Implementing boundary conditions using high level
Building blocks – Implementing boundary programming
conditions and initial conditions using 6. Modifying applications – Highlights
codeStream – Modifying applications 7. Implementing an application from scratch
8. Adding the scalar transport equation to icoFoam

938 939

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


• During this session we will study the building blocks to write basic
programs in OpenFOAM®:
• First, we will start by taking a look at the algebra of tensors in
• In the directory $WM_PROJECT_DIR/applications/test, you will OpenFOAM®.
find the source code of several test cases that show the usage of most • Then, we will take a look at how to generate tensor fields from tensors.
of the OpenFOAM® classes. • Next, we will learn how to access mesh information.
• We highly encourage you to take a look at these test cases and try to • Finally we will see how to discretize a model equation and solve the
understand how to use the classes. linear system of equations using OpenFOAM® classes and templates.
• We will use these basic test cases to understand the following base • And of course, we are going to program a little bit in C++. But do not be
classes: tensors, fields, mesh, and basic discretization. afraid, after all this is not a C++ course.
• For your convenience, we already copied the directory
$WM_PROJECT_DIR/applications/test into the directory • Remember, all OpenFOAM® components are implemented in library form for
$PTOFC/programming_playground/test easy re-use.
• OpenFOAM® encourage code re-use. So basically we are going to take
something that already exist and we are going to modify it to fix our needs.
• We like to call this method CPAC (copy-paste-adapt-compile).
940 941
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Basic tensor classes in OpenFOAM® Basic tensor classes in OpenFOAM®
• OpenFOAM® represents scalars, vectors and matrices as tensor fields. A zero rank • In OpenFOAM®, the second rank tensor (or matrix)
tensor is a scalar, a first rank tensor is a vector and a second rank tensor is a matrix.
• OpenFOAM® contains a C++ class library named primitive
($FOAM_SRC/OpenFOAM/primitives/). In this library, you will find the classes for
the tensor mathematics.
• In the following table, we show the basic tensor classes available in OpenFOAM®,
with their respective access functions.

Tensor Rank Common name Basic class Access function can be declared in the following way

0 Scalar scalar tensor T(1, 2, 3, 4, 5, 6, 7, 8, 9);

1 Vector vector x(), y(), z()


• We can access the component or using the xz ( ) access function,
2 Tensor tensor xx(), xy(), xz() …

942 943

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


Basic tensor classes in OpenFOAM® Algebraic tensor operations in OpenFOAM®
• For instance, the following statement, • Tensor operations operate on the entire tensor entity.
• OpenFOAM® syntax closely mimics the syntax used in written mathematics, using descriptive
functions (e.g. mag) or symbolic operators (e.g. +).
Info << “Txz = “ << T.xz ( ) << endl;
• OpenFOAM® also follow the standard rules of linear algebra when working with tensors.
• Some of the algebraic tensor operations are listed in the following table (where a and b are
vectors, s is a scalar, and T is a tensor).
Mathematical OpenFOAM®
Operation Remarks
description description
Addition a+b a + b
• Will generate the following screen output,
Scalar multiplication sa s * a

Outer product rank a, b >=1 ab a * b


$> Txz = 3
Inner product rank a, b >=1 a.b a & b

Double inner product rank a, b >=2 a:b a && b


• Notice that to output information to the screen in OpenFOAM®, we use the function
Info instead of the function cout (used in standard C++). Magnitude |a| mag(a)

• The function cout will work fine, but it will give you problems when running in parallel. Determinant det T det(T)

944 You can find a complete list of all operators in the programmer’s guide 945
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Dimensional units in OpenFOAM® Dimensional units in OpenFOAM®

• As we already know, OpenFOAM® is fully dimensional. • Units are defined using the dimensionSet class tensor, with its units defined using
the dimensioned<Type> template class, the <Type> being scalar, vector, tensor,
• Dimensional checking is implemented as a safeguard against implementing etc. The dimensioned<Type> stores the variable name, the dimensions and the
a meaningless operation. tensor values.
• OpenFOAM® encourages the user to attach dimensional units to any tensor • For example, a tensor with dimensions is declare in the following way:
and it will perform dimension checking of any tensor operation.
• You can find the dimensional classes in the directory 1 dimensionedTensor sigma
2 (
$FOAM_SRC/OpenFOAM/dimensionedTypes/ 3 “sigma”,
4 dimensionSet(1, -1, -2, 0, 0, 0, 0),
• The dimensions can be hardwired directly in the source code or can be
5 tensor(10e6,0,0,0,10e6,0,0,0,10e6)
defined in the input dictionaries. 6 );
• From this point on, we will be attaching dimensions to all the tensors.

• In line 1 we create the object sigma.


• In line 4, we use the class dimensonSet to attach units to the object sigma.
• In line 5, we set the input values of the tensor sigma.
946 947

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


Units correspondence in dimensionSet Dimensional units examples

• The units of the class dimensionSet are defined as follows • To attach dimensions to any tensor, you need to access dimensional units class.
• To do so, just add the header file dimensionedTensor.H to your program.
dimensionSet (kg, m, s, K, mol, A, cd)
#include “dimensionedTensor.H”
...
...
• Therefore, the tensor sigma, ...
dimensionedTensor sigma
(
1 dimensionedTensor sigma "sigma",
dimensionSet(1, -1, -2, 0, 0, 0, 0),
2 (
tensor(1e6,0,0,0,1e6,0,0,0,1e6)
3 “sigma”, );
4 dimensionSet(1, -1, -2, 0, 0, 0, 0), Info<< "Sigma: " << sigma << endl;
5 tensor(10e6,0,0,0,10e6,0,0,0,10e6) ...
6 ); ...
...

• Has pressure units or • The output of the previous program should looks like this:
sigma sigma [1 -1 -2 0 0 0 0] (1e+06 0 0 0 1e+06 0 0 0 1e+06)
948 949
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Dimensional units examples OpenFOAM® lists and fields

• As for base tensors, you can access the information of dimensioned tensors. • OpenFOAM® frequently needs to store sets of data and perform mathematical
operations.
• For example, to access the name, dimensions, and values of a dimensioned tensor,
you can proceed as follows: • OpenFOAM® provides an array template class List<Type>, making it possible to
create a list of any object of class Type that inherits the functions of the Type. For
example a List of vector is List<vector>.
Info << “Sigma name: “ << sigma.name ( ) << endl;
Info << “Sigma dimensions: “ << sigma.dimensions ( ) << endl; • Lists of the tensor classes are defined in OpenFOAM® by the template class
Info << “Sigma value: “ << sigma.value ( ) << endl; Field<Type>.
• For better code legibility, all instances of Field<Type>, e.g. Field<vector>, are
renamed using typedef declarations as scalarField, vectorField, tensorField,
• To extract a value of a dimensioned tensor, you can proceed as follows:
symmTensorField, tensorThirdField and symmTensorThirdField.
• You can find the field classes in the directory
Info<< "Sigma yy (22) value: " << sigma.value().yy() << endl;
$FOAM_SRC/OpenFOAM/fields/Fields.
• Algebraic operations can be performed between fields, subject to obvious restrictions
• Note that the value() member function first converts the expression to a tensor, which such as the fields having the same number of elements.
has a yy() member function. • OpenFOAM® also supports operations between a field and a zero rank tensor, e.g.
• The dimensionedTensor class does not have a yy() member function, so it is not all values of a Field U can be multiplied by the scalar 2 by simple coding the
possible to directly get its value by using sigma.yy(). following line, U = 2.0 * U.
950 951

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


Construction of a tensor field in OpenFOAM® Example of use of tensor and field classes
• To create fields, you need to access the tensor class. • In the directory $PTOFC/programming_playground/my_tensor you will find a
• To do so, just add the header file tensorField.H to your program. This class tensor class example.
inherit all the tensor algebra. • The original example is located in the directory
$PTOFC/programming_playground/test/tensor. Feel free to compare the
#include "tensorField.H" files to spot the differences.
... • Before compiling the file, let us recall how applications are structure,
...
...
tensorField tf1(2, tensor::one); working_directory/
Info<< "tf1: " << tf1 << endl; ├── applicationName.C
tf1[0] = tensor(1, 2, 3, 4, 5, 6, 7, 8, 9); ├── header-files.H
Info<< "tf1: " << tf1 << endl; └── Make
Info<< "2.0*tf1: " << 2.0*tf1 << endl; ├── files
...
... └── options
...

• applicationName.C: is the actual source code of the application.


• In this example, we created a list of two tensor fields (tf1), and both tensors are
initialized to one. • header_files.H: header files required to compile the application.
• We can access components on the list using the access operator [ ].
952 953
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Example of use of tensor and field classes Example of use of tensor and field classes
• Before compiling the file, let us recall how applications are structure. • Let us now compile the tensor class example. Type in the terminal:
working_directory/
├── applicationName.C 1. $> cd $PTOFC/programming_playground/my_tensor
├── header-files.H
└── Make 2. $> wmake
├── files 3. $> my_Test-tensor
└── options
• The Make directory contains compilation instructions.
• In step 2, we used wmake (distributed with OpenFOAM®) to compile the
• files: names all the source files (.C), it specifies the name of the new application and
source code.
the location of the output file.
• options: specifies directories to search for include files and libraries to link the solver • The name of the executable will be my_Test-tensor and it will be located in
against. the directory $FOAM_USER_APPBIN (as specified in the file Make/files)
• At the end of the file files, you will find the following line of code, • At this point, take a look at the output and study the file Test-tensor.C.
EXE = $(FOAM_USER_APPBIN)/my_Test-tensor
Try to understand what we have done.
• This is telling the compiler to name your application my_Test-tensor and to copy the executable
in the directory $FOAM_USER_APPBIN. • After all, is not that difficult. Right?
• To avoid conflicts between applications, always remember to give a proper name and a location
to your programs and libraries.
954 955

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


Discretization of a tensor field in OpenFOAM®

• The discretization is done using the FVM (Finite Volume Method).

• At this point, we are a little bit familiar with tensor, fields, and lists in • The cells are contiguous, i.e., they do not overlap and completely fill the domain.
OpenFOAM®. • Dependent variables and other properties are stored at the cell centroid.
• They are the base to building applications in OpenFOAM®. • No limitations on the number of faces bounding each cell.
• Let us now take a look at the whole solution process: • No restriction on the alignment of each face.
• Creation of the tensors. • The mesh class polyMesh is used to construct the polyhedral mesh using the
• Mesh assembly. minimum information required.

• Fields creation. • You can find the polyMesh classes in the directory $FOAM_SRC/OpenFOAM/meshes

• Equation discretization. • The fvMesh class extends the polyMesh class to include additional data needed for
the FVM discretization.
• All by using OpenFOAM® classes and template classes
• You can find the fvMesh classes in the directory
$FOAM_SRC/src/finiteVolume/fvMesh

956 957
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Discretization of a tensor field in OpenFOAM® Data stored in the fvMesh class
• The template class geometricField relates a tensor
field to a fvMesh. Access
Class Description Symbol
• Using typedef declarations geometricField is renamed
function
to volField (cell center), surfaceField (cell faces), and volScalarField Cell volumes V()
pointField (cell vertices).
• You can find the geometricField classes in the directory surfaceVectorField Face area vector Sf()
$FOAM_SRC/OpenFOAM/fields/GeometricFields.
surfaceScalarField Face area magnitude magSf()
• The template class geometricField stores internal
fields, boundary fields, mesh information, dimensions, volVectorField Cell centres C()
old values and previous iteration values.
surfaceVectorField Face centres Cf()
• A geometricField inherits all the tensor algebra of its
corresponding field, has dimension checking, and can surfaceScalarField Face fluxes Phi()
be subjected to specific discretization procedures.
• Let us now access the mesh information of a simple
case.

958 959

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


Accessing fields defined in a mesh Accessing fields using for loops
• To access fields defined at cell centers of the mesh you need to use the class • To access fields using for loops, we can use OpenFOAM® macro forAll, as follows,
volField.
Outputs name of patch
• The class volField can be accessed by adding the header volFields.H to your forAll(mesh.boundaryMesh(), patchI)
program. Info << "Patch " << patchI << ": " << mesh.boundary()[patchI].name() << " with "
<< mesh.boundary()[patchI].Cf().size() << " faces. Starts at total face "
<< mesh.boundary()[patchI].start() << endl;
volScalarField p Create scalar volField p Outputs size of patch (number of faces)
(
IOobject • In the previous statement mesh.boundaryMesh() is the size of the loop, and patchI
( is the iterator. The iterator always starts from zero.
"p",
runTime.timeName(), Assign and initialization of • The forAll loop is equivalent to the standard for loop in C++.
mesh, scalar volField to the
IOobject::MUST_READ, mesh
IOobject::AUTO_WRITE for (int i = 0; i < mesh.boundaryMesh().size(); i++)
Info << "Patch " << i << ": " << mesh.boundary()[i].name() << " with "
), << mesh.boundary()[i].Cf().size() << " faces. Starts at total face "
mesh << mesh.boundary()[i].start() << endl;
);
Info<< p << endl; Outputs starting face of patch
Output some information
Info<< p.boundaryField()[0] << endl;
• Notice that we used as iterator i instead of patchI, this does not make any
960 difference. 961
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Equation discretization in OpenFOAM® Discretization of the basic PDE terms in OpenFOAM®
The list is not complete
• At this stage, OpenFOAM® converts the PDEs into a set of linear algebraic
equations, A x = b, where x and b are volFields (geometricField). Mathematical fvm::
Term description
expression fvc::
• A is a fvMatrix, which is created by the discretization of a geometricField and
inherits the algebra of its corresponding field, and it supports many of the standard
algebraic matrix operations. laplacian(phi)
Laplacian , laplacian(Gamma, phi)
• The fvm (finiteVolumeMethod) and fvc (finiteVolumeCalculus) classes contain
static functions for the differential operators, and discretize any geometricField. ddt(phi)
Time derivative ,
• fvm returns a fvMatrix, and fvc returns a geometricField. ddt(rho,phi)
• In the directories $FOAM_SRC/finiteVolume/finiteVolume/fvc and
$FOAM_SRC/finiteVolume/finiteVolume/fvm you will find the respective div(psi,scheme)
Convection ,
classes. div(psi,phi)

• Remember, the PDEs or ODEs we want to solve involve derivatives of tensor fields
Sp(rho,phi)
with respect to time and space. What we re doing at this point, is applying the finite Source
SuSp(rho,phi)
volume classes to the fields, and assembling a linear system.
vol<type>Field scalar, volScalarField surfaceScalarField

962 963

Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks


Discretization of the basic PDE terms in OpenFOAM® Discretization of the basic PDE terms in OpenFOAM®
• To discretize the fields in a valid mesh, we need to access the finite volume class. • The previous discretization is equivalent to,
This class can be accessed by adding the header fvCFD.H to your program.
• To discretize the scalar transport equation in a mesh, we can proceed as follows, Creates object TEqn that
fvScalarMatrix TEqn contains the coefficient matrix
arising from the discretization
(
Assemble and solve
solve linear system arising form fvm::ddt(T)
( the discretization + fvm::div(phi,T) Discretize equations

fvm::ddt(T) - fvm::laplacian(DT,T)
+ fvm::div(phi,T) Discretize equations );
- fvm::laplacian(DT,T)
); Teqn.solve(); Solve the linear system Teqn

• Here, fvScalarMatrix contains the matrix derived from the discretization of the model
• Remember, you will need to first create the mesh, and initialize the variables and equation.
constants. That is, all the previous steps. • fvScalarMatrix is used for scalar fields and fvVectorMatrix is used for vector fields.
• Finally, everything we have done so far inherits all parallel directives. There is no • This syntax is more general, since it allows the easy addition of terms to the model
need for specific parallel programming. equations.
964 965
Programming in OpenFOAM®. Building blocks Programming in OpenFOAM®. Building blocks
Discretization of the basic PDE terms in OpenFOAM® Example of use of tensor and field classes
• At this point, OpenFOAM® assembles and solves the following linear system, • Let us study a fvMesh example. First let us compile the program my_Test-
mesh. Type in the terminal,

1. $> cd $PTOFC/programming_playground/my_mesh/
2. $> wmake

• To access the mesh information, we need to use this program in a valid


mesh.
1. $> cd $PTOFC/programming_playground/my_mesh/cavity
2. $> blockMesh
3. $> my_Test-mesh

• At this point, take a look at the output and study the file Test-mesh.C. Try to
Coefficient Matrix (sparse, square) understand what we have done.
The coefficients depend on geometrical quantities, Boundary conditions
fluid properties and non linear equations and source terms • FYI, the original example is located in the directory
Unknow quantity
$PTOFC/programming_playground/test/mesh.
966 967

Programming in OpenFOAM®. Building blocks Roadmap


A few OpenFOAM® programming references

• You can access the API documentation in the following link, https://cpp.openfoam.org/v5/ 1. Programming in OpenFOAM®. Building blocks.
• You can access the coding style guide in the following link, https://openfoam.org/dev/coding-style-guide/
• You can report programming issues in the following link, https://bugs.openfoam.org/rules.php 2. codeStream – Highlights
• You can access openfoamwiki coding guide in the following link,
http://openfoamwiki.net/index.php/OpenFOAM_guide
3. Implementing boundary conditions using
• You can access the user guide in the following link, https://cfd.direct/openfoam/user-guide/ codeStream
• You can read the OpenFOAM® Programmer’s guide in the following link (it seems that this guide is not
supported anymore), http://foam.sourceforge.net/docs/Guides-a4/ProgrammersGuide.pdf 4. Solution initialization using codeStream
5. Implementing boundary conditions using high level
A few good C++ references programming
• The C++ Programming Language. B. Stroustrup. 2013, Addison-Wesley.
• The C++ Standard Library. N. Josuttis. 2012, Addison-Wesley. 6. Modifying applications – Highlights
• C++ for Engineers and Scientists. G. J. Bronson. 2012, Cengage Learning.
• Sams Teach Yourself C++ in One Hour a Day. J. Liberty, B. Jones. 2004, Sams Publishing. 7. Implementing an application from scratch
• C++ Primer. S. Lippman, J. Lajoie, B. Moo. 2012, Addison-Wesley.
• http://www.cplusplus.com/ 8. Adding the scalar transport equation to icoFoam
• http://www.learncpp.com/
• http://www.cprogramming.com/
• http://www.tutorialspoint.com/cplusplus/
• http://stackoverflow.com/
968 969
codeStream – Highlights codeStream – Highlights
• There are many boundary conditions available in OpenFOAM®. • When it comes to initial conditions, you can use the utility setFields.
• But from time to time it may happen that you do not find what you are looking for. • This utility is very flexible, you can even read STL files and use them to initialize fields.
• It is possible to implement your own boundary conditions, so in theory you can do whatever you • But again, it may happen that you can not get the desired results.
want.
• As for boundary conditions, to implement your own initials conditions you have three options:
• Remember, you have the source code. • Use codeStream.
• To implement your own boundary conditions, you have three options: • Use high level programing.
• Use codeStream.
• Use an external library (e.g., swak4foam).
• Use high level programing. • codeStream is the simplest way to implement initial conditions, and most of the times you will
• Use an external library (e.g., swak4foam). be able to code initial conditions with no problem.
• codeStream is the simplest way to implement boundary conditions, and most of the times you • If you can not implement your initial conditions using codeStream, you can use high level
will be able to code boundary conditions with no problem. programming. However, this requires some knowledge on C++ and OpenFOAM® API.
• If you can not implement your boundary conditions using codeStream, you can use high level • Hereafter, we are going to work only with codeStream.
programming. However, this requires some knowledge on C++ and OpenFOAM® API. • Using high level programming is a little bit more trickier, and we guarantee you that 99% of the
• Hereafter, we are going to work with codeStream and basic high level programming. time codeStream will work.
• We are not going to work with swak4Foam because it is an external library that is not officially • 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 relative easy to supported by the OpenFOAM foundation®. However, it works very well and is relative easy to
use. use.

970 971

codeStream – Highlights Roadmap


• You can access the API documentation in the following link,
https://cpp.openfoam.org/v5/ 1. Programming in OpenFOAM®. Building blocks.
2. codeStream – Highlights
3. Implementing boundary conditions using
API documentation
codeStream
4. Solution initialization using codeStream
5. Implementing boundary conditions using high level
programming
Boundary conditions and
6. Modifying applications – Highlights
functionObjects documentation
7. Implementing an application from scratch
8. Adding the scalar transport equation to icoFoam

972 973
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• OpenFOAM® includes the capability to compile, load and execute C++ code Body of the codeStream directive for boundary conditions
at run-time.
patch-name Patch name
• This capability is supported via the directive #codeStream, that can be used {
type fixedValue;
in any input file for run-time compilation. value #codeStream
Use codeStream to set the value
{ of the boundary condition
• This directive reads the entries code (compulsory), codeInclude (optional), codeInclude
#{
codeOptions (optional), and codeLibs (optional), and uses them to #include "fvCFD.H" Files needed for compilation
generate the dynamic code. #};

• The source code and binaries are automatically generated and copied in the codeOptions
#{
directory dynamicCode of the current case. -I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
• The source code is compiled automatically at run-time. #};

codeLibs
• The use of codeStream is a very good alternative to avoid high level #{
Libraries needed for compilation.
Needed if you want to visualize the
programming of boundary conditions or the use of external libraries. -lmeshTools \
-lfiniteVolume output of the boundary condition
at time zero
• Hereafter we will use codeStream to implement new boundary conditions, #};

but have in mind that codeStream can be used in any dictionary. code
Insert your code here.
#{
At this point, you need to know
#}; how to access mesh information
};
}
974 975

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream Implementation of a parabolic inlet profile using codeStream
• Let us implement a parabolic inlet profile. • We will use the following formula to implement the 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

• 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,

Inlet
velocity-inlet-5

Inlet Bounds of velocity-inlet-5 boundary patch


velocity-inlet-6
Parabolic inlet profile 976 977
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• The codeStream BC in the body of the file U is as follows, • The code section of the codeStream BC in the body of the file U is as follows,

To access boundary mesh information


1 code
velocity-inlet-5 Patch name 2 #{
{
3 const IOdictionary& d = static_cast<const IOdictionary&>
type fixedValue;
4 (
value #codeStream
5 dict.parent().parent()
{
6 );
codeInclude
7
#{
8 const fvMesh& mesh = refCast<const fvMesh>(d.db());
#include "fvCFD.H"
9 const label id = mesh.boundary().findPatchID("velocity-inlet-5");
#};
Depending of what are you trying 10 const fvPatch& patch = mesh.boundary()[id];
11
codeOptions to do, you will need to add new
12 vectorField U(patch.size(), vector(0, 0, 0));
#{ files, options and libraries. 13
-I$(LIB_SRC)/finiteVolume/lnInclude \
14 ...
-I$(LIB_SRC)/meshTools/lnInclude For most of the cases, this part is 15 ... Remember to update this value with the
#};
always the same. 16 ...
actual name of the patch
17 #};
codeLibs
#{
-lmeshTools \ • Lines 3-11, are always standard, they are used to access boundary mesh information.
-lfiniteVolume
#}; • In lines 3-6 we access the current dictionary.
• In line 8 we access the mesh database.
code
Insert your code here. • 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
#{
At this point, you need to know the patch).
#}; how to access mesh information • 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
978 the statement vector(0, 0, 0) initializes a zero vector field in the patch. 979

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows, Implementation of a parabolic inlet profile using codeStream
1 code Index used to access the • This case is ready to run, the input files are located in the directory
2 #{ y coordinate $PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet
3 ... 0→x
4 ...
5 ...
1→y • To run the case, type in the terminal,
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 1. $> cd $PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet
9 const scalar p_r = 8.; //patch radius
10 2. $> foamCleanTutorials
11 forAll(U, i) //equivalent to for (int i=0; patch.size()<i; i++)
12
13
{
const scalar y = patch.Cf()[i][1];
3. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh

14 U[i] = vector(U_0*(1-(pow(y - p_ctr,2))/(p_r*p_r)), 0., 0.);


15 }
4. $> icoFoam | tee log
16 Assign input profile to vector field U (component x)
17 U.writeEntry("", os); 5. $> paraFoam
18 #};

• In lines 6-17 we implement the new boundary condition. • The codeStream boundary condition is implemented in the file 0/U.
• In lines 6-9 we declare a few constant 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. 980 981
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream codeStream works with scalar and vector fields
• If everything went fine, you should get something like this • 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 S.writeEntry("", os);
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
982 983

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile 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. • We will implement the following equation in the boundary patch auto3.
• As usual, the first step is to get all the spatial references.

Inlet
auto3

Bounds of auto3 boundary patch


Paraboloid inlet profile
984 985
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• The codeStream BC in the body of the file U is as follows, • Hereafter, we only show the actual implementation of the codeStream boundary
condition.
auto3 Patch name
{ • The rest of the body is a template that you can always reuse. Including the section of
type fixedValue; how to access the dictionary and mesh information.
value #codeStream
{ • Remember, is you are working with a vector, you need to use vector fields. Whereas,
codeInclude
#{ if you are working with scalars, you need to use scalars fields.
#include "fvCFD.H"
#}; 1 code
For most of the cases, this part is 2 #{
codeOptions always the same. But depending of 3 ...
#{ 4 ...
what are you trying to do, you will
-I$(LIB_SRC)/finiteVolume/lnInclude \ 5 ...
-I$(LIB_SRC)/meshTools/lnInclude need to add more files, options and 6 vectorField U(patch.size(), vector(0, 0, 0) );
libraries. Initialize vector field
#}; 7
8 const scalar s = 0.5; Initialize scalar
codeLibs 9
#{ 10 forAll(U, i)
-lmeshTools \ 11 {
-lfiniteVolume 12 const scalar x = patch.Cf()[i][0]; Access faces center
#}; 13 const scalar y = patch.Cf()[i][1]; coordinates (x, y, and z)
Insert your code here. 14 const scalar z = patch.Cf()[i][2];
code 15
#{
We will implement the following
16 U[i] = vector(-1.*(pow(z/s, 2) + pow((y-s)/s,2) - 1.0), 0, 0);
equation 17 }
#}; 18
}; 19 U.writeEntry("", os);
} 20 #};
986 987

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream Implementation of a paraboloid inlet profile using codeStream
• This case is ready to run, the input files are located in the directory • If everything went fine, you should get something like this
$PTOFC/101programming/codeStream_BC/3Delbow_Uparaboloid/
• To run the case, type in the terminal,

1. $> cd $PTOFC/101programming/codeStream_BC/3Delbow_Uparaboloid/

2. $> foamCleanTutorials
3. $> gmshToFoam ../../../meshes_and_geometries/gmsh_elbow3d/geo.msh

4. $> autoPatch 75 -overwrite


5. $> createPatch -overwrite
6. $> renumberMesh -overwrite
7. $> icoFoam | tee log
8. $> paraFoam

• The codeStream boundary condition is implemented in the file 0/U.

988 989
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
codedFixedValue and codedMixed boundary conditions Body of the codedFixedValue boundary conditions
• OpenFOAM® also includes the boundary conditions codedFixedValue and patch-name Patch name
codedMixed. {
Use codedFixedValue and
type codedFixedValue;
• These boundary conditions are derived from codeStream and work in a value uniform (0 0 0); initializations

similar way. Unique name of the new boundary


redirectType name_of_BC; condition.
• They use a friendlier notation and let you access more information of the If you have more codedFixedValue
BC, the names must be different
simulation database (e.g. time). codeOptions
#{
• The source code and binaries are automatically generated and copied in the -I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
directory dynamicCode of the current case. #};

• Another feature of these boundary conditions, is that the code section can be codeInclude
#{
read from an external dictionary (system/codeDict), which is run-time #include "fvCFD.H"
Files needed for compilation
modifiable. #include <cmath>
#include <iostream>
#};
• The boundary condition codedMixed works in similar way. This boundary In this section we do the actual
implementation of the boundary
condition gives you access to fixed values (Dirichlet BC) and gradients code
#{ condition.
(Neumann BC). This is the only part of the body
#}; that you will need to change. The
• Let us implement the parabolic profile using codedFixedValue. } rest of the body is a template that
990
you can always reuse. 991

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows, codedFixedValue and codedMixed boundary conditions
• As you can see, the syntax and use of the codedFixedValue and codedMixed
1 code
2 #{ boundary conditions is much simpler than codeStream.
3 const fvPatch& boundaryPatch = patch();
4 const vectorField& Cf = boundaryPatch.Cf(); • You can use these instructions as a template. At the end of the day, you only need to
5
6
vectorField& field = *this; modify the code section.
7 scalar U_0 = 2, p_ctr = 8, p_r = 8;
8
• Depending of what you want to do, you might need to add new headers and
9 forAll(Cf, faceI) compilation options.
10 {
11 field[faceI] = vector(U_0*(1-(pow(Cf[faceI].y()-p_ctr,2))/(p_r*p_r)),0,0); • Remember, is you are working with a vector, you need to use vector fields. Whereas,
12 }
13 #};
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.
• 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). • On the positive side, accessing time and other values from the simulation database is
• In this case, as we are going to implement a vector profile, we initialize a vector field where we are going to straightforward.
assign the profile (line 5).
• Time can be accessed by adding the following statement,
• 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. this->db().time().value()
• In line 11 we do the actual implementation of the boundary profile (similar to the codeStream case). The
vector field was initialize in line 5.
992 993
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• Let us add time dependency to the parabolic profile. Implementation of a parabolic inlet profile using codedFixedValue
• This case is ready to run, the input files are located in the directory
1 code $PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet_timeDep
2 #{
3 const fvPatch& boundaryPatch = patch(); • To run the case, type in the terminal,
4 const vectorField& Cf = boundaryPatch.Cf();
5 vectorField& field = *this;
6
7 scalar U_0 = 2, p_ctr = 8, p_r = 8; 1. $> cd $PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet_timeDep
8
9 scalar t = this->db().time().value(); Time 2. $> foamCleanTutorials
10
11 forAll(Cf, faceI) 3. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh
12 {
13 field[faceI] = vector(sin(t)*U_0*(1-(pow(Cf[faceI].y()-p_ctr,2))/(p_r*p_r))),0,0);
4. $> icoFoam | tee log
14 }
15 #};
Time dependency 5. $> paraFoam

• This implementation is similar to the previous one, we will only address how to deal with time.
• The codeStream boundary condition is implemented in the file 0/U.
• 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 initialize 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).
994 995

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue Filling a tank using codedFixedValue
• If everything went fine, you should get something like this • Let us do a final example.
• We will deal with scalar and vector fields at the same Water enters here
time. This is a face selection in a single boundary patch

• 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.
www.wolfdynamics.com/wiki/BCIC/elbow_unsBC1.gif The tank is initially empty

996 997
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• Definition of the vector field boundary condition (dictionary file U), • Definition of the vector field boundary condition (dictionary file U),

Name of the patch where we want to implement the boundary condition 7 code Code section. The actual implementation of the BC is done in this section
8 #{
...
1 leftWall Use codedFixedValue BC and initialize value. ... Loop using size of boundary patch (Cf) and iterator
2 { The initialization is only needed for paraview ... faceI.
3 type codedFixedValue; in order to visualize something at time zero. 19 This is equivalent to:
4 value uniform (0 0 0); 20 forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
5 redirectType inletProfile1; Unique name of the BC 21 {
6 Do not use the same name in other patches 22
7 code 23 if (
8 #{ 24 (Cf[faceI].z() > minz) &&
9 const fvPatch& boundaryPatch = patch(); Access boundary mesh Use conditional structure to
25 (Cf[faceI].z() < maxz) &&
10 const vectorField& Cf = boundaryPatch.Cf(); information and initialize 26 (Cf[faceI].y() > miny) && select faces according to the
11 vectorField& field = *this; vector field field 27 (Cf[faceI].y() < maxy) variables defined in lines 13-16
12 28 )
13 scalar minz = 0.4; 29 {
14 scalar maxz = 0.6; 30 if ( t < 1.)
15 scalar miny = 0.5; Initialize variables 31 { Use conditional structure to
16 scalar maxy = 0.7; 32 field[faceI] = vector(1,0,0); add time dependency and
17 33 } assign values to the
18 scalar t = this->db().time().value(); Access time 34 else
... selected faces.
35 {
... 36 field[faceI] = vector(0,0,0); The variable field was
... 37 } initialize in line 11.
40 #}; 38 }
41 } 39 }
40 #};
41 }
998 999

Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
• Definition of the scalar field boundary condition (dictionary file alpha.water), • Definition of the scalar field boundary condition (dictionary file alpha.water),

Name of the patch where we want to implement the boundary condition 7 code Code section. The actual implementation of the BC is done in this section
8 #{
1 leftWall Use codedFixedValue BC and initialize value. ...
2 { Loop using size of boundary patch (Cf) and iterator
The initialization is only needed for paraview ...
3 type codedFixedValue; in order to visualize something at time zero. ... faceI.
4 value uniform 0; 22 This is equivalent to:
5 redirectType inletProfile2; Unique name of the BC 23 forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
6 Do not use the same name in other patches 24 {
7 code 25 if (
8 #{ 26 (Cf[faceI].z() > minz) && Use conditional structure to
9 const fvPatch& boundaryPatch = patch(); Access boundary mesh 27 (Cf[faceI].z() < maxz) && select faces according to the
Code section. The actual implementation of

10 const vectorField& Cf = boundaryPatch.Cf(); information and initialize 28 (Cf[faceI].y() > miny) &&
11 scalarField& field = *this; variables defined in lines 13-16
scalar field field 29 (Cf[faceI].y() < maxy)
12 30 )
13 field = patchInternalField(); Assign value from the internal field to the patch 31 {
14
the BC is done in this section

32 if ( t < 1.)
15 scalar minz = 0.4; 33 {
16 scalar maxz = 0.6;
Use conditional structure to add
Initialize variables 34 field[faceI] = 1.; time dependency and assign
17 scalar miny = 0.5; 35 }
18 scalar maxy = 0.7; 36 else
values to the selected faces.
20 37 { The variable field was initialize in
21 scalar t = this->db().time().value(); Access time 38 field[faceI] = 0.; line 11.
22 39 }
... 40 }
... 41 }
... 42 #};
42 #}; 43 }
43 }
1000 1001
Implementing boundary conditions using codeStream Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue Implementation of a parabolic inlet profile using codedFixedValue
• This case is ready to run, the input files are located in the directory • If everything went fine, you should get something like this
$PTOFC/101programming/codeStream_BC/fillBox_BC/
• To run the case, type in the terminal,

1. $> cd $PTOFC/101programming/codeStream_BC/fillBox_BC/
2. $> foamCleanTutorials
3. $> blockMesh
4. $> decomposePar
5. $> mpirun -np 4 interFoam -parallel | tee log
6. $> reconstructPar
7. $> paraFoam

• As you can see, we can also run in parallel with no problem.


Visualization of water phase Volume integral of water entering the
• FYI, the stand alone version of Paraview does not handle codedFixedValue BC. (alpha.water) domain
• To visualize the results, you need to use paraFoam with no options (avoid the option www.wolfdynamics.com/wiki/BCIC/filltank1.gif
–builtin). 1002 1003

Roadmap Solution initialization using codeStream


• When it comes to initial conditions, you can use the utility setFields.
1. Programming in OpenFOAM®. Building blocks. • This utility is very flexible, you can even read STL files and use them to
2. codeStream – Highlights initialize your fields.
• But in case that you can not get the desired results using setFields, you
3. Implementing boundary conditions using can implement your own initial conditions using codeStream.
codeStream
• To implement initial conditions using codeStream, we proceed in a similar
4. Solution initialization using codeStream way as for boundary conditions.
5. Implementing boundary conditions using high level • The source code and binaries are automatically generated and copied in the
programming directory dynamicCode of the current case.
• The source code is compiled automatically at run-time.
6. Modifying applications – Highlights
• The use of codeStream is a very good alternative to avoid high level
7. Implementing an application from scratch programming of initial conditions or the use of external libraries.
8. Adding the scalar transport equation to icoFoam • Hereafter we will use codeStream to implement new initial conditions.

1004 1005
Solution initialization using codeStream Solution initialization using codeStream
Body of the codeStream directive for initial conditions Implementation of an elliptic initialization using codeStream

internalField #codeStream Use codeStream to set the value • Let us implement an elliptic initialization using codeStream.
{ of the initial conditions
{
• The firs step is to know your domain and identify the region that you want to initialize.
codeInclude
#{
• Then you will need to do a little bit of math to get the expression for the initialization.
#include "fvCFD.H" Files needed for compilation
• In this example, we are also going to show you how to do the same initialization by
Initial conditions

#};
reading a STL file with the utility setFields.
codeOptions

Initialization using STL


#{
-I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
#}; Phase 2

codeLibs
Libraries needed for compilation.
#{
-lmeshTools \ Needed if you want to visualize the
-lfiniteVolume output of the initial conditions at
#}; time zero

code Phase 1
#{
Insert your code here.
#}; At this point, you need to know
}; how to access internal mesh
} information Initialization using codeStream Initialization using a STL with setFields

1006 1007

Solution initialization using codeStream Solution initialization using codeStream


• The codeStream IC in the body of the file alpha.phase1 is as follows, • The code section of the codeStream IC in the body of the file alpha.phase1 is as follows,

Access internal mesh information


Use codeStream to set the value code
internalField #codeStream
of the initial conditions #{
{
const IOdictionary& d = static_cast<const IOdictionary&>(dict);
{
const fvMesh& mesh = refCast<const fvMesh>(d.db());
codeInclude
#{
scalarField alpha(mesh.nCells(), 0.); Initialize scalar field to zero
#include "fvCFD.H"
#};
scalar he = 0.5;
scalar ke = 0.5;
Initialize variables
codeOptions Depending of what are you trying
scalar ae = 0.3;
#{ to do, you will need to add new scalar be = 0.15;
-I$(LIB_SRC)/finiteVolume/lnInclude \ forAll loop to access cell centers and to assign alpha values.
files, options and libraries. Notice the alpha was previously initialized.
-I$(LIB_SRC)/meshTools/lnInclude
forAll(alpha, i) The size of the loop is defined by alpha and the iterator is i.
#};
For most of the cases, this part is {
always the same. const scalar x = mesh.C()[i][0];
codeLibs
const scalar y = mesh.C()[i][1]; Access cell centers coordinates
#{
const scalar z = mesh.C()[i][2];
Assign value to alpha

-lmeshTools \
-lfiniteVolume
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.;
code
}

following statement
#{
Insert your code here. }
alpha.writeEntry("", os);
#}; At this point, you need to know
#};
}; how to access internal mesh
} information Write output to input dictionary

1008 1009
Solution initialization using codeStream Solution initialization using codeStream
Implementation of an elliptic initialization using codeStream Implementation of an elliptic initialization using codeStream
• This case is ready to run, the input files are located in the directory • If everything went fine, you should get something like this
$PTOFC/101programming/codeStream_INIT/elliptical_IC
• To run the case, type in the terminal,

1. $> cd $PTOFC/101programming/codeStream_INIT/elliptical_IC
2. $> foamCleanTutorials
3. $> blockMesh
4. $> rm –rf 0
5. $> cp –r 0_org 0
6. $> paraFoam
7. $> interFoam | tee log
8. $> paraFoam
codeStream initialization setFields initialization
Visualization of volume fraction (alpha.phase1) Visualization of volume fraction (alpha.phase1)
• In step 6, we launch paraFoam to visualize the initialization. www.wolfdynamics.com/wiki/BCIC/bubble_zeroG.gif www.wolfdynamics.com/wiki/BCIC/bubble_zeroG_SF.gif

• FYI, you can run in parallel with no problem.


Surface tension driven flow - Bubble in a zero gravity flow using interFoam
1010 1011

Solution initialization using codeStream Solution initialization using codeStream


Elliptic initialization using setFields The setFieldsDict dictionary
• Let us do the same initialization using a STL file with setFields.
defaultFieldValues
• First, you will need to create the solid model that encloses the region you want to (
Initialize the whole domain to zero
volScalarFieldValue alpha.phase1 0
initialize. For this, you can use your favorite CAD/solid modeling software. );
Remember to save the geometry is STL format. setFields method to read STL files.
regions
If you want to know all the options
• Then you will need to read in the STL file using setFields. You will need to modify (
available use a word that does not exist
the setFieldsDict dictionary. 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
Region defined by
fieldValues
the STL file (
Computational domain
volScalarFieldValue alpha.phase1 1 Initialize this value.
); In this case the initialization will be inside
the STL
}
);
1012 1013
Solution initialization using codeStream Solution initialization using codeStream
Elliptic initialization using setFields Rayleigh-Taylor instability initialization
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_INIT/elliptical_IC
• Let us study the Rayleigh-Taylor
• To run the case, type in the terminal, instability.
• In this case, we have two phases with
1. $> cd $PTOFC/101programming/codeStream_INIT/elliptical_IC different physical properties (one phase
2. $> foamCleanTutorials is heavier).
• To onset this instability, we need to
3. $> blockMesh
perturbate somehow the interface
4. $> rm –rf 0 between the two phases.

5. $> cp –r 0_org 0 • We will use codeStream to initialize the


two phases.
6. $> setFields
• For simplicity, we will only show the
7. $> paraFoam code section of the input files.
• The entries codeInclude, codeOptions,
• At this point, compare this initialization with the previous one. and codeLibs, are the same most of the
• Also, feel free to launch the simulation using interFoam. times.

1014 1015

Solution initialization using codeStream Solution initialization using codeStream


• The code section of the codeStream IC in the body of the file alpha.phase1 is as follows, Rayleigh-Taylor instability initialization
• This case is ready to run, the input files are located in the directory
code Access internal mesh information
#{ $PTOFC/101programming/codeStream_INIT/rayleigh_taylor
const IOdictionary& d = static_cast<const IOdictionary&>(dict);
const fvMesh& mesh = refCast<const fvMesh>(d.db()); • To run the case, type in the terminal,
scalarField alpha(mesh.nCells(), 0.); Initialize scalar field to zero
forAll(alpha, i)
1. $> cd $PTOFC/101programming/codeStream_INIT/rayleigh_taylor
Assign value to alpha

{
const scalar x = mesh.C()[i][0];
const scalar y = mesh.C()[i][1];
Access cell centers coordinates 2. $> foamCleanTutorials
if (y >= -0.05*cos(2*constant::mathematical::pi*x)) 3. $> blockMesh
{
alpha[i] = 1.; 4. $> interFoam | tee log
}
} 5. $> paraFoam
alpha.writeEntry("", os);
#}; Write output to input dictionary

• FYI, you can run in parallel with no problem.


• For simplicity, we only show the code section.
• The rest of the body of the codeStream IC is a template.

1016 1017
Solution initialization using codeStream Solution initialization using codeStream
Rayleigh-Taylor instability initialization Filling a tank using codeStream and codedFixedValue
• If everything went fine, you should get something like this • 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 conditions Visualization of volume fraction, static pressure and velocity


magnitude
www.wolfdynamics.com/wiki/BCIC/rayleigh_taylor_ins1.gif

Initial water level

1018 1019

Solution initialization using codeStream Solution initialization using codeStream


• The code section of the codeStream IC in the body of the file alpha.water is as follows, • The code section of the codeFixedValue BC in the body of the file U is as follows,

Use codeStream to set the Name of the patch where we want to implement the boundary condition
internalField #codeStream
{ value of the initial conditions

Access internal mesh information


... leftWall Use codedFixedValue BC and initialize value.
... { The initialization is only needed for paraview
... type codedFixedValue;
in order to visualize something at time zero.
code value uniform (0 0 0);
#{
Unique name of the BC
const IOdictionary& d = static_cast<const IOdictionary&>(dict); redirectType inletProfile1;
const fvMesh& mesh = refCast<const fvMesh>(d.db()); Do not use the same name in other patches
code Code section. The actual implementation of the BC is done here
scalarField alpha(mesh.nCells(), 0.); Initialize scalar field to zero #{
const fvPatch& boundaryPatch = patch(); Access boundary mesh
forAll(alpha, i) const vectorField& Cf = boundaryPatch.Cf(); information and initialize
{ vectorField& field = *this; vector field field
const scalar x = mesh.C()[i][0];
const scalar y = mesh.C()[i][1]; Access cell centers scalar min = 0.5;
const scalar z = mesh.C()[i][2]; coordinates scalar max = 0.7; Initialize variables

if (y <= 0.2) scalar t = this->db().time().value(); Access time


{ Assign value to alpha according to ...
alpha[i] = 1.; conditional structure ...
} ...
} #};
}
alpha.writeEntry("", os); Write output to input dictionary
#};

1020 1021
Solution initialization using codeStream Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file U is as follows, • 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 Name of the patch where we want to implement the boundary condition
#{
... leftWall Use codedFixedValue BC and initialize value.
... Loop using size of boundary patch (Cf) and iterator { The initialization is only needed for paraview
... faceI. type codedFixedValue; in order to visualize something at time zero.
This is equivalent to: value uniform 0;
forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++) Unique name of the BC
{ redirectType inletProfile2;
Do not use the same name in other patches
if (
(Cf[faceI].z() > min) && code Code section. The actual implementation of the BC is done here
(Cf[faceI].z() < max) && Use conditional structure to #{
(Cf[faceI].y() > min) && const fvPatch& boundaryPatch = patch(); Access boundary mesh
select faces.
(Cf[faceI].y() < max) const vectorField& Cf = boundaryPatch.Cf(); information and initialize
) scalarField& field = *this; scalar field field
{
if ( t < 2.)
{ field = patchInternalField(); Assign value from the internal field to the patch
field[faceI] = vector(1,0,0); Use conditional structure to
} scalar min = 0.5;
add time dependency and scalar max = 0.7;
Initialize variables
else
assign values to the
{
field[faceI] = vector(0,0,0); selected faces. scalar t = this->db().time().value(); Access time
} ...
} ...
} ...
#}; #};
}
1022 1023

Solution initialization using codeStream Solution initialization using codeStream


• The code section of the codeFixedValue BC in the body of the file alpha.water is as follows, Filling a tank using codeStream and codedFixedValue
• If everything went fine, you should get something like this
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.;
}
} Visualization of water phase (alpha.water) Volume integral of water entering
}
#}; www.wolfdynamics.com/wiki/BCIC/filltank2.gif the domain

1024 1025
Roadmap Implementing boundary conditions using high level programming

• Hereafter we will work with high level programming, this is the hard part of
1. Programming in OpenFOAM®. Building blocks. programming in OpenFOAM®.
2. codeStream – Highlights • High level programming requires some knowledge on C++ and OpenFOAM®
API library.
3. Implementing boundary conditions using • Before doing high level programming, we highly recommend you to try with
codeStream codeStream, most of the time it will work.
4. Solution initialization using codeStream • We will implement the parabolic profile, so you can compare this
implementation with codeStream ad codedFixedValue BCs.
5. Implementing boundary conditions using high level
programming • When we program boundary conditions, we are actually building a new
library that can be linked with any solver. To compile the library, we use the
6. Modifying applications – Highlights command wmake (distributed with OpenFOAM®).
7. Implementing an application from scratch • At this point, you can work in any directory. But we recommend you to work
in your OpenFOAM® user directory, type in the terminal,
8. Adding the scalar transport equation to icoFoam
1. $> cd $WM_PROJECT_USER_DIR/run

1026 1027

Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

• Let us create the basic structure to write the new boundary condition, type in Directory structure of the new boundary condition
the terminal,
./myParabolicVelocity
├── Make
1. $> foamNewBC –f –v myParabolicVelocity │ ├── files
│ └── options
2. $> cd myParabolicVelocity
├── myParabolicVelocityFvPatchVectorField.C
└── myParabolicVelocityFvPatchVectorField.H

• The utility foamNewBC, will create the directory structure and all the files needed to
write your own boundary conditions. The directory contains the source code of the boundary condition.
• myParabolicVelocityFvPatchVectorField.C: is the actual source code of the
• We are setting the structure for a fixed (the option –f) velocity (the option –v), application. This file contains the definition of the classes and functions.
boundary condition, and we name our boundary condition ParabolicVelocity .
• myParabolicVelocityFvPatchVectorField.H: header files required to compile the
• If you want to get more information on how to use foamNewBC, type in the terminal, application. This file contains variables, functions and classes declarations.
• The Make directory contains compilation instructions.
1. $> foamNewBC –help • Make/files: names all the source files (.C), it specifies the boundary condition
library name and location of the output file.
• Make/options: specifies directories to search for include files and libraries to link the
solver against.
1028 1029
Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The header file (.H) The header file (.H)


• Let us start to do some modifications. Open the header file using your favorite text • At this point, your header file should looks like this one,
editor (we use gedit).
99 //- Single valued scalar quantity, e.g. a coefficient
100 scalar scalarData_;
99 //- Single valued scalar quantity, e.g. a coefficient 101
100 scalar scalarData_; • In lines 99-126 different types of 102 //- Single valued Type quantity, e.g. reference pressure pRefValue_
101 private data are declared. 103 // Other options include vector, tensor
102 //- Single valued Type quantity, e.g. reference pressure pRefValue_ 104 vector data_;
103 // Other options include vector, tensor • These are the variables we will 105 vector data_;
104 vector data_;
105
use for the implementation of the
106 //- Field of Types, typically defined across patch faces new BC.
107 // e.g. total pressure p0_. Other options include vectorField
108 vectorField fieldData_; • In our implementation we need • Change the name of scalarData_ to maxValue_ (line 100).
109
to use vectors and scalars,
110 //- Type specified as a function of time for time-varying BCs
therefore we can keep the lines
• Change the names of the two vectors data_ (lines 104-105). Name the first one n_
111 autoPtr<Function1<vector>> timeVsData_;
112 100 and 104. and the last one y_.
113 //- Word entry, e.g. pName_ for name of the pressure field on database
114 word wordData_; • We can delete lines 106-120, as
115
116 //- Label, e.g. patch index, current time index we do not need those datatypes. 99 //- Single valued scalar quantity, e.g. a coefficient
117 label labelData_; 100 scalar maxValue_;
118 • Also, as we will use two vectors 101 It is recommended to initialize
119 //- Boolean for true/false, e.g. specify if flow rate is volumetric_ in our implementation, we can 102 //- Single valued Type quantity, e.g. reference pressure pRefValue_
120 bool boolData_; 103 // Other options include vector, tensor them in the same order as you
duplicate line 104.
121 104 vector n_; declare them in the header file
122 105 vector y_;
123 // Private Member Functions • You can leave the rest of the file
124 as it is.
125 //- Return current time
126 scalar t() const; • You can now save and close the file.
1030 1031

Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The source file (.C) The source file (.C)


• Let us start to modify the source file. Open the source file with your favorite editor. • At this point, let us erase all the occurrences of the datatypes fieldData, timeVsData,
• Lines 34-37 refers to a private function definition. This function allows us to access wordData, labelData, and boolData.
simulation time. Since in our implementation we do not need to use time, we can • Locate line 38,
safely remove these lines.
38 Foam::myParabolicVelocityFvPatchVectorField::
...
34 Foam::scalar Foam::myParabolicVelocityFvPatchVectorField::t() const ...
35 { ...
36 return db().time().timeOutputValue();
37 }

• Using this line as your reference location in the source code, follow these steps,

• Let us compile the library to see what errors we get. Type in the terminal, • Erase the following lines in incremental order (be sure to erase only the lines that
contain the words fieldData, timeVsData, wordData, labelData and boolData):
1. $> wmake 48-52, 64-68, 92-96, 105-109, 119-123, 177-180.
• Erase the following lines (they contain the word fieldData), 131, 146, 159-161.
• You will get a lot of errors. • Replace all the occurrences of the word scalarData with maxValue (11
• Since we deleted the datatypes fieldData, timeVsData, wordData, labelData and occurrences).
boolData in the header file, we need to delete them as well in the C file. Otherwise
the compiler complains. 1032 1033
Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The source file (.C) The source file (.C)


• Duplicate all the lines where the word data appears (6 lines), change the word data • We are almost done, we just defined all the datatypes. Now we need to implement
to n in the first line, and to y in the second line, erase the comma in the last line. For the actual boundary condition.
example, • Starting in line 156, add the following statements,
Original statements

45 fixedValueFvPatchVectorField(p, iF), The actual


46 maxValue_(0.0), 150 void Foam::myParabolicVelocityFvPatchVectorField::updateCoeffs() implementation of
151 { the BC is always
47 data_(Zero),
152 if (updated()) done in this class
48 data_(Zero),
153 {
154 return;
155 } Find patch bounds (minimum
156 boundBox bb(patch().patch().localPoints(), true); and maximum points)

Add these lines


Modified statements 157
158 vector ctr = 0.5*(bb.max() + bb.min()); Coordinates of patch midpoint
45 fixedValueFvPatchVectorField(p, iF), 159
160 const vectorField& c = patch().Cf(); Access patch face centers
46 maxValue_(0.0), 161
47 n_(Zero), 162 scalarField coord = 2*((c - ctr) & y_)/((bb.max() - bb.min()) & y_);
48 y_(Zero) Remember to erase the comma 163
x
x
Computes scalar field to be used for defining the parabolic profile

1034 1035

Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The source file (.C) The source file (.C)


• Add the following statement in line 166, • Before moving forward, let us comment a little bit the source file.
• First at all, there are five classes constructors and each of them have a specific task.
The access function operator== is

164 fixedValueFvPatchVectorField::operator==
used to assign the values to the • In our implementation we do not use all the classes, we only use the first two classes.
boundary patches
165 ( • The first class is related to the initialization of the variables.
166 n_*maxValue_*(1.0 - sqr(coord)) Our boundary condition
167 ); • The second class is related to reading the input dictionaries.
168
• We will not comment on the other classes as it is out of the scope of this example
(they deal with input tables, mapping, and things like that).
• At this point we have a valid library where we implemented a new BC. • The implementation of the boundary condition is always done using the
• Try to compile it, we should not get any error (maybe one warning). Type in the updateCoeffs() member function.
terminal, • When we compile the source code, it will compile a library with the name specified in
the file Make/file. In this case, the name of the library is libmyParabolicVelocity.
1. $> wmake • The library will be located in the directory $(FOAM_USER_LIBBIN), as specified in
the file Make/file.
• If you are feeling lazy or you can not fix the compilation errors, you will find the source
code in the directory,
• $PTOFC/101programming/src/myParabolicVelocity
1036 1037
Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The source file (.C) The source file (.C)


• The first class is related to the initialization of the variables declared in the header file. • The second class is used to read the input dictionary.
• In line 47 we initialize maxValue with the value of zero. The vectors n and y are • Here we are reading the values defined by the user in the dictionary U.
initialized as a zero vector by default or (0, 0, 0). • The function lookup will search the specific keyword in the input file.
• It is not a good idea to initialize these vectors as zero vectors by default. Let us use
as default initialization (1, 0, 0) for vector n and (0,1,0) for vector y.
53 Foam::myParabolicVelocityFvPatchVectorField::
54 myParabolicVelocityFvPatchVectorField
55 (
56 const fvPatch& p,
57 const DimensionedField<vector, volMesh>& iF,
38 Foam::myParabolicVelocityFvPatchVectorField::
58 const dictionary& dict
39 myParabolicVelocityFvPatchVectorField
59 )
40 (
60 :
41 const fvPatch& p,
61 fixedValueFvPatchVectorField(p, iF),
42 const DimensionedField<vector, volMesh>& iF dict.lookup will look for
62 maxValue_(readScalar(dict.lookup("maxValue"))),
43 ) these keywords in the
63 n_(pTraits<vector>(dict.lookup("n"))),
44 : input dictionary
64 y_(pTraits<vector>(dict.lookup("y")))
45 fixedValueFvPatchVectorField(p, iF),
65 {
46 maxValue_(0.0),
66
47 n_(Zero), Change to n_(1,0,0)
67
48 y_(Zero)
68 fixedValueFvPatchVectorField::evaluate();
49 {
50 } Change to y_(0,1,0) 77 }

1038 1039

Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The source file (.C) The source file (.C)


• Since we do not want the vectors n and y to be zero vectors, we add the following • At this point, we are ready to go.
sanity check from lines 67-75. • Save files and recompile. Type in the terminal,
• These statements check if the given n and y vectors in the input dictionary is zero or
not.
1. $> wmake
• If any of the vectors are zero it gives the fatal error and terminate the program.
• On the other hand, if everything is ok it will normalize n and y (since in our
implementation they are direction vectors). • We should not get any error (maybe one warning).

66
• At this point we have a valid library that can be linked with any solver.
Add these statements

67 if (mag(n_) < SMALL || mag(y_) < SMALL)


68 {
• If you get compilation errors read the screen and try to sort it out, the compiler is
69 FatalErrorIn("parabolicVelocityFvPatchVectorField(dict)") always telling you what is the problem.
70 << "n or y given with zero size not correct"
71 << abort(FatalError); • If you are feeling lazy or you can not fix the compilation errors, you will find the source
72 }
73 code in the directory,
74 n_ /= mag(n_); //This is equivalent to n_ = n_/mag(n_)
75 y_ /= mag(y_); //This is equivalent to y_ = y_/(mag(y_)
• $PTOFC/101programming/src/myParabolicVelocity
76
77 fixedValueFvPatchVectorField::evaluate();
78

1040 1041
Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

The source file (.C) Running the case


• Before using the new BC, let us take a look at the logic behind the implementation. • This case is ready to run, the input files are located in the directory
$PTOFC/101programming/src/case_elbow2d
• Go to the case directory,

1. $> cd $PTOFC/101programming/cases/elbow2d

• Open the file 0/U, and look for the definition of the new BC velocity-inlet-5,

velocity-inlet-5
{
type myParabolicVelocity; Name of the boundary condition

maxValue 2.0;
n (1 0 0); User defined values
y (0 1 0); max value, n, y
} If you set n or y to (0 0 0), the solver will
abort execution

1042 1043

Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

Running the case Running the case


• We also need to tell the application that we want to use the library we just compiled. • This case is ready to run, the input files are located in the directory
$PTOFC/101programming/src/case_elbow2d
• To do so, we need to add the new library in the dictionary file controlDict,
• To run the case, type in the terminal,

1. $> foamCleanTutorials
15 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 2. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh
16
17 libs ("libmyParabolicVelocity.so"); Name of the library 3. $> icoFoam | tee log
18 You can add as many libraries as you like
19 application icoFoam; 4. $> paraFoam

• At this point, you can compare the three implementations (codeStream,


codedFixedValue and high level programming).
• All of them will give the same outcome.
• The solver will dynamically link the library.
• At this point, we are ready to launch the simulation.

1044 1045
Implementing boundary conditions using high level programming Implementing boundary conditions using high level programming

Adding some verbosity to the BC implementation Do you take the challenge?


• Let us add some outputs to the BC. • Starting from this boundary condition, try to implement a paraboloid BC.
• Starting at line 181 (after the function updateCoeffs), add the following lines, • If you are feeling lazy or at any point do you get lost, in the directory
$PTOFC/101programming/src/myParaboloid you will find a working
179 fixedValueFvPatchVectorField::updateCoeffs(); implementation of the paraboloid profile.
180
181 Info << endl << "Face centers (c):" << endl;
182 Info << c << endl; • Open the source code and try to understand what we did (pretty much similar to the
183
184
Info << endl << "Patch center (ctr):" << endl;
Info << ctr << endl;
previous case).
185 Info << endl << "Patch (c - ctr):" << endl;
186 Info << c - ctr << endl; • In the directory $PTOFC/101programming/src/case_elbow3d you will find a
187
188
Info << endl << "Patch max bound (bb.max):" << endl;
Info << bb.max() << endl; case ready to use.
189 Info << endl << "Patch min bound (bb.max):" << endl;
190 Info << bb.min() << endl;
191 Info << endl << "Patch coord ( 2*((c - ctr) & y_)/((bb.max() - bb.min()) & y_) ):" << endl;
192 Info << coord << endl;
193 Info << endl << "Patch ( 1.0 - sqr(coord)) :" << endl;
194 Info << n_*maxValue_*(1.0 - sqr(coord))<< endl;
195 Info << endl << "Loop for c, BC assigment << endl;
196 forAll(c, faceI)
197 {
198 Info << c[faceI] << " " << n_*maxValue_*(1.0 - sqr(coord[faceI])) << endl;
199 }
200
201

• Recompile, rerun the simulation, look at the output, and do the math.
1046 1047

Roadmap Modifying applications – Highlights


• Implementing a new application from scratch in OpenFOAM® (or any other
1. Programming in OpenFOAM®. Building blocks. high level programming library), can be an incredible daunting task.
2. codeStream – Highlights • OpenFOAM® comes with many solvers, and as it is today, you do not need
to implement new solvers from scratch.
3. Implementing boundary conditions using • Of course, if your goal is to write a new solver, you will need to deal with
codeStream programming. What you usually do, is take an existing solver and modify it.
4. Solution initialization using codeStream • But in case that you would like to take the road of implementing new
applications from scratch, we are going to give you the basic building blocks.
5. Implementing boundary conditions using high level
programming • We are also going to show how to add basic modifications to existing solvers.
• We want to remind you that this requires some knowledge on C++ and
6. Modifying applications – Highlights OpenFOAM® API library.
7. Implementing an application from scratch • Also, you need to understand the FVM, and be familiar with the basic algebra
8. Adding the scalar transport equation to icoFoam of tensors.
• Some common sense is also helpful.

1048 1049
Roadmap Implementing an application from scratch
• Let us do a little bit of high level programming, this is the hard part of working
1. Programming in OpenFOAM®. Building blocks. with OpenFOAM®.
2. codeStream – Highlights • At this point, you can work in any directory. But we recommend you to work
in your OpenFOAM® user directory, type in the terminal,
3. Implementing boundary conditions using
codeStream 1. $> cd $WM_PROJECT_USER_DIR/run

4. Solution initialization using codeStream • To create the basic structure of a new application, type in the terminal,
5. Implementing boundary conditions using high level
1. $> foamNewApp scratchFoam
programming
2. $> cd scratchFoam
6. Modifying applications – Highlights
7. Implementing an application from scratch • The utility foamNewApp, will create the directory structure and all the files needed to
create the new application from scratch. The name of the application is
8. Adding the scalar transport equation to icoFoam scratchFoam.
• If you want to get more information on how to use foamNewApp, type in the terminal,

1. $> foamNewApp –help


1050 1051

Implementing an application from scratch Implementing an application from scratch


Directory structure of the new boundary condition • Open the file scratchFoam.C using your favorite text editor, we will use gedit.
• At this point you should have this file, this does not do anything. We need to add the
scratchFoam/
statements to create a working applications.
├── createFields.H Does not exist, we will create it later
├── scratchFoam.C • This is the starting point for new applications.
└── Make
This header is extremely important, it will add all the class
├── files 30 declarations needed to access mesh, fields, tensor algebra, fvm/fvc
└── options 31 #include "fvCFD.H" operators, time, parallel communication, linear algebra, and so on.
32
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34
35 int main(int argc, char *argv[])
The scratchFoam directory contains the source code of the solver. 36 {
• scratchFoam.C: contains the starting point to implement the new application. 37 #include "setRootCase.H"
38 #include "createTime.H"
• createFields.H: in this file we declare all the field variables and initializes the solution. 39
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
This file does not exist at this point, we will create it later. 41
42 Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
• The Make directory contains compilation instructions. 43 << " ClockTime = " << runTime.elapsedClockTime() << " s"
• Make/files: names all the source files (.C), it specifies the name of the solver and 44 << nl << endl;
45
location of the output file. 46 Info<< "End\n" << endl;
47
• Make/options: specifies directories to search for include files and libraries to link the 48 return 0;
solver against. 49 }
50
• To compile the new application, we use the command wmake.
1052 1053
Implementing an application from scratch Implementing an application from scratch
• Stating from line 31, add the following statements. • We are going to use the PISO control options, even if we do not have to deal with
• We are going to use the PISO control options, even if we do not have to deal with velocity-pressure coupling.
velocity-pressure coupling.
49 while (runTime.loop()) Time loop
50 {
30 51 Info<< "Time = " << runTime.timeName() << nl << endl;
31 #include "fvCFD.H“ 52
53 #include "CourantNo.H" Calculates and outputs the Courant Number
32 #include "pisoControl.H" Solution control using PISO class 54
33 55 while (piso.correct()) PISO options (correct loop)
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 56 {
35 PISO options (non orthogonal corrections
57 while (piso.correctNonOrthogonal())
36 int main(int argc, char *argv[]) loop)
58 {
37 { 59 fvScalarMatrix Teqn Create object TEqn.
38 #include "setRootCase.H“ Set directory structure fvScalarMatrix is a scalar instance of fvMatrix
60 (
39 #include "createTime.H“ Create time (object runtime) 61 fvm::ddt(T) Model equation (convection-diffusion)
62 + fvm::div(phi, T) We need to create the scalar field T, vector
40 #include "createMesh.H“ Create time (object mesh) 63 - fvm::laplacian(DT, T) field U (used in phi or face fluxes), and the
Initialize fields 64 ); constant DT.
41 #include "createFields.H“
This source file does not exist yet, we need to create it We will declare these variables in the
42 #include "CourantNo.H“ createFields.H header file.
Calculates and outputs the Courant Number
In the dictionary fvSchemes, you will need to
define how to compute the differential
43 #include "initContinuityErrs.H“ Declare and initialize the cumulative continuity error 65
44 operators, that is,
Assign PISO controls to object mesh. Creates object piso. 66 TEqn.solve(); ddt(T)
45 pisoControl piso(mesh); 67 }
Alternatively, you can use the header file createControl.H Solve TEqn div(phi, T)
46 68 }
At this point the object laplacian(DT, T)
47 Info<< "\nStarting time loop\n" << endl; Output some information 69
48 TEqn holds the solution.
1054 1055

Implementing an application from scratch Implementing an application from scratch


• We are going to use the PISO control options, even if we do not have to deal with • Let us create the file createFields.H, type in the terminal,
velocity-pressure coupling.
1. $> touch createFields.H

If you want to compute the CPU time of each iteration,


69
70 #include "continuityErrs.H" Computes continuity errors • Now open the file with your favorite editor, and start to add the following information,
71 add the same statement inside the time loop
Write CPU time at the end of the time loop.

72 runTime.write(); Write the solution in the runtime folder


It will write the data requested in the file createFields.H

73 } At this point we are outside of the time loop 1 Info<< "Reading field T\n" << endl;
74 2
75 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 3 volScalarField T Create scalar field T
76 4 (
77 Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s" 5 IOobject Create object for input/output operations
78 << " ClockTime = " << runTime.elapsedClockTime() << " s" 6 (
79 << nl << endl; 7 "T", Name of the dictionary file to read/write
80 8 runTime.timeName(), runtime directory
81 Info<< "End\n" << endl; Output this message 9 mesh, Object registry
82 10 IOobject::MUST_READ,
11 IOobject::AUTO_WRITE Read the dictionary in the runtime directory
83 return 0; End of the program (exit status). 12 ), (MUST_READ, and write the value in the runtime
84 } If everything went fine, the program should return 0. 13 mesh Link object to mesh directory (AUTO_WRITE).
85 To now the return value, type in the terminal, 14 ); If you do not want to write the value, use the option
86 $> echo $? NO_WRITE

1056 1057
Implementing an application from scratch Implementing an application from scratch
• Remember, in the file createFields.H, we declare all the variables (or fields) that • We also need to declare the constant DT, that is read from the dictionary
we will use (U and T in this case). transportProperties.
• The dimensions of the fields are defined in the input dictionaries, you also have the • The dimensions are defined in the input dictionary.
option to define the dimensions in the source code.
• You can also define the fields directly in the source file scratchFoam.C, but it is 33 Info<< "Reading transportProperties\n" << endl;
34
good practice to do it in the header. This improves code readability. 35 IOdictionary transportProperties Create object transportProperties used to
36 ( read data
37 IOobject
38 ( Name of the input dictionary
17 Info<< "Reading field U\n" << endl; 39 "transportProperties",
40 runTime.constant(), Location of the input dictionary, in this case
18 is located in the directory constant
19 volVectorField U Create vector field U 41 mesh,
20 ( 42 IOobject::MUST_READ_IF_MODIFIED, Re-read data if it is modified
21 IOobject 43 IOobject::NO_WRITE
22 ( 44 ) Do not write anything in the dictionary
23 "U", Name of the dictionary file to read/write 45 );
24 runTime.timeName(), 46
25 mesh, 47
26 IOobject::MUST_READ, 48 Info<< "Reading diffusivity DT\n" << endl;
27 IOobject::AUTO_WRITE 49
28 ), 50 dimensionedScalar DT Create scalar DT (diffusion coefficient)
29 mesh 51 (
52 transportProperties.lookup("DT") Access value of DT in the object
30 );
53 ); transportProperties
31
54
55 #include "createPhi.H" Creates and initializes the relative face-
56 flux field phi.

1058 1059

Implementing an application from scratch Implementing an application from scratch


• At this point, we are ready to compile. Type in the terminal, • Let us now add a little bit more complexity, a non-uniform initialization of the scalar
field T.
1. $> wmake • Remember codeStream? Well, we just need to proceed in a similar way.
• As you will see, initializing directly in the source code of the solver is more intrusive
than using codeStream in the input dicitionaries.
• If everything went fine, you should have a working solver named scratchFoam.
• It also requires recompiling the application.
• If you are feeling lazy or you can not fix the compilation errors, you will find the source
• Add the following statements to the createFields.H file, recompile and run again
code in the directory,
the test case.

• $PTOFC/101programming/applications/solvers/scratchFoam
16
17 forAll(T, i) We add the initialization of T after the its declaration
18 {
19 const scalar x = mesh.C()[i][0];
• You will find a case ready to run in the directory, 20 const scalar y = mesh.C()[i][1]; Access cell center coordinates.
21 const scalar z = mesh.C()[i][2]; In this case y and z coordinates are not used.
22
$PTOFC/101programming/applications/solvers/scratchFoam/test_case 23 if ( 0.3 < x && x < 0.7) Conditional structure
24 {
25 T[i] = 1.;
26 }
• At this point, we are all familiar with the convection-diffusion equation and 27 }
28 T.write(); Write field T. As the file createFields.H is outside the time loop
OpenFOAM®, so you know how to run the case. Do your magic. the value is saved in the time directory 0

1060 1061
Implementing an application from scratch Implementing an application from scratch
• Let us compute a few extra fields. We are going to compute the gradient, divergence, • Let us talk about the file write.H,
and Laplacian of T.
• We are going to compute these fields in a explicit way, that is, after finding the 1
2
volVectorField gradT(fvc::grad(T)); Compute gradient of T.
fvc is the explicit operator, it will compute the
solution of T. 3 volVectorField gradT_vector
requested value using the solution of T
4 (
• Therefore we are going to use the operator fvc. 5 IOobject
6 (
• Add the following statements to the source code of the solver (scratchFoam.C), 7 "gradT",
8 runTime.timeName(), Save vector field in output dictionary gradT
9 mesh,
10 IOobject::NO_READ,
11 IOobject::AUTO_WRITE
68 } 12 ),
13 gradT
69 14 );
70 #include "continuityErrs.H" 15
71 #include "write.H" Add this header file ...
56
72 runTime.write(); 57 volScalarField divGradT
73 The file is located in the directory 58 (
74 } $PTOFC/101programming/applications/solvers/scratchFoam 59 IOobject
60 (
Compute divergence of gradT.
In this file we declare and define the new variables, take a look at it
61 "divGradT", The output of this operation is a scalar field.
62 runTime.timeName(), In this case we compute the quantity inside the scalar field
63 mesh, declaration (line 67).
64 IOobject::NO_READ, We use the fvc operator because the solution of gradT is
already known.
• Recompile the solver and rerun the test case. 65
66 ),
IOobject::AUTO_WRITE

• The solver will complain, try to figure out what is the problem (you are missing some 67
68 );
fvc::div(gradT)
In the dictionary fvSchemes, you will need to tell the solver how to do
information in the fvSchemes dictionary). 69 ... the interpolation of the term div(grad(T))
1062 1063

Roadmap Adding the scalar transport equation to icoFoam


• Let us modify a solver, we will work with icoFoam.
1. Programming in OpenFOAM®. Building blocks. • We will add a passive scalar (convection-diffusion equation).
2. codeStream – Highlights • At this point, you can work in any directory. But we recommend you to work
in your OpenFOAM® user directory, type in the terminal,
3. Implementing boundary conditions using
codeStream $> cd $WM_PROJECT_USER_DIR/run
1.
4. Solution initialization using codeStream
5. Implementing boundary conditions using high level • Let us clone the original solver, type in the terminal,
programming
1. $> cp -r $FOAM_APP/solvers/incompressible/icoFoam/ my_icoFoam
6. Modifying applications – Highlights
2. $> cd my_icoFoam
7. Implementing an application from scratch
8. Adding the scalar transport equation to icoFoam • At this point, we are ready to modify the solver.

1064 1065
Adding the scalar transport equation to icoFoam Adding the scalar transport equation to icoFoam
• Open the file icoFoam.C using your favorite editor and add the new • Open the file createFields.H using your favorite editor and add the following lines
equation in lines 115-120, at the beginning of the file,
1 Info<< "Reading field S1 (passive scalar 1)\n" << endl;
2 volScalarField S1
111 U = HbyA - rAU*fvc::grad(p); 3 (
112 U.correctBoundaryConditions(); 4 IOobject
5 ( Declaration of scalar field S1.
113 } 6 "S1", The solver will read the input file S1
114 7 runTime.timeName(), (BC and IC).
8 mesh,
115 solve 9 IOobject::MUST_READ, You will need to create the file S1 in
116 ( Scalar transport equation. 10 IOobject::AUTO_WRITE the time directory 0.
117 fvm::ddt(S1) The name of the scalar is S1. 11 ),
We need to declare it in the 12 mesh
118 + fvm::div(phi, S1) 13 );
createFields.H file.
119 - fvm::laplacian(DT, S1) . We also need to read the coefficient DT.
14
15 Info<< "Reading diffusionProperties\n" << endl;
120 ); 16
121 17 IOdictionary diffusionProperties
122 runTime.write(); 18 (
19 IOobject Declaration of input/output dictionary
123 20 ( file.
21 "diffusionProperties", The name of the dictionary is
22 runTime.constant(), diffusionProperties and is located in
23 mesh,
24 IOobject::MUST_READ_IF_MODIFIED,
the directory constant.
• As the passive scalar equation depends on the vector field U, we need to 25 IOobject::NO_WRITE
26 )
add this equation after solving U. 27 );
28
29 Info<< "Reading diffusivity DT\n" << endl;
30 dimensionedScalar DT
31 (
Read DT value from the dictionary
32 diffusionProperties.lookup("DT") diffusionProperties.
1066 33 ); 1067

Adding the scalar transport equation to icoFoam Adding the scalar transport equation to icoFoam
• Those are all the modifications we need to do. • At this point we are ready to compile, type in the terminal,
• But before compiling the new solver, we need to modify the compilation
instructions. 1. $> wmake

• Using you favorite editor, open the file Make/files,


• If everything went fine, you should have a working solver named my_icoFoam.
Original file

• If you are feeling lazy or you can not fix the compilation errors, you will find the source
1 icoFoam.C code in the directory,
2
3 EXE = $(FOAM_APPBIN)/icoFoam
• $PTOFC/101programming/applications/solvers/my_icoFoam

Modified file
• You will find a case ready to run in the directory,
Name of the executable.
1 icoFoam.C Name of the input file To avoid conflicts with the original
installation, we give a different $PTOFC/101programming/applications/solvers/my_icoFoam/test_case
2 name to the executable
3 EXE = $(FOAM_USER_APPBIN)/my_icoFoam
Location of the executable.
To avoid conflicts with the original installation, we install the
executable in the user’s personal directory
1068 1069
Adding the scalar transport equation to icoFoam Adding the scalar transport equation to icoFoam
Running the case Running the case
• This case is ready to run, the input files are located in the directory • If everything went fine, you should get something like this
$PTOFC/101programming/applications/solvers/my_icoFoam/test_case
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> fluentMeshToFoam ../../../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh
S1 = 300
3. $> my_icoFoam | tee log
4. $> paraFoam

• Remember, you will need to create the file 0/S1 (boundary conditions and initial
conditions for the new scalar).
S1 = 350
S1 = 400
• You will also need to create the input dictionary constant/diffusionProperties,
from this dictionary we will read the diffusion coefficient value.
S1 inlet values Visualization of velocity magnitude and passive scalar S1
• Finally, remember to update the files system/fvSchemes and www.wolfdynamics.com/wiki/BCIC/2delbow_S1

system/fvSolution to take into account the new equation.


1070 1071

• In this module, we will deal with advanced modeling capabilities.


• We will 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 the
models.

Module 8 “Essentially, all models are wrong,


Advanced physics but some are useful”
Turbulence modeling – Multiphase flows –
Compressible flows – Moving bodies – G. E. P. Box
Source terms – Passive scalars
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”.
1072 1073
Roadmap A crash introduction to turbulence modeling in OpenFOAM®

What is turbulence?
A crash introduction to: • For the purpose of this training, let us state the following:
1. Turbulence modeling in OpenFOAM® • Turbulence is an unsteady, aperiodic motion in which all three velocity
components fluctuate in space and time.
2. Multiphase flows modeling in
• Every transported quantity shows similar fluctuations (pressure,
OpenFOAM® temperature, species, concentration, and so on)
3. Compressible flows in OpenFOAM® • Turbulent flows contains a wide range of eddy sizes (scales):
• Large eddies derives their energy from the mean flow. The size and
4. Moving bodies in OpenFOAM® velocity of large eddies are on the order of the mean flow.
5. Source terms in OpenFOAM® • Large eddies are unstable and they break-up into smaller eddies.
6. Scalar transport pluggable solver • The smallest eddies convert kinetic energy into thermal energy via
viscous dissipation.
• The behavior of small eddies is more universal in nature.

1074 1075

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Wake turbulence behind individual wind turbines


Photo credit: NREL's wind energy research group. Flow visualization over a spinning spheroid
Copyright on the images is held by the contributors. Apart from Fair Use, Photo credit: Y. Kohama.
permission must be sought for any other purpose. Copyright on the images is held by the contributors. Apart from
Fair Use, permission must be sought for any other purpose.

Von Karman vortices created when prevailing winds sweeping east across Flow around an airfoil with a leading-edge slat
the northern Pacific Ocean encountered Alaska's Aleutian Islands Photo credit: S. Makiya et al.
Buoyant plume of smoke rising from a stick of incense Photo credit: USGS EROS Data Center Satellite Systems Branch. Copyright on the images is held by the contributors. Apart from Fair Use,
Photo credit: https://www.flickr.com/photos/jlhopgood/ Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose.
This work is licensed under a Creative Commons License (CC BY-NC-ND 2.0) 1076 permission must be sought for any other purpose. 1077
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Vortices on a 1/48-scale model of an F/A-18 aircraft inside a Water Tunnel Flow around two spheres. Left image: smooth sphere. Right image: sphere with rough surface at the nose
Photo credit: NASA Dryden Flow Visualization Facility. http://www.nasa.gov/centers/armstrong/multimedia/imagegallery/FVF 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. 1078 Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 1079

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter? Turbulence, does it matter?


Blower simulation using sliding grids 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

No turbulence model used (laminar, K-epsilon turbulence model


unresolved DNS, name it as you want) www.wolfdynamics.com/wiki/turb/turb2.gif
www.wolfdynamics.com/wiki/turb/turb1.gif
Laminar (no turbulence model) – Vortices DES (SpalartAllmarasDDES) – Vortices visualized by
visualized by Q-criterion Q-criterion
1080 www.wolfdynamics.com/wiki/squarecil/laminar.gif www.wolfdynamics.com/wiki/squarecil/des.gif 1081
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence, does it matter? Turbulence, does it matter?


Vortex shedding past square cylinder Transitional flow past square cylinder with rounded corners – Re = 54000

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


Turbulence model Drag coefficient Lift coefficient
RANS 2.20 - 28246 (10000 iter) DNS 0.06295 0.07524

LES 0.1146 0.03269


Experimental values 2.05-2.25 0.132 -
URANS (No WF) 0.1107 0.00725
Note: all simulations were run using 4 cores.
Transition K-KL-Omega 0.059 -0.0104
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. Transition K-Omega SST 0.0987 -0.0143
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. Experimental values 0.045 to 0.075 -0.011 to -0.015
1082 1083

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling in engineering Why turbulent flows are challenging?


• The majority of natural and engineering flows are turbulent, hence the • Unsteady aperiodic motion.
necessity of modeling turbulence. • All fluid properties and transported quantities exhibit random spatial and
• The goal of turbulence modeling is to develop equations that predict the time temporal variations.
averaged velocity, pressure, temperature fields without calculating the • They are intrinsically three-dimensional due to vortex stretching.
complete turbulent flow pattern as a function of time.
• Strong dependence from initial conditions.
• There is no universal turbulence model, hence you need to know the
capabilities and limitations of the turbulence models. • Contains a wide range of scales (eddies).

• Simulating turbulent flows in any general CFD solver requires selecting a • Therefore, in order to accurately model/resolve turbulent flows, the
turbulence model, providing initial conditions and boundary conditions for the simulations must be three-dimensional, time-accurate, and with fine enough
closure equations of the turbulent model, selecting a near-wall modeling, meshes such that all spatial scales are resolved.
and choosing runtime parameters and numerics.

1084 1085
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Reynolds number and Rayleigh number Reynolds number and Rayleigh number
• It is well known that the Reynolds number characterizes if the flow is laminar or turbulent. • If you are dealing with natural convection, you can use the Rayleigh number, Grashof number,
• So before doing a simulation or experiment, check if the flow is turbulent. and Prandtl number to characterize the flow.
• The Reynolds number is defined as follows,
Specific heat Thermal expansion coefficient

Buoyancy effects

Convective effects
Viscous effects Thermal conductivity
where
Viscous effects

Momentum diffusivity
• Where U and L are representative velocity and length scales.
Thermal diffusivity

1086 1087

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Reynolds number and Rayleigh number What happens when we increase the Reynolds number?
• Turbulent flow occurs at large Reynolds number.
• For external flows, C reeping flow (no s eparation)
S teady flow Re < 5
Along a surface (slender body) Easy to simulate
A pair of s table vortices

Around an obstacle (bluff body)


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

• For internal flows, Laminar vortex s treet


Relative easy to
(Von Karman s treet)
Uns teady flow
40 - 46 < Re < 150
simulate up to the
point the boundary
Laminar boundary layer up to 150 < Re < 300 layer becomes
the s eparation point, turbulent Trans ition to turbulence
wake turbulent
Uns teady flow 300 < Re < 3 x 10 5
• 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 Boundary layer trans ition to 5 6
number. turbulent 3 x 10 < Re < 3 x 10
Uns teady flow

• If you are dealing with natural convection and buoyancy, turbulent flows occurs when Challenging to
Turbulent vortex s treet, but the
simulate
6
wake is narrower than in the
laminar cas e 3 x 10 > Re
Uns teady flow

Vortex shedding behind a cylinder and Reynolds number


1088 1089
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Vorticity does not always mean turbulence Turbulence modeling – Fluctuations of transported quantities

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 have defined turbulence as an unsteady, aperiodic motion in which velocity components and
• We are in the presence of the Von Karman vortex street, which is the periodic shedding of vortices caused by every transported quantity fluctuate in space and time.
the unsteady separation of the fluid around blunt bodies. • For most engineering application it is impractical to account for all these instantaneous
• Vorticity is not a direct indication of turbulence. fluctuations.
• However turbulent flows are rotational, they exhibit vortical structures. 1090 • Therefore, we need to somehow remove those small scales by using models. 1091

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling – Fluctuations of transported quantities Turbulence modeling – Fluctuations of transported quantities

Laminar flow in a pipe Turbulent flow in a pipe Averaged turbulent flow Instantaneous turbulent flow

• Turbulence has a direct effect on the velocity profiles and mixing of transported quantities. • In the left figure, the velocity profile has been averaged.
• The turbulent case shows two regions. One thin region close to the walls with very large velocity • In reality, the velocity profile fluctuates in time (right figure).
gradients, and a region far from the wall where the velocity profile is nearly uniform. • The thin region close to the walls has very large velocity gradients and is laminar.
• In the illustration, the velocity profile of the turbulent case has been averaged (in reality there are • Far from the flows, the flow becomes turbulent.
fluctuations). 1092 1093
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling – Fluctuations of transported quantities Turbulence modeling – Boundary layer


Note: The scales are
exaggerated for clarity

Boundary layer (Laminar-Transitional-Turbulent flow)


Flow in a pipe. (a) Laminar, (b) Transitional, (c) Turbulent
• In this case, a laminar boundary layer starts to form at the leading edge.
• Turbulence has a direct effect on the velocity profiles and mixing of transported quantities. • As the flow proceeds further downstream, large shear stresses and velocity gradient develop within the
• Case (a) correspond to a laminar flow, where the dye can mix with the main flow only via molecular diffusion, boundary layer. At one point the flow becomes turbulent.
this kind of mixing can take very long times. • The turbulent motion increases the mixing and the boundary layer mixing.
• Case (b) shows a transitional state where the dye streak becomes wavy but the main flow still is laminar. • What is happening in the transition region is not well understood. The flow can become laminar again or can
• Case (c) shows the turbulent state, where the dye streak changes direction erratically, and the dye has mixed become turbulent.
significantly with the main flow due to the velocity fluctuations. 1094 • The velocity profiles in the laminar and turbulent regions are different. 1095

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence near the wall - Law of the wall Turbulence near the wall - Law of the wall
Note: The scales are
exaggerated for clarity

Actual profile - Physical velocity profile


Non-dimensional profile Actual profile - Physical velocity profile

• Near walls, in the boundary layer, the velocity changes rapidly. • Near walls, in the boundary layer, the velocity changes rapidly.
• In CFD, the most important zones are the viscous sublayer and the log-law layer. • The use of the non-dimensional velocity u+ and non-dimensional distance from the wall y+, results in a
• The buffer layer is the transition layer which we try to avoid. predictable boundary layer profile for a wide range of flows
• Turbulence models require different considerations depending on whether you solve the viscous sublayer, • Turbulence models require different considerations depending on whether you solve the viscous sublayer of
model the log-law layer, or solve the whole boundary layer. model the log-law layer.
1096 1097
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence near the wall - Law of the wall Near-wall treatment and wall functions
• When dealing with wall turbulence, we need to
choose a near-wall treatment.
• 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 6 to 10
layers at y+ < 10.
• This is the most accurate approach but it is
computationally expensive.

• When dealing with wall turbulence, we need to


Where y is the distance normal to the wall, U choose a near-wall treatment.
is the shear velocity, and relates the mean
velocity to the shear velocity • If you are not interested in resolving boundary layer
up to the viscous sub-layer, you can use wall
or wall distance units is a very functions.
important concept when dealing • In terms of y+, wall functions will model everything
with turbulence modeling, for y+ < 30
remember this definition as we are • This approach use coarser meshes, but you should
going to use it a lot. be aware of the limitations of the wall functions.

1098 1099

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling – Grid scales Removing small scales (fluctuations)


Steady mean value Unsteady mean value

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 • To remove the instantaneous fluctuations or small scales, two methods can be used:
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.
• Reynolds averaging
• Therefore, if we want to capture all scales we need very fine meshes in the whole domain. • Filtering
• Both methods introduce additional terms that must be modeled for closure.
Bullet at Mach 1.5
Photo credit: Andrew Davidhazy. Rochester Institute of Technology. • We are going to talk about closure methods later.
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose. 1100 1101
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Overview of turbulence modeling approaches Overview of turbulence modeling approaches

MODEL

Increasing modelling and mathematical


RANS

Increasing computational cost


Reynolds-Averaged Navier-Stokes equations RANS LES (Instantaneous field)

URANS
RANS/URANS DES/LES DNS

complexity
Unsteady Reynolds-Averaged Navier-Stokes equations

SAS •

Solve the time-average NSE.
All turbulent spatial scales are


Solve the filtered unsteady NSE.
Sub-grid scales (SGS) are filtered,


Solves the unsteady laminar NSE.
Solves all spatial and temporal
Scale Adaptive Simulations
modeled. grid scales (GS) are resolved. scales; hence, requires extremely
Scale-Resolving Simulations

fine meshes and small time-steps.


DES • Many models are available. One • Aim at resolving the temporal scales,
SRS

equation models, two equation hence requires small time-steps. • No modeling is required.
Detached Eddy Simulations models, Reynolds stress models,
• For most industrial applications, it is • It is extremely computational
transition models, and so on.
LES • This is the most widely approach for
computational expensive. However,
thanks to the current advances in

expensive.
Not practical for industrial flows.
Large Eddy Simulations industrial flows. parallel and scientific computing it is
becoming affordable. • It is intrinsically 3D and asymmetric.
• Unsteady RANS (URANS), use the
DNS same equations as the RANS but
with the transient term retained.
• Many models are available.
Direct Numerical Simulations • It is intrinsically 3D and asymmetric.
1102 • It can be used in 2D and 3D cases. 1103

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Short description of some RANS turbulence models Turbulence modeling – Starting equations
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
NSE
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 Additional closure equations for the turbulence models
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 • Equations cannot be derived from fundamental principles.
under adverse pressure gradient and separation (external aerodynamics and turbomachinery).
• All turbulence models contain some sort of empiricism.
Offers similar benefits as standard k–omega. Not overly sensitive to inlet boundary conditions • Some calibration to observed physical solutions is contained in the turbulence
SST k–omega like the standard k–omega. Provides more accurate prediction of flow separation than other models.
RANS models. Probably the most widely used RANS model.
• Also, some intelligent guessing is used.
1104 • A lot of uncertainty is involved! 1105
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Incompressible RANS equations Incompressible RANS equations


• The RANS equations are similar to the laminar NSE (no turbulence model). • The RANS approach to turbulence modeling requires the Reynolds stresses to be
appropriately modeled.
• The main difference is that all quantities are averaged (the overbar over the field
quantities) and the appearance of a new term named Reynolds stress tensor.

Reynolds stress tensor

• The Reynolds stress tensor can be modeled using the Boussinesq hypothesis,
Reynolds stress models, non-linear eddy viscosity models or algebraic models.

If we retain this term we talk about URANS equations and if we drop it we talk about RANS equations
• The Reynolds stress model (RSM), probably is the most physically sound RANS
model as it derives its own governing equations (six new equations as the tensor is
symmetric).
• To derive the RANS equations we used Reynolds decomposition (and a lot of algebra
is involved), • However, it is much simpler to model the Reynolds stress tensor by means of the
Boussinesq hypothesis, which will be briefly outlined next.
• It is important to know the capabilities and limitations of each model.
1106 1107

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Incompressible RANS equations Incompressible RANS equations


• By using the Boussinesq hypothesis, we can relate the Reynolds stress tensor to the • We just outlined the incompressible RANS.
mean velocity gradient such that,
• The compressible RANS equations are similar, when to derive them we use Favre
average (which can be seen as a mass-weighted averaging), instead of Reynolds
average.
• The idea behind LES/DES models is very similar, but instead of using averaging we
filter the equations in space, and we solve the temporal scales

• In the previous equation, denotes the strain-rate tensor. • LES/DES models are intrinsically unsteady and three-dimensional.

• is the identity matrix. • Let us take a look at the governing equations of the RANS model.

• is the turbulent eddy viscosity. • Remember, the main goal of the RANS turbulence models is to Reynolds stress
tensor and 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.
• And each model will compute this quantity in a different way. 1108 1109
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence model overview Turbulence model free stream initial conditions

• It is called because it solves two additional equations for modeling the • The initial value for the turbulent kinetic energy can be found as follows
turbulence, namely, the turbulent kinetic energy and the specific kinetic energy

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

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


• These are the closure equations of the turbulence problem using Reynolds average.
• If you are totally lost, you can use these reference values. They work most of the
• These are not physical quantities. They kind of represent the generation and times, but it is a good idea to have some experimental data or a better initial estimate.
destruction of turbulence.
Low Medium High
• In the model, the turbulent eddy viscosity can be computed as follows,
I 1.0 % 5.0 % 10.0 %

1 10 100

1110 • By the way, use these guidelines for external aerodynamics only. 1111

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence model boundary conditions at the walls Turbulence model boundary conditions at the walls
• Remember, you can only use wall functions if the primitive patch (the patch
• Follow these guidelines to find the boundary conditions for the near-wall treatment. type defined in the boundary dictionary), is of type wall.
• We highly recommend you to read the source code and find the references used to
implement the model. Field Wall functions – High RE Resolved BL – Low RE

• As for the free-stream boundary conditions, you need to give the boundary conditions nutUSpaldingWallFunction** or
nut(–)WallFunction* or
nut nutLowReWallFunction or
for the near-wall treatment. nutUSpaldingWallFunction**
fixedValue 0 (or a small number)
• When it comes to near-wall treatment, you have three options:
k, q, R kqRWallFunction fixedValue 0 (or a small number)
• Use wall functions:
zeroGradient or fixedValue 0
epsilon epsilonWallFunction
(or a small number)
• Use scalable wall functions, this only applies with the model:
omegaWallFunction** or
omega omegaWallFunction
fixedValue (with a large number)
• Resolve the boundary layer (no wall functions):
nuTilda – fixedValue 0 (or a small number)

* $WM_PROJECT_DIR/src/TurbulenceModels/turbulenceModels/derivedFvPatchFields/wallFunctions/nutWallFunctions
1112 ** For scalable wall functions 1113
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

RANS/URANS Turbulence models available in OpenFOAM® Turbulence models available in OpenFOAM®


• LRR • kEpsilon • As you can see, there is a cornucopia, plethora, fullness, abundance of turbulence models
• LamBremhorstKE • kOmega implemented in OpenFOAM®, from RANS to LES.
• LaunderSharmaKE • kOmegaSST
• You can also implement yours!
• LienCubicKE • kOmegaSSTSAS
• LienLeschziner • kOmegaSSTLM • You can find the turbulence models in the following directories:
• RNGkEpsilon • kkLOmega • $WM_PROJECT_DIR/src/TurbulenceModels
• SSG • qZeta
• The wall functions are in the following directories:
• ShihQuadraticKE • realizableKE
• SpalartAllmaras • v2f
• $WM_PROJECT_DIR/src/TurbulenceModels/turbulenceModels/derivedFvPatc
hFields
• buoyantKEpsilon • laminar (DNS)
• 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.
DES/LES Turbulence models available in OpenFOAM®
• Remember, when a turbulent flow enters a domain, turbulent boundary conditions and initial
• DeardorffDiffStress • WALE conditions must be specified.
• Smagorinsky • dynamicKEqn
• Also, if you are dealing with wall bounded turbulence you will need to choose the near-wall
• SpalartAllmarasDDES • dynamicLagrangian
treatment.
• SpalartAllmarasDES • kEqn
• SpalartAllmarasIDDES • laminar (DNS) • You can choose to solve the viscous sub-layer (low-Re approach) or use wall functions
• kOmegaSSTDES (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 ! 1114 1115

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

wall distance units wall distance units


• To compute the wall distance units , • We never know a priori the value (because we do not know the friction velocity)
you can use the following equation
• What we usually do is to run the simulation for a few time-steps or iterations, and then
we get an estimate of the 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.
• Where is the distance to the first cell • It is an iterative process and it can be very time consuming.
center normal to the wall, and is
the friction velocity and is equal to • Have in mind that it is quite difficult to get a uniform value at the walls.
• Usually, try to get a mean value as close as possible to your target.
• Also check that you do not get very high maximum values of (more than a 1000)
• Use common sense when accessing value.

where is the wall shear stresses.

1116 1117
A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Estimating normal wall distance Wall distance units and some rough estimates
• To get an initial estimate of the distance from the wall to the first cell center ,
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.
• Similar to , the wall distance units can be computed in the stream-wise ( ) and span-
wise ( ) directions.
4.
• 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.
You desired value
5. • Typical requirements for LES are:

1118 1119

A crash introduction to turbulence modeling in OpenFOAM® A crash introduction to turbulence modeling in OpenFOAM®

Turbulence modeling guidelines and tips Turbulence modeling guidelines and tips
• Compute Reynolds number and determine whether the flow is turbulent. • Set reasonable boundary and initial conditions for the turbulence model variables.
• Try to avoid the use of turbulent models with laminar flows. • Always monitor the turbulent variables, some of them are positive bounded.
• Choose the near-wall treatment and estimate before generating the mesh. • Avoid strong oscillations of the turbulent variables.
• Run the simulation for a few time steps and get a better prediction of and • If you are doing LES, remember that these models are intrinsically 3D and unsteady.
correct your initial prediction of . You should choose your time-step in such a way to get a CFL of less than 1 and
• The realizable or models are good choices for general preferably of about 0.5.
applications. • If you are doing RANS, it is perfectly fine to use upwind to discretize the turbulence
• The standard model is very reliable, you can use it to get initial values. closure equations. After all, turbulence is a dissipative process. However, some
authors may disagree with this, make your own conclusions.
• If you are interested in resolving the large eddies and modeling the smallest eddies,
DES or LES are the right choice. • If you are doing unsteady simulations, always remember to compute the average
values (ensemble average).
• If you do not have any restriction in the near wall treatment method, use wall
functions (even with LES/DES models). • If you are dealing with external aerodynamics and detached flows, DES simulations
are really affordable.
• Be aware of the limitations of the turbulence model chosen, find and read the original
references used to implement the model in OpenFOAM®. • The work-horse of turbulence modeling in CFD: RANS

1120 1121
A crash introduction to turbulence modeling in OpenFOAM® Turbulence hands-on tutorials
References
• Turbulent Flows
Stephen B. Pope • Vortex shedding past square cylinder
• Turbulence Modeling for CFD
David C. Wilcox • Let us run this case. Go to the directory:
• Turbulence: An Introduction for Scientists and Engineers
P. A. Davidson
• Large Eddy Simulation for Incompressible Flows $PTOFC/advanced_physics/turbulence/squarecil
Pierre Sagaut
• A First Course in Turbulence
H. Tennekes and J. L. Lumley
• Boundary-Layer Theory
• From this point on, please follow me.
H. Schlichting
• https://turbmodels.larc.nasa.gov/ • We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
1122 1123

Turbulence hands-on tutorials Turbulence hands-on tutorials


Vortex shedding past square cylinder Vortex shedding past square cylinder

Turbulence model Drag coefficient Strouhal number Computing time (s)


Physical and numerical side of the
Laminar 2.81 0.179 93489
problem:
• The governing equations of the problem are the LES 2.36 0.124 77465
incompressible Navier-Stokes equations.
• To model the turbulence, we will use two approaches, DES 2.08 0.124 70754
LES and RANS.
SAS 2.40 0.164 57690
• We are going to work in a 3D domain with periodic
boundary conditions.
URANS (WF) 2.31 0.130 67830
• This problem has plenty of experimental data for
validation. 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.
Working fluid: Water 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.
1124 1125
Turbulence hands-on tutorials Turbulence hands-on tutorials
Vortex shedding past square cylinder Vortex shedding past square cylinder
• We select the turbulence model in the turbulenceProperties dictionary file.
• We will use this case to learn how to setup a turbulent case (RANS and
LES). • This dictionary file is located in the directory constant.
• To select the K-Omega SST turbulence model,
• To run this case we will use the solvers simpleFoam (steady solver) and
pimpleFoam (unsteady solver).
17 simulationType RAS; RANS type simulation
• To get fast outcomes, we will use a coarse mesh. But feel free to refine the 18
mesh, specially close to the walls. 19
20
RAS
{
RANS sub-dictionary

RANS model to use


• After finding the solution, we will visualize the results. 21 RASModel kOmegaSST;

22 turbulence on; Turn on/off turbulence. Runtime modifiable


• We will also compare the numerical solution with the experimental results.
23 printCoeffs on; Print coefficients at the beginning
• At the end, we will do some plotting and advanced post-processing using 24 }
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 • Remember, you need to assign boundary and initial conditions to the new variables (k, omega,
README.FIRST located in the case directory. and nut).

1126 1127

Turbulence hands-on tutorials Turbulence hands-on tutorials


Vortex shedding past square cylinder Vortex shedding past square cylinder
• We select the turbulence model in the turbulenceProperties dictionary file. • To select wall functions, follow this table,
• This dictionary file is located in the directory constant.
• To select the LES (Smagorinsky) turbulence model,
Field Wall functions – High RE Resolved BL – Low RE

17 simulationType LES; LES type simulation


18 nut nutUSpaldingWallFunction fixedValue 0 or a small number
19 LES LES sub-dictionary
20 {
21 LESModel Smagorinsky; LES model to use k kqRWallFunction fixedValue 0 or a small number

24 turbulence on; Turn on/off turbulence. Runtime modifiable


omega omegaWallFunction omegaWallFunction
25 printCoeffs on; Print coefficients at the beginning

27 delta cubeRootVol;
31 cubeRootVolCoeffs
32 {
LES filter • In this tutorial,
33 deltaCoeff 1; • Use High RE for RANS.
34 }
100 } • Use High RE and Low RE for URANS.
• Use High RE and Low RE for LES.
• Remember, you need to assign boundary and initial conditions to the new variables (nut).
1128 1129
Turbulence hands-on tutorials Turbulence hands-on tutorials
Vortex shedding past square cylinder Vortex shedding past square cylinder
• The initial value for the turbulent kinetic energy can be found as follows, • At this point, we are ready to run the simulation.
• To run the tutorial using simpleFoam (RANS simulation), type in the terminal:
1. $> foamCleanTutorials
2. $> blockMesh
• The initial value for the specific kinetic energy can be found as follows,
3. $> checkMesh
4. $> rm -r 0
5. $> cp -r 0_org 0
• Use the following initial estimates, and 6. $> decomposePar
7. $> mpirun -np 4 renumberMesh -overwrite -parallel
• At this point, we are ready to run. But before running, remember to setup the right 8. $> mpirun -np 4 simpleFoam -parallel | tee log
numerics in the dictionary files fvSolution and fvSchemes.
9. $> mpirun -np 4 simpleFoam –postProcess –func Q -parallel
• Also, for the LES simulation try to keep the CFL number below 0.9
10. $> mpirun -np 4 simpleFoam –postProcess –func yPlus -parallel
• Finally, do not forget to setup the functionObjects to compute the forces, do the $> reconstructPar
11.
sampling, and compute y+ on-the-fly.
1130 12. $> paraFoam 1131

Turbulence hands-on tutorials Turbulence hands-on tutorials


Vortex shedding past square cylinder Vortex shedding past square cylinder
• In step 1, we clean the case directory. This is not compulsory, but it is highly • To run the tutorial using pimpleFoam (LES simulation), type in the terminal:
advisable.
1. $> foamCleanTutorials
• In steps 2-3 we generate the mesh and check its quality.
• In steps 4-5, we transfer the backup or original files to the directory 0. It is highly 2. $> blockMesh
advisable to always keep backup files. 3. $> checkMesh
• In step 6 we decompose the mesh. At this point we are preparing to run in parallel. 4. $> rm -r 0
• In step 7 we use renumberMesh to reduce the bandwidth of the coefficient matrices. 5. $> cp -r 0_org 0
• In step 8 we run in parallel and save the standard output in the file log. 6. $> refineWallLayer '(square)' 0.7 -overwrite
• In step 9 we compute the Q-criterion using the utility postProcess.
7. $> refineWallLayer '(square)’ 0.5 -overwrite
• In step 10 we compute the yPlus using the utility postProcess.
8. $> refineWallLayer '(square)’ 0.3 -overwrite
• In step 11 we reconstruct the solution.
$> mapFields ../RANS -consistent -noFunctionObjects
• In step 12 we use paraFoam to visualize the solution. 9.
-mapMethod cellPointInterpolate -sourceTime latestTime

1132 1133
Turbulence hands-on tutorials Turbulence hands-on tutorials
Vortex shedding past square cylinder Vortex shedding past square cylinder
• To run the tutorial using pimpleFoam (LES simulation), type in the terminal: • In step 1, we clean the case directory. This is not compulsory, but it is highly advisable.
• In steps 2 and 3 we generate the mesh and check its quality.
10. $> decomposePar
• In steps 4-5, we transfer the backup or original files to the directory 0. It is highly advisable to
11. $> mpirun -np 4 renumberMesh -overwrite -parallel always keep backup files.

$> mpirun -np 4 pimpleFoam -parallel > log | tail -f log • In steps 6-8, we use the utility refineWallLayer to refine the mesh close to the walls (square
12.
in this case). This is helpful if you do not want to regenerate the mesh.
13. $> mpirun -np 4 pimpleFoam –postProcess –func Q -parallel
• In step 9, we interpolate the solution obtained using a RANS method on a coarse mesh, into the
14. $> mpirun -np 4 pimpleFoam –postProcess –func yPlus -parallel current finer mesh (the mesh was refined in steps 6-8).

15. $> reconstructPar • In step 10 we decompose the mesh. At this point we are preparing to run in parallel.
• In step 11 we use renumberMesh to reduce the bandwidth of the coefficient matrices.
16. $> paraFoam
• In step 12 we run in parallel and save the standard output in the file log.
• In step 13 we compute the Q-criterion using the utility postProcess.
• In step 14 we compute the yPlus using the utility postProcess.
• In step 15 we reconstruct the solution.
• In step 16 we use paraFoam to visualize the solution.

1134 1135

Turbulence hands-on tutorials Turbulence hands-on tutorials


Laminar-Turbulent flat plate

• Laminar-Turbulent flat plate


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

$PTOFC/advanced_physics/turbulence/flatPlate

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you • 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.
unpacked the tutorials.
• By plotting the velocity in terms of the non-dimensional variables u+ and y+, we can compare
1136
the profiles obtained from the simulations with the theoretical profiles. 1137
Turbulence hands-on tutorials Turbulence hands-on tutorials
Laminar-Turbulent flat plate Laminar-Turbulent flat plate
• In the directory python of each case, you will find a jupyter notebook (a python • We are going to use the following solver: simpleFoam (for RANS).
script), that you can use to plot the non-dimensional u+ and y+ profiles. • This case is rather simple but we will use it to explain many features used in
• The notebook uses some precomputed results, but you can adjust it to any case. OpenFOAM® when dealing with turbulence, especially when dealing with near the
• Remember, the u+ vs. y+ plot is kind of a universal plot. wall treatment.

• It does not matter your geometry or flow conditions, if you are resolving well the • We will also show you how to do the post-processing in order to reproduce the law of
turbulent flow, you should be able to recover this profile. the wall. For this, we will use a jupyter notebook (a python script).

• To compute this plot, you must sample the wall shear stresses. • Remember, as we are introducing new closure equations for the turbulence problem,
we need to define initial and boundary conditions for the new variables.
• Then, you can compute the shear velocity, friction coefficient, and u+ and y+ values.
• 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.

1138 1139

Roadmap A crash Introduction to multiphase flows modeling OpenFOAM®

What is a multiphase flow?


A crash introduction to: • A multiphase flow is a fluid flow consisting of more than one
1. Turbulence modeling in OpenFOAM® phase component and have some level of phase separation
above molecular level.
2. Multiphase flows modeling in
• Multiphase flows exist in many different forms.
OpenFOAM®
• Two phase flows can be classified according to the state of the
3. Compressible flows in OpenFOAM® different phases:
4. Moving bodies in OpenFOAM® • Gas-Liquid mixture.
5. Source terms in OpenFOAM® • Gas-Solid mixture.
6. Scalar transport pluggable solver • Liquid-Solid mixture.
• Immiscible liquid-liquid.

1140 1141
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Multiphase flows in industry and nature Multiphase flows in industry and nature
• Multiphase flows are very common in industry and in nature, the following • Multiphase flows are very common in industry and in nature, the following
are a few examples depending on the state of the different phase. are a few examples depending on the state of the different phase.

• Gas–particle flows: • Gas–liquid flows:


• Natural: sand storms, volcanoes, avalanches, rain droplets, mist • Natural: ocean waves.
formation. • Biological: blood flow, eyes, lungs.
• Biological: aerosols, dust particles, smoke (finely soot particles), • Industrial: boiling water and pressurized water nuclear reactors,
• Industrial: pneumatic conveyers, dust collectors, fluidized beds, solid chemical reactor, desalination systems, sewage treatment plants,
propellant rockets, pulverized solid particles, spray drying, spray casting. boilers, heat exchangers, internal combustion engines, liquid propellant
rockets, fire sprinkler suppression systems.
• Liquid–solid flows:
• Natural: sediment transport of sand in rivers and sea, soil erosion, mud • Liquid–liquid flows:
slides, debris flows, iceberg formation. • Industrial: emulsifiers, fuel-cell systems, micro-channel applications,
• Biological: blood flow, eyes, lungs. extraction systems.
• Industrial: slurry transportation, flotation, fluidized beds, water jet cutting,
sewage treatment plants, bio-reactors. • Gas–liquid–solid flows:
1142
• Industrial: air lift pumps, fluidized beds, oil transportation 1143

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Examples of multiphase flows Examples of multiphase flows

Municipal and industrial water treatment Cargo ship wake Cooling Towers Volcano eruption
https://whatiswatertreatment.wordpress.com/what-are-the-systems-associated-with-water-
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/ http://americanpreppersnetwork.com/2014/08/preparing-volcano-eruption.html
treatment-and-how-are-they-treated/103-2/
Chem-2010-Intex-Shanghai

Propeller cavitation Coastal structures – Waves interaction.


http://www.veempropellers.com/features/cavitationresistance http://californiabeachblog.blogspot.it/2013_10_01_archive.html
Siltation & Sedimentation Fermentation of beer and spirits
http://blackwarriorriver.org/siltation-sedimentation/
http://www.distillingliquor.com/2015/02/05/how-to-make-alcohol-and-spirits/

1144 1145
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Classifying multiphase flows according to phase morphology Why simulating multiphase flows is challenging?
• Simulating multiphase flows is not an easy task.
• Disperse system: the phase is dispersed as non-contiguous isolated
regions within the other phase (the continuous phase) . When we work with a • The complex nature of multiphase flows is due to:
disperse phase we say that the system is dispersed: disperse-continuous • More than one working fluid.
flow. • The transient nature of the flows.
• Separated system: the phase is contiguous throughout the domain and • The existence of dynamically changing interfaces.
there is one well defined interphase with the other phase. When we work • Significant discontinuities (fluid properties and fluid separation).
with continuous phases we say that the system is separated: continuous-
• Complicated flow field near the interface.
continuous flow.
• 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,
Dispersed system Separated system
frictional stresses, collisions, kinetic theory, and so on).
1146 1147

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Overview/remarks on modeling approaches How to treat the wide range of behaviors in


Free surface
(system scale)
multiphase flows
Increase
• Multiphase flows are inherently multi-scale
in nature.
• Fully resolved: solves complete
physics. All spatial and temporal scales

Modeling requirements
• It is necessary to account for the cascade
are resolved.

Computational power
effect of the various flow physics at
different scales: Large bubbles
(system scale) • Eulerian-Lagrangian: solves idealized
• Large flow structures within the fluid Medium bubbles isolated particles that are transported
flow (system-scale). (system-scales)
with the flow. One- or two-way coupling
• Local structural changes due to is possible. Can account for turbulence,
coalescence and breakage processes momentum transfer, and mass transfer.
(meso-scales). Small bubbles interaction
(meso-scales) • Eulerian-eulerian: solves two or more
• Motion and interaction of discrete
constituents or small particles (micro-
co-existing fluids. The system can be
scale). dispersed or separated, and can account
Bubble break-up
And coalescence
for turbulence, momentum transfer, and Increase
(meso-scales) Small sized particles
(micro-scales)
mass transfer.
MPF-1148 1148 1149
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in How to treat the wide range of behaviors in
multiphase flows Free surface multiphase flows Bubbles larger than cell size

Cell size

Separated system Dispersed system

Eulerian-Eulerian approach
Eulerian-Eulerian approach Eulerian-Lagragian approach
(Multi-fluid and mixture
(VOF) (Particle tracking)
models)

• Applicability of the VOF method to separated systems (non-interpenetrating continua).


• In the illustrations, the free surface and bubbles are track/resolve by the mesh.
1150 • The smaller the features we want to track/resolve, the smaller the cells should be. 1151

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in How to treat the wide range of behaviors in
multiphase flows
Not ok. Only one cell to resolve the bubble. multiphase flows

VOF ≈ 0.5

Average phase
properties

• Bubbles, droplets and/or particles • Bubbles, droplets and/or particles


bigger than grid scales (GS), can be smaller than grid scales (sub-grid scales • Dispersed phase in a continuous phase.
resolved using VOF. or SGS), can not be resolve using the • In this case, the VOF method is not able to handle bubbles smaller than grid scales.
• To resolve a bubble you will need at VOF method. • Multi-fluid and mixture models are able to model bubbles smaller than grid scales by averaging the phase
least two cells in every direction • We need to use models. 1152 properties in the discrete domain. 1153
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in How to treat the wide range of behaviors in
multiphase flows 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.
• Multi-fluid and mixture approaches can model bubble coalescence, bubble break-up
and wake entrainment in dispersed systems 1154 1155

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

How to treat the wide range of behaviors in Numerical approaches for multiphase flows
multiphase flows
Eulerian-Eulerian Eulerian-Eulerian
Eulerian-Lagrangian
(VOF) (Dispersed systems)
The particles position is
tracked by solving an ODE
for each particle
The continuous phase is • Non-interpenetrating • Interpenetrating continua. • Continuous phase:
solve in the mesh continua. Eulerian.
• Continuous phase:
• Continuous phases: Eulerian. • Dispersed phase:
Eulerian. Lagrangian.
• Dispersed phase: Eulerian.
• Fluid properties are written • Phase-weighted averages. • Solves ODEs for particle
on either side of the tracking (for every single
interface (no averaging). • Solves PDEs for all phases particle).
• In the Eulerian-Lagrangian framework, the continuous phase is solved in an Eulerian reference (including interphase
system and the particles or dispersed phase is solved in a Lagrangian reference system. • Solves one single set of transfer terms): mass, • Solves a set of PDEs for
PDEs: mass, momentum, momentum, energy. the continuous phase:
• The particles can be smaller or larger than the grid size.
energy. mass, momentum, energy.
• The particles can be transported passively or they can be coupled with the fluid governing • It can deal with gas-liquid,
equations. • Phase interaction terms
gas-solid, and liquid-solid
(including interphase
• It accounts for particle interaction and mass transfer. interactions.
transfer terms).
• The particles can interact with the boundaries and have a fate. 1156 1157
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows Numerical approaches for multiphase flows

www.wolfdynamics.com/training/mphase/image10.gif http://www.wolfdynamics.com/training/mphase/image16.gif

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
• Simulations showing free surface tracking using the VOF approach
entrainment using the VOF method.
• The left image corresponds to a simulation with rigid body motion and accurate surface tracking using the VOF
• In this simulation the free surface and bubbles are capture by using AMR. However, the smallest bubble that
method.
can be resolved is at the smallest grid size. 1158 1159

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows Numerical approaches for multiphase flows

twoPhaseEulerFoam twoPhaseEulerFoam
http://www.wolfdynamics.com/training/mphase/image18.gif
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 simulation (gas-liquid).


• The bubbles are not being solved, instead, the interaction between phase is being averaged.
• Eulerian-Eulerian simulations using the Eulerian-Granular KTGF approach (solid-gas).
• The granular phase is simulated as continuous phase.
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. • In these simulations we can observe the influence of turbulence modeling in the solution.
Chemical Engineering Science 57 (2002) 4715 – 4736 1160 1161
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Numerical approaches for multiphase flows 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 …

DPMFoam twoPhaseEulerFoam
Particle-particle interactions colored by velocity Air volume fraction
Phase transport equation and interface
magnitude (particles not to scale) Turbulent case tracking with surface compression
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).


Volume fraction (bounded quantity)
• 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
• You can see the volume fraction as a pointer that indicates what phase (with the
Eulerian-Lagrangian simulation. 1162 corresponding physical properties), is inside each cell of the computational domain.1163

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Volume-of-Fluid (VOF) governing equations for separated systems Eulerian-Eulerian governing equations for dispersed systems
• The Eulerian-Eulerian approach solves the governing equations for each phase, it
• For example, in the case of two phases treats the phases as interpenetrating continua.
where phase 1 is represented by and
0 0 0 0.1 0.3 • The incompressible, isothermal governing equations with interface tracking can be
phase 2 is represented by ; a volume
written as follows,
fraction value of 1 indicates that the cell is fill 0 0 0.3 0.8 1 Surface tension - Continuum surface force (CSF)
with phase 1; a volume fraction of 0.8
indicates that the cell contains 80% of a 0 0.1 0.8 1 1 Interface forces or momentum transfer.
Bubbles interaction models
phase 1; and a volume fraction of 0, indicates
that the cell is fill with phase 2. 0 0.4 1 1 1
• The values between 0 and 1 can be seen as
Interface
the interface between the phases.

• The fluid properties can be written on either side of the interface as follows,
Source terms:
• Porous media
• Coriolis forces
• Centrifugal forces
• Mass transfer
• and so on …

1164 1165
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Eulerian-Lagrangian governing equations On the multiphase flows models


• 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. • In OpenFOAM®, there are many interfacial momentum transfer
• The particles can be transported passively, or they can be coupled with the fluid models implemented.
governing equations (they can modify the fluid field).
• There are also many models for Eulerian-Lagrangian methods.
• The particles can interact with the boundaries, they can escape, bounce, stick, or
form a wall film. • No need to say that turbulence also applies to multiphase flows.
• This formulation accounts for particle interaction and mass transfer.
• The governing equations can be written as follows, • We want to remind you that 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.
• Remember, you have the source code so feel free to explore it.
Any of the Eulerian formulations (single or multi-phase)
1166 1167

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Multiphase solvers in OpenFOAM® Multiphase solvers in OpenFOAM®


• OpenFOAM® comes with many solvers and models that can address a wide physics. • These are the multiphase solvers that you will use most of the time in
• When dealing with multiphase flows in OpenFOAM®, you can use VOF, Eulerian- OpenFOAM®.
Eulerian, Eulerian-Eulerian with VOF, and Eulerian-Lagrangian methods.
• The solution methods can account for turbulence models, interface momentum • The VOF approach:
transfer models, mass transfer models, particle interaction models and so on.
• interFoam family solvers
• It is also possible to add source terms, deal with moving bodies or use adaptive mesh
refinement.
• The Eulerian-Eulerian approach:
• twoPhaseEulerFoam, multiphaseEulerFoam
• You will find the source code of all the multiphase solvers in the directory:
• OpenFOAM-5.x/applications/solvers/multiphase
• The Eulerian-Granular KTGF (kinetic theory of granular flows) approach.
• twoPhaseEulerFoam
• You will find the source code all the particle tracking solvers in the directory:
• OpenFOAM-5.x/applications/solvers/lagrangian • The Eulerian-Lagrangian framework,
• DPMFoam, MPPICFoam
1168 1169
A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Multiphase solvers in OpenFOAM® Selecting physical properties and advanced physics


• In the directory constant you will find the dictionaries used to select physical
• Remember, you should always conduct production runs using a second properties and advanced physics.
order discretization scheme.
• The following dictionaries are compulsory:
• Most of multiphase flows are transient, so you need to use transient
methods. • g: in this dictionary you set the gravity field.

• You also need to add new entries in the dictionaries fvScheme and • transportProperties: in this dictionary you set the transport properties for
fvSolution. each phase.

• The new entries, correspond to the new terms and equations used by the • turbulenceProperties: in this dictionary you set the turbulence model.
solver. • The dictionary transportProperties requires special attention, as it is in this
• You also need to set the initial and boundary conditions and assign the dictionary where we set the transport properties for each phase.
physical properties. • We also give a name to the phases in the dictionary transportProperties.
• Hereafter we will only address how to select physical properties for the VOF • These dictionaries are standard for the VOF solvers (interFoam and so on).
method. However, the procedure is similar for other solvers.
• If you are using a different solver (e.g., twoPhaseEulerFoam), you will need to use
• In the training material, you will find many tutorials addressing the different additional dictionaries where you define the interfacial models and so on.
approaches.
1170 1171

A crash Introduction to multiphase flows modeling OpenFOAM® A crash Introduction to multiphase flows modeling OpenFOAM®

Selecting physical properties and advanced physics Selecting physical properties and advanced physics
• If you are using the solver interFoam, the transportProperties • In the directory 0 you will find the dictionaries used to define the boundary
dictionary should looks like this one: conditions and initial conditions of all field variables (including the volume
The first phase is always considered the primary phase
fraction)
Phases naming convention.
The name of the phases is chosen by phases (phase1 phase2);
the user.

phase1 properties phase1 • When you create the dictionaries for the boundary conditions and initials
{ conditions for the volume fraction (or alpha), you use the same naming
transportModel Newtonian; convention as in the dictionary transportProperties.
nu nu [ 0 2 -1 0 0 0 0 ] 1e-06;
rho rho [ 1 -3 0 0 0 0 0 ] 1000;
}
• That is to say, if you are naming you primary phase phase1, you should
phase2 properties phase2
{ create the dictionary alpha.phase1.
transportModel Newtonian;
nu nu [ 0 2 -1 0 0 0 0 ] 1.48e-05;
rho rho [ 1 -3 0 0 0 0 0 ] 1;
}
• This dictionary will contain the initial and boundary conditions of the volume
fraction
Surface tension between phase1
and phase2
sigma sigma [ 1 0 -2 0 0 0 0 ] 0.07;

1172 1173
A crash Introduction to multiphase flows modeling OpenFOAM® Multiphase flows hands-on tutorials
Some useful bibliographical references
• Computational Techniques for Multiphase Flows


G. H. Yeoh, J. Tu. 2009, Butterworth-Heinemann
Multiphase Flow Analysis Using Population Balance Modeling: Bubbles, Drops and Particles
• Free surface – Ship resistance simulation

G. H. Yeoh, C. P Cheung, J. Tu. 2013, Butterworth-Heinemann
Turbulence Modeling for CFD
• Let us run this case. Go to the directory:
D. Wilcox. 2006, DCW Industries.
• Error analysis and estimation in the Finite Volume method with applications to fluid flows.
H. Jasak. PhD Thesis. 1996. Imperial College, London.
$PTOFC/advanced_physics/multiphase/wigleyHull
• Computational fluid dynamics of dispersed two-phase flows at high phase fractions
H. Rusche. PhD Thesis. 2002. Imperial College, London.
• Towards the numerical simulation of multi-scale two-phase flows
H. Marschall. PhD Thesis. 2011. Technische Universität München.
• Derivation, Implementation, and Validation of Computer Simulation Models for Gas-Solid Fluidized
Bed • From this point on, please follow me.
B. van Wachem. PhD Thesis. 2000, TUDelft.
• Gas-Particle flow in a vertical pipe with particle-particle intractions • We are all going to work at the same pace.
J. L. Sinclair, R. Jackson AIChE Journal. Volume 35, Issue 9, 1473-1486, September 1989
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
1174 1175

Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials


Free surface – Ship resistance simulation Free surface – Ship resistance simulation

Comparison of water level on hull surface Drag coefficient monitor

Free surface colored by height


http://www.wolfdynamics.com/training/mphase/image45.gif 1176 1177
Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation Free surface – Ship resistance simulation

• We are going to use the following solver: interFoam • The next step is to set the boundary conditions and initial conditions.
• The first step is to set the physical properties. • In the dictionary constant/transportProperties we defined the phases water
• Go to the directory constant and open the dictionary transportProperties. and air, where water is the primary phase.
• Therefore, in the directory 0 we define the dictionary alpha.water that will take
The first phase is always considered the primary phase
the values of the phase water.
Phases naming convention.
The name of the phases is chosen by phases (water air);
• In this case, you will find the directory 0_org, here is where we keep a backup of the
the user.
original files as we are doing field initialization using setFields.
water properties water
{ • In the directory 0, you will find the dictionary p_rgh, in this dictionary we set the
transportModel Newtonian;
nu nu [ 0 2 -1 0 0 0 0 ] 1.09e-06; boundary and initial conditions for the pressure field, and the dimensions are in
rho rho [ 1 -3 0 0 0 0 0 ] 998.8; Pascals.
}
• The turbulence variables values were calculated using an eddy viscosity ratio equal
air properties air
{ to 1, turbulence intensity equal 5%, and the water properties.
transportModel Newtonian;
nu nu [ 0 2 -1 0 0 0 0 ] 1.48e-05; • If you are simulating numerical towing tanks, the setup of the boundary conditions is
rho rho [ 1 -3 0 0 0 0 0 ] 1; always the same.
}
• Feel free to reuse this setup.
Surface tension between phase1 sigma sigma [ 1 0 -2 0 0 0 0 ] 0.07;
and phase2

1178 1179

Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials


Free surface – Ship resistance simulation Free surface – Ship resistance simulation
Opening
Air phase Wall Patch name Pressure Velocity Turbulence fields alpha.water

fixedValue
inflow fixedFluxPressure fixedValue fixedValue
calculated (nut)
Inlet outlet
inletOutlet
outflow inletOutlet outletPhaseMeanVelocity variableHeightFlowRate
calculated (nut)

Water phase Slip bottom symmetry symmetry symmetry symmetry

midplane symmetry symmetry symmetry symmetry

side symmetry symmetry symmetry symmetry

Note:
inletOutlet
Phases must be initialized top totalPressure pressureInletOutletVelocity
calculated (nut)
inletOutlet
on the internal cells and
boundary faces kqRWallFunction (k)
ship fixedFluxPressure fixedValue omegaFunction (omega) zeroGradient
nutkWallFunction (nut)
Symmetry
Physical domain and boundary patches 1180 Typical setup of boundary conditions for numerical towing tank simulations 1181
Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation Free surface – Ship resistance simulation

• OpenFOAM® solves the following modified volume fraction convective • MULES options in the fvSolution dictionary.
equation to track the interface between the phases, • 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.

(phi, alpha) (phirb, alpha) nAlphaCorr 3; Number of corrections.


Use a TVD scheme with gradient limiters. Use a high order scheme. The use of linear Use 2-3 for slowly varying flows.
Good choice is the vanLeer scheme. interpolation is fine for this term. Use 3 or more for highly transient, high Reynolds,
high CFL number flows.

nLimiterIter 10; Number of iterations to calculate the MULES


• Where a value of (cAlpha), is recommended to accurately resolve limiter. Use 3-5 if CFL number is less than 3. Use
the sharp interface. 5-10 if CFL number is more than 3.

• To solve this equation, OpenFOAM® uses the semi-implicit MULES method. alphaApplyPrevCorr yes; Use previous time corrector as initial estimate.
… Set to yes for slowly varying flows. Set to no for
highly transient flows.
• The MULES options can be controlled in the fvSolution dictionary. 1182
} 1183

Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials


Free surface – Ship resistance simulation Free surface – Ship resistance simulation

• Additional notes on the fvSolution dictionary. • 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
Set to yes for high Reynolds flows, where
momentumPredictor yes; convection dominates governing equations.
Recommended value is 1 (equivalent to PISO). • Convective terms discretization is set as follows:
nOuterCorrectors 1; Increase to improve the stability of second
order time discretization schemes (LES
simulations).
divSchemes
These terms are related to the

Increase for highly coupled problems.


Recommended to use at least 2 correctors. {
volume fraction equation

nCorrector 3; It improves accuracy and stability. div(rhoPhi,U) Gauss linearUpwind grad(U);


Recommend to use at least 1 corrector. div(phi,alpha) Gauss vanLeer;
nNonOrthogonalCorrectors 2;
Increase the value for bad quality meshes. div(phirb,alpha) Gauss linear;
div((muEff*dev(T(grad(U))))) Gauss linear;
}

• 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. • Notice that we are using a high resolution scheme for the surface tracking or
1184
div(phi,alpha). 1185
Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation Free surface – Ship resistance simulation

• For time discretization we can use an unsteady formulation (Euler in this case). • A way to accelerate the convergence to steady state, is by using local time stepping.
• This scheme requires setting the time-step, and it should be choosing in such a way • In LTS or local time steeping, the time-step is manipulated for each individual cell in
that it resolves the mean physics. the mesh, making it as high as possible to enable the simulation to reach steady-
• Remember, as the free surface is a strong discontinuity, for stability and good state quickly.
resolution we need to use a CFL less than one for the interface courant. • 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.
ddtSchemes
• 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.
default Euler;
} • To enable LTS, we use the localEuler method.

ddtSchemes
• Hereafter, we are using what is know as global time stepping, that is, the CFL {
number is limited by the smallest cell. default localEuler;
• The simulation is time-accurate, but it requires a lot of CPU time to reach a steady }
state (if it reaches one).
1186 1187

Multiphase flows hands-on tutorials Multiphase flows hands-on tutorials


Free surface – Ship resistance simulation Free surface – Ship resistance simulation

• In the LTS method, the maximum flow CFL number, maximum interface CFL number, • At this point, we are ready to run the simulation.
and the smoothing and damping of the solution across the cells, can be controlled in • Remember to adjust the numerics according to your physics.
the dictionary fvSolution, in the sub-dictionary PIMPLE.
• You can choose between running using global time stepping (directory uns) or local
time stepping (directory LTS).
PIMPLE • You will find the instructions of how to run the cases in the file README.FIRST
{ located in the case directory.
momentumPredictor yes;

nOuterCorrectors 1;
nCorrector 3;
nNonOrthogonalCorrectors 2;

maxCo 10; Maximum flow Courant


Maximum interface maxAlphaCo 1;
Courant
Local time step
rDeltaTSmoothingCoeff 0.05;
Local time step rDeltaTDampingCoeff 0.5; smoothing
damping
Limit the maximum
maxDeltaT 1;
time-step size
}

1188 1189
Roadmap A crash Introduction to compressible flows modeling OpenFOAM®

What are compressible flows?


A crash introduction to: • In few words, compressible flows are flows where the density change.

1. Turbulence modeling in OpenFOAM® • The changes in density can be due to velocity, pressure, or temperature
variations.
2. Multiphase flows modeling in • Compressible flows can happen at low speed (subsonic) or high speed
OpenFOAM® (transonic, supersonic, hypersonic and so on).
3. Compressible flows in OpenFOAM® • Buoyancy-driven flows are also considered compressible flows. After all, the
buoyancy is due to temperature gradients.
4. Moving bodies in OpenFOAM®
• In compressible flows, the viscosity also change with temperature.
5. Source terms in OpenFOAM® • In compressible flows, the thermodynamical variables are related via an
6. Scalar transport pluggable solver 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.
1190 1191

A crash Introduction to compressible flows modeling OpenFOAM® 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 Rayleigh–Bénard convection cells
Large Natural Convection Plume, as effect of combustion of excess
non-useable gases behind oilfield. https://en.wikipedia.org/wiki/File:B%C3%A9nard_cells_convection.ogv
• Heating, ventilation, and air conditioning (HVAC). https://en.wikipedia.org/wiki/Plume_(fluid_dynamics)#/media/File:Naturalc
onvectionplume.JPG
• Thermal comfort.
• Turbomachinery.
• Combustion.
• Chemical reactions.
• Condensation, evaporation, and melting.
• And many more.
Iron melting Airplane thermal image
• As you can see, the range of applicability is very wide. https://commons.wikimedia.org/wiki/File:Iron_-melting.JPG http://www.blackroc.com/wp-content/uploads/2016/03/thermal-image.jpg
1192 Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 1193
A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Compressible flows – Starting equations

NSE

Shadowgraph Images of Re-entry Vehicles Additional closure equations for:


Photo credit: NASA on the Commons.
https://www.flickr.com/photos/nasacommons/
turbulence models, multiphase models, combustion, particles, source
terms, equation of state, and so on
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 1194 1195

A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Compressible flows – Boundary layer 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 boundary layer in the velocity distribution (or momentum), there is also a thermal
boundary layer. Horizontal heated plate immersed in a quiescent fluid. Vertical heated plate immersed in a quiescent fluid.
Natural convection Natural convection.
• Thermal boundary layer thickness is different from the thickness of the viscous sublayer (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
Natural convection in a heated plate
momentum sublayer thickness.
• As the fluid is warmed by the plate, its density decreases and a buoyant force arises which induces flow
• For fluids of low Prandtl numbers (e.g., air), it is much larger than the momentum sublayer thickness. motion in the vertical or horizontal direction.
• For Prandtl number equal 1, the thermal boundary layer is equal to the momentum boundary layer. 1196 • The force is proportional to , therefore gravity must be considered. 1197
A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Compressible solvers in OpenFOAM® Compressible solvers in OpenFOAM®


• Dealing with compressible flows in OpenFOAM® is not so different from what • Additionally, the numerics of compressible solvers is a little bit more delicate.
we have done so far. • Temperature is a bounded quantity, so we need to use accurate and
• The new steps are: stable methods (preferably TVD).
• Define the thermophysical variables. • If you are in the presence of shock waves, you need to use TVD
• Define the boundary conditions and initial conditions for temperature. methods and gradient limiters.

• If you are dealing with turbulence, you will need to define the • The solvers are very sensitive to overshoots and undershoots in the
boundary conditions and initial conditions for the turbulent thermal gradients, so you need to use very aggressive limiters.
diffusivity. • If you are dealing with chemicals reactions or combustion, you need to
• Define discretization schemes and linear solvers for the new use accurate and stable methods (preferably TVD).
variables and equations. • TVD methods requires good meshes and CFL number below 1 for good
accuracy and stability.

• Remember to choose the near-wall treatment. • Using steady solvers requires tuning of the under-relaxation factors.
Usually, the default values do not work well.
• We have found that it is tricky to achieve convergence using a low-RE
approach with compressible flows (high speed). • The use local time stepping to reach steady state can improve the
1198
convergence rate. 1199

A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Compressible solvers in OpenFOAM® Compressible solvers in OpenFOAM®


• OpenFOAM® comes with many solvers and models that can address a wide physics.
• These are the compressible solvers that you will use most of the time in
• Compressibility can be introduced in all the modeling capabilities we have seen so far
OpenFOAM®.
(turbulence modeling and multiphase flows).
• It is also possible to add source terms, deal with moving bodies or use adaptive mesh
• HVAC and low speed aerodynamics:
refinement.
• rhoSimpleFoam, rhoPimpleFoam

• You will find the source code of all the compressible solvers in the directories: • High speed aerodynamics:
• OpenFOAM-5.x/applications/solvers/compressible • sonicFoam, rhoSimpleFoam, rhoPimpleFoam
• OpenFOAM-5.x/applications/solvers/combustion
• OpenFOAM-5.x/applications/solvers/heatTransfer • Buoyancy driven flows (including Boussinesq approximation):
• OpenFOAM-5.x/applications/solvers/lagrangian • buoyantBoussinesqPimpleFoam buoyantBoussinesqSimpleFoam,
buoyantSimpleFoam, buoyantPimpleFoam
• OpenFOAM-5.x/applications/solvers/multiphases
• You will find the source code of the thermophysical models in the directory: • Conjugate heat transfer
• OpenFOAM-5.x/src/thermophysicalModels • chtMultiRegionFoam
1200 1201
A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Selecting thermophysical properties Selecting thermophysical properties


• The thermophysical properties are set in the dictionary • The form of the energy equation to be used is specified
1 thermoType thermophysicalProperties. 1 thermoType in line 9 (energy).
2 { 2 {
3 type hePsiThermo; • This dictionary file is located in the directory constant. 3 type hePsiThermo; • In this case we are using enthalpy formulation
4 mixture pureMixture; 4 mixture pureMixture;
(sensibleEnthalpy).
5 transport const; • Thermophysical models are concerned with energy, heat 5 transport const;
6 thermo hConst; 6 thermo hConst;
7 equationOfState perfectGas;
and physical properties. 7 equationOfState perfectGas;
• In this formulation, the following equation is solved,
8 specie specie; 8 specie specie;
• In the sub-dictionary thermoType (lines 1-10), we define
9 energy sensibleEnthalpy; 9 energy sensibleEnthalpy;
10 } the thermophysical models. 10 }
11 11
12 mixture • The entries in lines 3-4, are determined by the choice of 12 mixture
13 { the solver (they are hardwired to the solver). 13 { • Alternatively, we can use the sensibleInternalEnergy
14 specie 14 specie formulation, where the following equation is solved for
15 { • The transport keyword (line 5). concerns evaluating 15 { the internal energy,
16 nMoles 1; dynamic viscosity. In this case the viscosity is constant. 16 nMoles 1;
17 molWeight 28.9; 17 molWeight 28.9;
18 } • The thermodynamic models (thermo keyword) are 18 }
19 thermodynamics 19 thermodynamics
20 {
concerned with evaluating the specific heat Cp (line 6). In 20 {
21 Cp 1005; this case Cp is constant. 21 Cp 1005; • In the previous equations, the effective thermal diffusivity
22 Hf 0; 22 Hf 0;
23 } • The equationOfState keyword (line 7) concerns to the 23 }
is equal to,
24 transport equation of state of the working fluid. In this case, 24 transport
25 { 25 {
26 mu 1.84e-05; 26 mu 1.84e-05;
27 Pr 0.713; 27 Pr 0.713;
28 } 28 }
29 } 29 } • And is the kinetic energy per unit mass.
• Line 8 is a fixed option (hardwired to the solver). 1202 1203

A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Selecting thermophysical properties Selecting thermophysical properties


• When we use the sensible formulation • When we use the sensible formulation
1 thermoType 1 thermoType
2 {
(sensibleEnthalpy or sensibleInternalEnergy), the 2 {
(sensibleEnthalpy or sensibleInternalEnergy), the
3 type hePsiThermo; heat of formation is not included in the energy equation. 3 type hePsiThermo; heat of formation is not included in the energy equation.
4 mixture pureMixture; 4 mixture pureMixture;
5 transport const; • In the sub-dictionary mixture (lines 12-29), we define the 5 transport sutherland; • If you want to include the heat of formation, you must use
6 thermo hConst; thermophysical properties of the working fluid. 6 thermo hConst; the absoluteEnthalpy formulation (line 6).
7 equationOfState perfectGas; 7 equationOfState perfectGas;
8 specie specie; • In line 17, we define the molecular weight. 8 specie specie; • If you use the transport model sutherland (line 5), you
9 energy sensibleEnthalpy; 9 energy sensibleEnthalpy; will need to define the coefficients of the Sutherland
10 } • In line 21, we define the specific heat. 10 }
11 11 model.
12 mixture • The heat of formation is defined is line 22 (not used in 12 mixture
13 { the sensible formulation). 13 { • The Sutherland model is defined as follows
14 specie 14 specie (OpenFOAM® uses the 2 coefficients formulation):
15 { • In this case, we are defining the properties for air at 20° 15 {
16 nMoles 1; Celsius and at a sea level. 16 nMoles 1;
17 molWeight 28.9; 17 molWeight 28.9;
18 } • As we are using the transport model const (line 5), we 18 }
19 thermodynamics 19 thermodynamics
20 { need to define the dynamic viscosity and Prandtl number 20 {
21 Cp 1005; (lines 26 and 27). 21 Cp 1005;
22 Hf 0; 22 Hf 0;
• The Sutherland coefficients are defined in lines 26-27.
23 } • If you set the viscosity to zero, you solve the Euler 23 }
24 transport equations. 24 transport
25 { 25 {
26 mu 1.84e-05; • Remember, transport modeling (line 5), concerns 26 As 1.4792e-06; • Remember, you can use the banana method
27 Pr 0.713; evaluating dynamic viscosity, thermal conductivity and 27 Ts 116; to know all the options available.
28 } 28 }
29 } thermal diffusivity. 29 }
1204 1205
A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Adjusting the numerical method Adjusting the numerical method


• If you choose the sensibleEnthalpy formulation, you need to define the convective • If you choose the sensibleInternalEnergy formulation, you need to define the convective
discretization schemes and linear solvers of the energy equation (enthalpy formulation). discretization schemes and linear solvers of the energy equation (internal energy formulation).

fvSchemes fvSolution fvSchemes fvSolution

divSchemes “(h|T|rho)” divSchemes “(e|T|rho)”


{ { { {
div(phi,T) Gauss linearUpwind Grad(T); solver PBiCGStab; div(phi,T) Gauss linearUpwind Grad(T); solver PBiCGStab;
div(phi,K) Gauss linear; preconditioner DILU; div(phi,K) Gauss linear; preconditioner DILU;
div(phi,h) Gauss linear; tolerance 1e-8; div(phi,e) Gauss linear; tolerance 1e-8;
… relTol 0.01; div(phiv,p) Gauss linear; relTol 0.01;
… } … }
… … … …
} … … …
… } …

• Remember, temperature is a bounded quantity so you need to use non-oscillatory methods. • 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 • For low speed flows, the kinetic energy K and the internal energy e can be discretized using the
method. For high speed flows, is better to use bounded methods. linear method. For high speed flows, is better to use bounded methods.
• Remember to use gradient limiters. • Remember to use gradient limiters.
• If you are using a steady solver, remember to set the under relaxation factors for h, T, and rho.
1206 • If you are using a steady solver, remember to set the under relaxation factors for e, T, and rho.
1207

A crash Introduction to compressible flows modeling OpenFOAM® A crash Introduction to compressible flows modeling OpenFOAM®

Transport properties – Boussinesq solvers Final remarks


• If you use the family of solvers that uses the Boussinesq
• When solving the enthalpy equation,
transportModel Newtonian; approximation, you do not need to define the
// Laminar viscosity thermodynamical properties.
nu nu [0 2 -1 0 0 0 0] 1e-05;
• Instead, you need to the define the transport properties
// Thermal expansion coefficient (as for incompressible flows) and a reference
beta beta [0 0 0 -1 0 0 0] 3e-03; temperature.
the pressure work term can be excluded from the solution.
// Laminar Prandtl number • You will need to define the following fluid properties:
Pr Pr [0 0 0 0 0 0 0] 0.9;
laminar viscosity, thermal expansion coefficient, laminar • This has a stabilizing effect on the solution, specially if you are using steady solvers.
// Turbulent Prandtl number Prandtl number, and turbulent Prandtl number.
Prt Prt [0 0 0 0 0 0 0] 0.7;
• The following solvers use the Boussinesq approximation:
• To turn off the pressure work term , set the option dpdt to no ( dpdt no; ) in
// Reference temperature the thermophysicalProperties dictionary.
TRef TRef [0 0 0 1 0 0 0] 300;
• buoyantBoussinesqPimpleFoam
• buoyantBoussinesqSimpleFoam.
• Remember, the Boussinesq approximation is a way to
solve natural convection problems, without having to • Finally, when you work with compressible solvers you use absolute
solve the compressible NSE.
pressure and the working units are in Pascals.
• It assumes that variations in density have no effect on
the flow field, except when they give rise to buoyancy
forces.
• This approximation is accurate when density variations
are small.
1208 1209
Compressible flows hands-on tutorials Compressible flows hands-on tutorials
2D Heated cylinder – Thermal plumes

• The cylinder and the bottom surface are heated.


• 2D Heated cylinder – Thermal plumes
• Let us run this case. Go to the directory:

$PTOFC/advanced_physics/compressible/2Dcylinder_plumes/buoyantPimpleFoam/

• From this point on, please follow me.


• We are all going to work at the same pace.
Temperature contours Temperature contours
• Remember, $PTOFC is pointing to the path where you No turbulent model K-omega SST turbulent model
http://www.wolfdynamics.com/training/compressible/image1.gif http://www.wolfdynamics.com/training/compressible/image2.gif
unpacked the tutorials.
1210 1211

Compressible flows hands-on tutorials Compressible flows hands-on tutorials


2D Heated cylinder – Thermal plumes 2D Heated cylinder – Thermal plumes
• In this case we will use the solver buoyantPimpleFoam. • At this point, we are ready to run the simulation.
• This family of solvers is specifically formulated for buoyancy driven flows and HVAC • To run the tutorial, type in the terminal:
applications.
• When we deal with buoyant flows, we also need to define the gravity vector. This is done in the
1. $> foamCleanTutorials
dictionary constant/g.
• As the flow is compressible, we need to define the thermodynamical properties of the working 2. $> blockMesh
fluid. 3. $> transformPoints -rollPitchYaw '(0 0 90)'
• This is done in he dictionary constant/thermophysicalProperties.
4. $> transformPoints -scale '(0.01 0.01 0.01)'
• We also need to define the boundary conditions and initial conditions for the temperature field.
5. $> createPatch -noFunctionObjects -overwrite
• Finally, adjust the numerics according to your physics.
6. $> rm -rf 0
• As an exercise, try to use the different formulations of the energy equation and compare the
solutions. 7. $> cp -r 0_org 0
• Alternatively, you can use the solver buoyantBoussinesqPimpleFoam, which instead of $> decomposePar -force
8.
solving the energy equation it uses the Boussinesq approximation.
• You will find the instructions of how to run the cases in the file README.FIRST located in the 9. $> mpirun -np 4 buoyantPimpleFoam -parallel | tee log
case directory. 10. $> paraFoam -builtin

1212 1213
Compressible flows hands-on tutorials Compressible flows hands-on tutorials
2D supersonic cylinder – Shock waves

• 2D supersonic cylinder – Shock waves


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

$PTOFC/advanced_physics/compressible/supersonic_cyl

• From this point on, please follow me. Shock wave visualization using numerical Schlieren (density gradient)
• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you • The shock wake is a strong discontinuity that need to be treated using high resolution
unpacked the tutorials. schemes.

1214
• Additionally, the non-orthogonality add extra complications to this problem. 1215

Compressible flows hands-on tutorials Compressible flows hands-on tutorials


2D supersonic cylinder – Shock waves 2D supersonic cylinder – Shock waves
• In this case we will use the solver sonicFoam.
• This solver is specifically formulated for trans-sonic/supersonic flows.
• The solver is unsteady, 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.
• Finally, adjust the numerics according to your physics.
• Alternatively, you can use the solver rhoPimpleFoam, but you will need to enable
transonic corrections.
Mach number contours Schlieren contours • This is done in the PIMPLE block of the dictionary fvSolution ( transonic yes; ).
http://www.wolfdynamics.com/training/compressible/image3.gif http://www.wolfdynamics.com/training/compressible/image4.gif

• You will find the instructions of how to run the cases in the file README.FIRST
located in the case directory.
1216 1217
Roadmap A crash Introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM® – A few examples


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
Moving domain (imposed motion) Oscillating cylinder (prescribed motion)
http://www.wolfdynamics.com/training/movingbodies/image1.gif http://www.wolfdynamics.com/training/movingbodies/image2.gif

1218 1219

A crash Introduction to moving bodies OpenFOAM® A crash Introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM® – A few examples Moving bodies in OpenFOAM® – A few examples

http://www.wolfdynamics.com/training/movingbodies/image3.gif http://www.wolfdynamics.com/training/movingbodies/image4.gif

Numerical towing tank (2 DoF)

VOF with MRF VOF with dynamic meshes

http://www.wolfdynamics.com/training/mphase/image32.gif http://www.wolfdynamics.com/training/mphase/image33.gif

Falling body (6 DoF)


http://www.wolfdynamics.com/training/movingbodies/image5.gif 1220 1221
A crash Introduction to moving bodies OpenFOAM® A crash Introduction to moving bodies OpenFOAM®

Moving bodies in OpenFOAM® Moving bodies in OpenFOAM®


• OpenFOAM® comes with many solvers and models that can address a wide physics. • The mesh motion solver is selected in the dictionary constant/dynamicMeshDict.
• Moving bodies can be added in all the modeling capabilities we have seen so far • In the case of prescribed motion of a boundary patch, the motion is assigned in the
(turbulence modeling, multiphase flows, and compressible flows). dictionary 0/pointDisplacement.
• Several class of motions can be simulated in OpenFOAM®: • Also, the boundary type of the moving walls must be movingWallVelocity, this is set
in the dictionary 0/U.
• Prescribed motion.
• And as usual, you will need to adjust the numerics according to your physics.
• Rigid body motion.
• To use the moving bodies capabilities, you will need to use solvers able to deal with
• Sliding meshes. dynamic meshes.
• MRF. • The solvers able to deal with dynamic meshes contain the word DyM in their name.
• 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:
• Setting moving bodies simulations is not so different from what we have done so far. • $> find . -iname “*DyM*”
• The main difference is that we must assign a motion type to a surface patch, a cell • A few solvers that work with dynamic meshes: interDyMFoam, pimpleDyMFoam,
region, or the whole domain. rhoPimpleDyMFoam, sonicDyMFoam.

1222 1223

A crash Introduction to moving bodies OpenFOAM® Moving bodies hands-on tutorials


Moving bodies in OpenFOAM®
• You will find the source code of all the mesh motion libraries in the directories: • Continuous stirring tank reactor – Sliding meshes and
• OpenFOAM-5.x/src/dynamicFvMesh
MRF
• OpenFOAM-5.x/src/dynamicMesh
• OpenFOAM-5.x/src/fvMotionSolver • Let us run this case. Go to the directory:
• OpenFOAM-5.x/src/rigidBodyDynamics
• OpenFOAM-5.x/src/rigidBodyMeshMotion $PTOFC/advanced_physics/sliding_meshes_MRF/CSTR
• OpenFOAM-5.x/src/sixDoFRigidBodyMotion

• You will find the source code of the prescribed patch motion in the directory:
• OpenFOAM-5.x/src/fvMotionSolver/pointPatchFields/derived • From this point on, please follow me.
• We are all going to work at the same pace.
• You will find the source code of the restraints/constraints of rigid body motion solvers • Remember, $PTOFC is pointing to the path where you
in the directory: unpacked the tutorials.
• OpenFOAM-5.x/src/sixDoFRigidBodyMotion/sixDoFRigidBodyMotion
1224 1225
Moving bodies hands-on tutorials Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF 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 a 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
Sliding grids – Unsteady solver MRF – Steady solver (fix region)s
http://www.wolfdynamics.com/training/movingbodies/image6.gif http://www.wolfdynamics.com/training/movingbodies/image7.gif

Face region between fix and


rotating regions Cell region 1
(face_inner_volume) (cell_inner_volume)

1226 1227

Moving bodies hands-on tutorials Moving bodies hands-on tutorials


Continuous stirring tank reactor – Sliding meshes and MRF Continuous stirring tank reactor – Sliding meshes and MRF
• In the MRF approach, the governing equations are solved in a relative rotating frame • In the sliding meshes approach, the selected rotating region is physically rotating.
in the selected rotating zone. • As the meshes are non-conforming, the solution between the rotating region and the
• Additional source terms that model the rotation effect are taken into account. fix region must be interpolated using arbitrary mesh interface.
• You select the rotating zone and set the rotation properties in the dictionary • In the sliding meshes approach, is not enough to only identify the rotating region.
constant/MRFProperties. • We also need to create the interface patches between the fix zone and the rotating
• In this case, the mesh is conforming. zone.

Shaft Shaft
type rotatingWallVelocity; type rotatingWallVelocity;
origin (0 0 0); origin (0 0 0);
axis (0 0 1); axis (0 0 1);
omega constant 12.566370; omega constant 12.566370;
value uniform (0 0 0); value uniform (0 0 0);

Impeller Impeller
type movingWallVelocity; type movingWallVelocity;
value uniform (0 0 0); Inner region generated during value uniform (0 0 0); Inner region – dynamicMeshDict
meshing - MRFProperties
Arbitrary mesh interface –
createBafflesDicts

1228 1229
Moving bodies hands-on tutorials Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF Continuous stirring tank reactor – Sliding meshes and MRF
Shaft • For siding meshes, we need to create separated regions.
type rotatingWallVelocity;
origin (0 0 0); • In this case, to create the two regions we proceed as follows,
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);

Impeller 1. $> createBaffles –overwrite


type movingWallVelocity;
value uniform (0 0 0); Inner region and arbitrary mesh 2. $> mergeOrSplitBaffles –split –overwrite
interface

• In step 1, we split the mesh in regions using the baffles (faceZone), created during the meshing
constant/dynamicMeshDict – For sliding meshes constant/MRFProperties – For MRF approach stage.

cellZone cell_inner_volume; • We also create the cyclicAMI patches AMI1 and AMI2.
dynamicFvMesh dynamicMotionSolverFvMesh; active yes;
motionSolverLibs ( "libfvMotionSolvers.so" ); • At this point we have two regions and one zone. However, the two regions are stich together
solver solidBody; // Fixed patches (by default they move’ with the MRF zone) via the patches AMI1 and AMI2.
cellZone cell_inner_volume; nonRotatingPatches ();
solidBodyMotionFunction rotatingMotion; • In step 2, we topologically split the patches AMI1 and AMI2. As we removed the link between
origin (0 0 0); origin (0 0 0); AMI1 and AMI2, the regions are free to move.
axis (0 0 1); axis (0 0 1);
omega constant 12.566370; omega constant 12.566370;
1230 1231

Moving bodies hands-on tutorials Moving bodies hands-on tutorials


Continuous stirring tank reactor – Sliding meshes and MRF Continuous stirring tank reactor – Sliding meshes and MRF

• The utility createBaffles, reads the dictionary createBafflesDict. • In sliding mesh simulations, the solution is interpolated back-and-forth
• With this utility we create the interface patches between the fix zone and the between the regions.
rotating zone. • The interpolation is done at the arbitrary mesh interface patches (AMI) .
• To reduce interpolation errors at the AMI patches, the meshes should be
baffles
similar in the master and slave patches.
{
rotating Name of the baffle group
{ AMI interface Fix domain
type faceZone; Use faceZone
zoneName face_inner_volume; Face to use to construct the AMI patches. http://www.wolfdynamics.com/training/movingbodies/image8.gif
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 noOrdering;
}
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 noOrdering;
}
}
}
} Initially, the master and slave patches Rotating domain Rotating patch Fix patch
share a common face 1232 Master patch Slave patch 1233
Moving bodies hands-on tutorials Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF Continuous stirring tank reactor – Sliding meshes and MRF

• At this point the mesh is ready to use. You can visualize the mesh using • The command moveDynamicMesh –checkAMI
paraFoam. will print on screen the quality of the AMI interfaces
for every time step.
• If you use checkMesh, it will report that there are two regions. • Ideally, you should get the AMI patches weights as
close as possible to one.
• In the dictionary constant/dynamicsMeshDict we set which region will
• Weight values close to one will guarantee a good
move and the rotation parameters. interpolation between the AMI patches.
• To preview the region motion, in the terminal type: http://www.wolfdynamics.com/training/movingbodies/image9.gif

• $> moveDynamicMesh … Name of the AMI patch Name of the AMI patch

• To preview the region motion and check the quality of the AMI interfaces, in Calculating AMI weights between owner patch: AMI1 and neighbour patch: AMI2
Number of faces in
the terminal type: AMI: Creating addressing and weights between 2476 source faces and 2476 target faces the AMI patches

• $> moveDynamicMesh -checkAMI -noFunctionObjects 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


• In our YouTube channel you can find an step-by-step video explaining …
this case. …
1234 1235

Moving bodies hands-on tutorials 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 • Oscillating cylinder – Prescribed motion
sliding_psio) or MRF (directories MRF_piso or MRF_simple).
• Let us run this case. Go to the directory:
• If you run the sliding meshes case, you will use the solver pimpleDyMFoam.
• If you run the MRF approach case, you can use the solver simpleFoam
(steady solution) or pimpleFoam (unsteady solution).
$PTOFC/advanced_physics/prescribed_motion/oscillatingCylinder
• You will find the instructions of how to run the cases in the file
README.FIRST located in the case directory.

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
1236 1237
Moving bodies hands-on tutorials Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion Oscillating cylinder – Prescribed motion
• In the dictionary constant/dynamicMeshDict we select the mesh morphing
Moving boundary
method and the boundary patch that it is moving (lines 21 and 25, respectively).
http://www.wolfdynamics.com/training/movingbodies/image10.gif
• 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.
• But in general, 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
Cylinder prescribed motion – Oscillating motion 24 {
25 diffusivity inverseDistance (cylinder);
26 }

1238 Mesh diffusion method Patch name 1239

Moving bodies hands-on tutorials Moving bodies hands-on tutorials


Oscillating cylinder – Prescribed motion Oscillating cylinder – Prescribed motion
• In the dictionary 0/pointDisplacement we select the prescribed body motion. • If you are dealing with turbulence modeling and you want to use wall functions, you
• In this case we are using oscillatingDisplacement (line 44) for the cylinder patch. will need to assign the movingWallVelocity boundary condition to the moving patch.
• This is done in the dictionary 0/U.
• 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 cylinder
41). 42 {
43 type movingWallVelocity;
44 value uniform (0 0 0);
45 }
37 in
38 {
39 type fixedValue;
40 value uniform (0 0 0); • And as usual, you will need to adjust the numerics according to your physics.
41 }
42 cylinder • In this case we need to solve the new fields cellDisplacement and diffusivity, which
43 { are related to the mesh motion and morphing.
44 type oscillatingDisplacement;
• In the dictionary fvSolution, you will need to add a linear solver for the field
45 amplitude ( 0 1 0 );
46 omega 6.28318; cellDisplacement.
47 value uniform ( 0 0 0 ); Dummy value for paraview
• In the dictionary fvSchemes, you will need to add the discretization schemes related
48 }
to the mesh morphing diffusion method, laplacian(diffusivity, cellDisplacement).
1240 1241
Moving bodies hands-on tutorials 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 • Floating body – Rigid body motion
README.FIRST located in the case directory.
• Let us run this case. Go to the 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. $PTOFC/advanced_physics/rigid_body_motion/floatingBody
• To check the mesh motion, type in the terminal:

1. $> moveDynamicMesh -noFunctionObjects


• From this point on, please follow me.
• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
1242 1243

Moving bodies hands-on tutorials Moving bodies hands-on tutorials


Floating body – Rigid body motion 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-78, we define all the inputs required by the rigid motion solver.

http://www.wolfdynamics.com/training/movingbodies/image11.gif
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 {



http://www.wolfdynamics.com/training/movingbodies/image12.gif 78 }
Floating body simulation with VOF and turbulence modeling. 1244 1245
Moving bodies hands-on tutorials Moving bodies hands-on tutorials
Floating body – Rigid body motion Floating body – Rigid body motion
• The dictionary constant/dynamicMeshDict (continuation). • The dictionary constant/dynamicMeshDict (continuation).

23 sixDoFRigidBodyMotionCoeffs 50 constraints
24 { 51 {
25 patches (floatingObject); Moving patch 55 fixedAxis
26 56 {
Mesh deformation limits.
27 innerDistance 0.1; 57 sixDoFRigidBodyMotionConstraint axis;
The mesh will not be deformed in the fringe located within
28 outerDistance 0.4; 58 axis (0 1 0);
innerDistance and outerDistance (distance normal to the wall)
59 } Motion constraints
33 centreOfMass (0.5 0.5 0.5); If you do not give any
34 mass 5; Physical properties of the body 63 fixedLine constraint, the body is free
35 momentOfInertia (0.08 0.08 0.1); 64 { to move in all directions.
65 sixDoFRigidBodyMotionConstraint line;
37 report on; Report on screen position of the body 66 centreOfRotation (0.5 0.5 0.5);
38 67 direction (0 0 1);
outerDistance
68 }
45 solver
46 { 70 }
47 type Newmark; Rigid body motion solver Body restraints
48 } 72 restraints
Restraints can be used to
… 73 {
Body patch damp the acceleration of the
… body.
76 }
… In this case, we are not
using restraints
78 }
innerDistance
Set it to zero if you do not want to apply mesh morphing to the inner region 1246 1247

Moving bodies hands-on tutorials Moving bodies hands-on tutorials


Floating body – Rigid body motion Floating body – Rigid body motion
• In the dictionary 0/pointDisplacement we select the body motion. • And as usual, you will need to adjust the numerics according to your physics.
• For rigid body motion, the body motion is computed by the solver, therefore, we use • In the case directory, you will find the script extractData.
the boundary condition calculated.
• This script can be use to extract the position of the body during the
33 floatingObject simulation.
34 {
35 type calculated;
• In order to use the extractData script, you will need to save the log file of
36 value uniform (0 0 0); the simulation.
37 }
• At this point, we are ready to run the simulation.
• We will use the solver interDyMFoam.
• If you are dealing with turbulence modeling and you want to use wall functions, you
will need to assign the movingWallVelocity boundary condition to the moving patch. • You will find the instructions of how to run the cases in the file
• This is done in the dictionary 0/U. README.FIRST located in the case directory.

33 floatingObject
34 {
35 type movingWallVelocity;
36 value uniform (0 0 0);
37 }
1248 1249
Roadmap A crash Introduction to source terms OpenFOAM®

Source terms in OpenFOAM®


A crash introduction to: • In addition to all modeling capabilities we have seen so far in OpenFOAM®, you can
also add source terms to the governing equations without the need of modifying the
1. Turbulence modeling in OpenFOAM® original source code.
• This functionality is provided via the dictionary fvOptions, which is located in the
2. Multiphase flows modeling in directory system.
OpenFOAM® • 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
3. Compressible flows in OpenFOAM® level programming.
4. Moving bodies in OpenFOAM® • The fvOptions functionality work with most of the solvers that deal with advanced
modeling capabilities.
5. Source terms in OpenFOAM® • Remember, the solver icoFoam is very basic with no modeling capabilities.
Therefore you can not use the fvOptions functionality and many other modeling
6. Scalar transport pluggable solver and postprocessing capabilities with it.
• You will find the source code of the source terms in the directory:
• OpenFOAM-5.x/src/fvOptions

1250 1251

A crash Introduction to source terms OpenFOAM® A crash Introduction to source terms OpenFOAM®

Source terms in OpenFOAM® Source terms in OpenFOAM®


• To use a source terms, you must first select where you want to apply it • The source terms can be selected in the dictionary
1 user_defined_name fvOptions, and they can be modified on-the-fly.
• You can apply a source term in the whole domain, a set of cells, a cell zone, or a 2 {
3 type name_of_source_term; • This dictionary file is located in the directory system.
point (or group of points). 4
5 active true; • Hereafter we show a generic fvOptions dictionary.
• You can create the set of cells at meshing time or you can use the utility topoSet to 6
7 input_coefficients • According to the source term you selected, you will need
select a group of cells. 8 {
to give different input parameters in the input coefficients
9 timeStart 0.5;
• By the way, boundary conditions are source terms added at the boundary patches. 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
Set of cell 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 quantity
21 volumeMode absolute;
• specific: input values are given as quantity/m3
22
...
...
... • Remember, you can use the banana method to know all
Point selection source terms and options available.
23 }
24 }
• You can also read the source code.
1252 1253
Source terms hands-on tutorials Source terms hands-on tutorials
Filter source term
• In this case we are using the source term explicitPorositySource.

• Filter source term • Using this source term we can apply a porous region (of the type Darcy-Forchheimer)
in the cell selection.
• Let us run this case. Go to the directory: • The source term is activated after 2 seconds of simulation time.

$PTOFC/advanced_physics/source_terms/filter/porous_source
Set of cell
(filter)

• From this point on, please follow me.


• We are all going to work at the same pace.
• Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
1254 http://www.wolfdynamics.com/training/sourceterms/image1.gif 1255

Source terms hands-on tutorials Source terms hands-on tutorials


Filter source term Filter source term
system/fvOptions system/topoSetDict
• The source terms can be selected in the • To create the cellZone used in fvOptions, we
17
18
filter1
{
dictionary fvOptions, and they can be modified first create a cellSet.
19 type explicitPorositySource; on-the-fly. • The set of cells (cellSet) is constructed using the
20 active yes;
22 explicitPorositySourceCoeffs • In this case we are using the source term utility topoSet.
23 {
25 timeStart 2; explicitPorositySource (line 19). • This utility reads the dictionary topoSetDict,
26 duration 5;
28 selectionMode cellZone; • Using this source term we can apply a porous which is located in the directory system.
29 cellZone filter; region (of the type Darcy-Forchheimer) in the cell
31 type DarcyForchheimer; actions • Hereafter we show the dictionary inputs used to
selection (line 28).
38 DarcyForchheimerCoeffs
( create the cellSet named filter.
// filter
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 name filter; Name of the selection
46 coordinateSystem at meshing time or using the utility topoSet. type cellSet; Select a set of cells
47 {
49 type cartesian; • In lines 38-60, we define the input parameters of action new; Create a new selection
50 origin (0 0 0);
52 coordinateRotation
the model.
source boxToCell;
53 {
54 type axesRotation; • In this case, the coefficients f and d are sourceInfo
Use a box to select the set of cells
{
55 e1 (1 0 0); resistance/impermiability coefficients, and e1 and box (1.5 -10 -10) (2 10 10);
56 e2 (0 1 0);
57 }
e2 are the vectors that are used to specify the }
}
59 } porosity. ...
60 } ...
61 } ...
62 } )
1256 1257
Source terms hands-on tutorials Source terms hands-on tutorials
Filter source term Filter source term
system/topoSetDict
• To create the cellZone used in fvOptions, we • At this point, we are ready to run the simulation.
first create a cellSet. • We will use the solver pimpleFoam, which can use source terms.
• Now that we have the cellSet filter, we can
convert it to a cellZoneSet that can be used by • Before running the simulation, remember to use the utility topoSet to create
fvOptions. the filter region used by the source term.
• The name of the new cellZoneSet is filter. • You can visualize the region using paraview.
• Remember, you can apply the source terms in a
actions
( cellSet or in a cellZone.
• 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.
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
}
}
)
1258 1259

Roadmap Scalar transport pluggable solver

• In addition to all modeling capabilities we have seen so far in OpenFOAM®,


A crash introduction to: you can also add scalar transport equations without the need of modifying
the original source code.
1. Turbulence modeling in OpenFOAM® • This functionality is provided via functionObjects, and it can be seen as a
solver that can be plug into another one.
2. Multiphase flows modeling in
• To setup the scalar transport equation you need to:
OpenFOAM®
• Define the functionObject in the dictionary controlDict.
3. Compressible flows in OpenFOAM® • Add the discretization schemes and linear solvers for the new equations.
4. Moving bodies in OpenFOAM® • Define the boundary conditions and initial conditions of the transported
scalars.
5. Source terms in OpenFOAM®
• You will find the source code of the scalar transport pluggable solver in the
6. Scalar transport pluggable solver directory:
• OpenFOAM-5.x/src/functionObjects/solvers

1260 1261
Scalar transport pluggable solver Scalar transport pluggable solver

The functionObject scalarTransport Boundary conditions


• The scalar transport functionObject is defined in
the dictionary controlDict.
0/s1
• Remember, the input parameters can be modified • Assuming that you named the new scalar s1, you
scalar1 on-the-fly. dimensions [0 0 0 0 0 0 0]; will need to define the boundary conditions and
{
type scalarTransport;
initial conditions for the field s1.
Select scalarTransport functionObject internalField uniform 0;
functionObjectLibs ("libsolverFunctionObjects.so");
• This is done in the dictionary 0/s1.
boundaryField
enabled true; Enable/Disable functionObject { • In this case, the scalar is entering in the patch
walls
writeControl outputTime; Saving frequency of the new field { inlet with a value of 1 (this is a concentration
log yes; Show functionObject information on screen
type zeroGradient; therefore it has no dimensions).
}

nCorr 1; Number of corrector iterations inlet


• The initial concentration of the scalar is zero.
{
D 0; Diffusion coefficient. type fixedValue;
//alphaD 0; If turbulent modeling is in use, you can define the value uniform 1;
//alphaDt 0; laminar diffusion coefficient alphaD and the turbulent }
diffusion coefficient alphaDt
outlet
{
Name of the new field. You will need to select the
type inletOutlet;
discretization schemes and linear solvers for this field.
inletValue uniform 0;
field s1; You will also need to define the boundary conditions value uniform 0;
and initial conditions for this field. }
}

//schemesField U; Option to use the same numerical scheme as the one


} used for the filed U
1262 1263

Scalar transport pluggable solver Scalar transport pluggable solver hands-on tutorials

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. • Scalar transport in an elbow – Internal geometry
• Remember, this is a bounded quantity so it is a good idea to use TVD schemes and
gradient limiters. • Let us run this case. Go to the directory:
System/fvSchemes System/fvSolution

gradSchemes s1 $PTOFC/advanced_physics/source_terms/2Delbow_passive_scalar
{ {
default Gauss linear; solver smoothSolver;
grad(s1) cellLimited Gauss linear 1; smoother symGaussSeidel;
} tolerance 1e-08;
relTol 0;
}
divSchemes • From this point on, please follow me.
{
default none; • We are all going to work at the same pace.
div(phi,U) Gauss linearUpwindV default;
div(phi,s1) Gauss vanLeer; • Remember, $PTOFC is pointing to the path where you
} unpacked the tutorials.
1264 1265
Scalar transport pluggable solver hands-on tutorials Scalar transport pluggable solver hands-on tutorials
Scalar transport in an elbow – Internal geometry Scalar transport in an elbow – Internal geometry
• Notice that we are adding two scalars, s1 and s2.
• At this point, we are ready to run the simulation.
• We will use the solver icoFoam.
• Remember to adjust the numerics according to your physics.
• Do not forget to create the boundary conditions and initial conditions of the
S1
U → (2 0 0) new field variables.
• You will find the instructions of how to run the cases in the file
README.FIRST located in the case directory.
http://www.wolfdynamics.com/training/sourceterms/image2.gif
S2
U → (0 3 0)

http://www.wolfdynamics.com/training/sourceterms/image3.gif 1266 1267

This is the end This is the end

That was only the tip of the iceberg


• 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.
• Select wisely the boundary conditions.

Now the rest is on you


1268 1269
This is the end This is the end
• We hope you have found this training useful and we hope to see you in one of our advanced

TGIF & TGIO


training sessions:
• OpenFOAM® – Multiphase flows
• OpenFOAM® – Naval applications

Enjoy OpenFOAM®
• OpenFOAM® – Turbulence Modeling
• OpenFOAM® – Computational heat transfer amd compressible flows
• OpenFOAM® – Advanced meshing
• OpenFOAM® – Basic programming
• Introduction to the Finite Volume Method
• 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/ 1270 1271

You might also like