Open Foam
Open Foam
Revision 1-2019
Joel Guerrero
Acknowledgements
This training material and tutorials are based upon personal experience, OpenFOAM® source
code, OpenFOAM® user guide, OpenFOAM® programmer’s guide, and presentations from
previous OpenFOAM® training sessions and OpenFOAM® workshops.
We gratefully acknowledge the following OpenFOAM® users for sharing online their material or for
giving us their consent to use their material:
1 #include <iostream>
2 using namespace std;
3
4 // main() is where program execution begins. It is the main function.
5 // Every program in c++ must have this main function declared
6
7 int main ()
8 {
9 cout << "Hello world"; //prints Hello world
10 return 0; //returns nothing
11 }
• To uncompress the tutorials go to the directory where you copied the training material and then type in the
terminal,
• $> tar –zxvf file_name.tar.gz
• In every single tutorial, you will find the file README.FIRST. In this file you will find the general instructions of
how to run the case. You will also find some additional comments.
• In some cases, you will also find additional files with the extension .sh. These files can be used to run the
case automatically, but we highly recommend to open the README.FIRST file and type the commands in the
terminal, in this way you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
• You will find the automatic scripts in the cases explained in the lectures notes and some random cases.
• A word of caution, use the tutorials included in the training material just for recreational, instructional,
or learning purposes and not for validation, benchmarking or as standard practices.
On the training material
Exercises
• At the end of each section, you will find an exercise section.
• The exercise section is optional, self-paced, and do it at anytime.
• The proposed exercises are designed to test your knowledge and to
reinforce the concepts addressed during the lectures.
• All the concepts to be addressed in the exercise sections have been treated
in the lecture notes, so the reader should not have problems answering the
questions.
• If you have doubts, do not hesitate in asking.
• To help you answering the exercises, we might give you a few tips.
• And if it is necessary, the solution will be given.
Training agenda
Module 0. Module 5.
• Training agenda • Sampling and plotting
• On the training material • Data conversion
• Housekeeping issues
• Additional information Module 6.
• The finite volume method. A crash introduction
Module 1. • On the CFL number
• Introduction to OpenFOAM® • Boundary conditions and initial conditions
• A few OpenFOAM® simulations • Unsteady and steady simulations
• Library organization • Assessing convergence
• OpenFOAM® 101 – My first tutorial • Velocity pressure-coupling
• Linear solvers
Module 2.
Module 7.
• Solid modeling for CFD
• Implementing boundary conditions and initial conditions using
codeStream
Module 3.
• Meshing preliminaries Module 8.
• Mesh quality assessment • Advanced modeling capabilities:
• Meshing in OpenFOAM® – blockMesh and snappyHexMesh • Turbulence modeling
• Mesh conversion and manipulation • Multiphase flows
• Compressible flows
Module 4. • Moving reference frames and sliding grids
• Running in parallel • Moving bodies and rigid body motion
• Source terms and passive scalars
Training agenda
• The training agenda is organized in such a way that we will address the whole CFD simulation workflow.
• The starting point of every CFD workflow is the geometry.
• Then we proceed to generate the mesh and assign the boundaries surface patches.
• After we have a valid mesh, we proceed to the case setup and we launch/monitor the simulation.
• At the end, we do the post-processing (quantitative and qualitative).
Module 1
OpenFOAM® overview – First tutorial –
Working our way in OpenFOAM®
1
Roadmap
2
OpenFOAM® brief overview
General description:
• OpenFOAM® stands for Open Source Field Operation and Manipulation.
• OpenFOAM® is first and foremost a C++ library used to solve partial
differential equations (PDEs), and ordinary differential equations (ODEs).
• It comes with several ready-to-use or out-of-the-box solvers, pre-processing
utilities, and post-processing utilities.
• It is licensed under the GNU General Public License (GPL). That means it is
freely available and distributed with the source code.
• It can be used in massively parallel computers. No need to pay for separate
licenses.
• It is under active development.
• It counts with a wide-spread community around the world (industry,
academia and research labs).
3
OpenFOAM® brief overview
Multi-physics simulation capabilities:
• OpenFOAM® has extensive multi-physics simulation capabilities, among
others:
• Computational fluid dynamics (incompressible and compressible flows).
• Computational heat transfer and conjugate heat transfer.
• Combustion and chemical reactions.
• Multiphase flows and mass transfer.
• Particle methods (DEM, DSMC, MD) and lagrangian particles tracking.
• Stress analysis and fluid-structure interaction.
• Rotating frames of reference, arbitrary mesh interface, dynamic mesh
handling, and adaptive mesh refinement.
• 6 DOF solvers, ODE solvers, computational aero-acoustics,
computational electromagnetics, computational solid mechanics, MHD.
4
OpenFOAM® brief overview
Physical modeling library:
• OpenFOAM® comes with many physical models, among others:
• Extensive turbulence modeling capabilities (RANS, DES and LES).
• Transport/rheology models. Newtonian and non-Newtonian viscosity
models.
• Thermophysical models and physical properties for liquids and gases.
• Source terms models.
• Lagrangian particle models.
• Interphase momentum transfer models for multiphase flows.
• Combustion, flame speed, chemical reactions, porous media, radiation,
phase change.
5
OpenFOAM® brief overview
Under the hood you will find the following:
• Finite Volume Method (FVM) based solver.
• Collocated polyhedral unstructured meshes.
• Second order accuracy in space and time. Many discretization schemes
available (including high order methods).
• Steady and transient solvers available.
• Pressure-velocity coupling via segregated methods (SIMPLE and PISO).
• But coupled solvers are under active development.
• Massive parallelism through domain decomposition.
• It comes with its own mesh generation tools.
• It also comes with many mesh manipulation and conversion utilities.
• It comes with many post-processing utilities.
• All components implemented in library form for easy re-use.
6
OpenFOAM® brief overview
OpenFOAM® vs. Commercial CFD applications:
• OpenFOAM® capabilities mirror those of commercial CFD applications.
• The main differences with commercial CFD applications are:
• There is no native GUI.
• It does not come with predefined setups. The users need to have a basic
understanding of the CFD basics and be familiar with OpenFOAM® command
line interface (CLI).
• Knowing your way around the Linux bash shell is extremely useful.
• It is not a single executable. Depending of what you are looking for, you will
need to execute a specific application from the CLI.
• It is not well documented, but the source code is available.
• Access to complete source = no black magic. But to understand the source
code you need to know object-oriented programming and C++.
• Solvers can be tailored for a specific need, therefore OpenFOAM® is ideal for
research and development.
• It is free and has no limitation on the number of cores you can use.
7
OpenFOAM® brief overview
Developing new solvers (in case you need it):
• As the user has complete access to the source code, 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.:
solve
(
fvm::ddt(T)
+ fvm::div(phi,T)
- fvm::laplacian(nu,T)
==
0
);
8
OpenFOAM® brief overview
9
Roadmap
10
OpenFOAM® directory organization
$WM_PROJECT_DIR If you installed OpenFOAM® in the default location, the
├── Allwmake directory the environment variable $WM_PROJECT_DIR
├── applications should point to the following directory (depending on the
installed version):
├── bin
├── COPYING
├── doc $HOME/OpenFOAM/OpenFOAM-6
├── etc or
├── platforms $HOME/OpenFOAM/OpenFOAM-dev
├── README.org
├── src In this directory you will find all the directories containing
├── tutorials OpenFOAM® installation.
└── wmake
In this directory you will also find additional files (such as
README.org, COPYING, etc.), but the most important
one is Allwmake, which compiles OpenFOAM®.
11
OpenFOAM® directory organization
$WM_PROJECT_DIR OpenFOAM® environment variables
├── Allwmake
├── applications The entries starting with the symbol $ are environment
├── bin variables. You can find out the value of an environment
├── COPYING variable by echoing its value, for example:
├── doc $> echo $WM_PROJECT_DIR
├── etc
├── platforms
will give you the following output on the terminal
├── README.org
$HOME/OpenFOAM/OpenFOAM-6
├── src
├── tutorials
└── wmake To list all the environment variables type in the terminal
window env
12
OpenFOAM® directory organization
$WM_PROJECT_DIR OpenFOAM® aliases
├── Allwmake
├── applications
You can go to any of these directories by using the
├── bin predefined aliases set by OpenFOAM® (see
├── COPYING $WM_PROJECT_DIR/etc/config/alias.sh). Just to
├── doc name a few of the aliases defined:
├── etc alias foam=‘cd $WM_PROJECT_DIR’
├── platforms alias app=‘cd $FOAM_APP’
├── README.org alias src=‘cd $FOAM_SRC’
├── src alias tut=‘cd $FOAM_TUTORIALS’
├── tutorials
└── wmake
For a complete list type alias in the terminal.
13
OpenFOAM® directory organization
$WM_PROJECT_DIR
├── Allwmake Let us study each directory inside
├── applications
├── bin $WM_PROJECT_DIR
├── COPYING
├── doc
├── etc
├── platforms
├── README.org • Any modification you add to the source code in
├── src WM_PROJECT_DIR will affect the whole library.
├── tutorials • Unless you know what are you doing, do not
└── wmake modify anything in the original installation
($WM_PROJECT_DIR), except for updates!
14
OpenFOAM® directory organization
The applications directory
$WM_PROJECT_DIR/applications
├── Allwmake
├── solvers
├── test
└── utilities
15
OpenFOAM® directory organization
The bin directory
$WM_PROJECT_DIR/bin/ Let us visit the bin directory:
├── foamCleanPolyMesh
• The bin directory contains many shell
├── foamCleanTutorials scripts, such as foamNew, foamLog,
├── foamCloneCase foamJob, foamNewApp, etc.
├── foamJob
├── foamLog • This directory also contains the script
paraFoam that will launch paraView.
├── foamMonitor
├── foamNew
├── foamNewApp
├── foamNewBC
├── foamNewFunctionObject
├── paraFoam
├── ...
└── tools
17
OpenFOAM® directory organization
The etc directory
$WM_PROJECT_DIR/etc/ Let us visit the etc directory:
├── bashrc
• The etc directory contains the environment
├── caseDicts
files, global OpenFOAM® instructions,
├── cellModels templates, and the default thermochemical
├── codeTemplates database thermoData/thermoData
├── config.csh
├── config.sh • It also contains the super dictionary
controlDict, where you can set several
├── controlDict debug flags and the defaults units.
├── cshrc
├── README.org
├── templates
└── thermoData
18
OpenFOAM® directory organization
The platforms directory
$WM_PROJECT_DIR/platforms/
├── linux64GccDPInt32Opt
│ ├── applications
│ ├── bin
│ ├── lib
│ └── src
└── linux64GccDPInt32OptSYSTEMOPENMPI
└── src
• If you want to locate a file inside $WM_PROJECT_DIR that contains the string fvPatch in its
name, you can proceed as follows,
• $> find $WM_PROJECT_DIR –type f -name “*fvPatch*”
• If you want to find a string inside a file, you can use the grep command.
• For example, if you want to find the string LES inside all the files within the directory
$FOAM_SOLVERS, you can proceed as follows,
• $> grep -r -n “LES” $FOAM_SOLVERS
The argument -r means recursive and -n will output the line number.
25
OpenFOAM® directory organization
Looking for information in OpenFOAM® source code
• Dictionaries are input files required by OpenFOAM®.
• As you can imagine, there are many dictionaries in OpenFOAM®. The easiest way to find all of
them is to do a local search in the installation directory as follows,
• For instance, if you are interested in finding all the files that end with the Dict word in the
tutorials directory, in the terminal type:
• $> find $FOAM_TUTORIALS -name “*Dict”
(Case sensitive search)
• $> find $FOAM_TUTORIALS –iname ‘*dict’
(Non-case sensitive search)
• When given the search string, you can use single quotes ‘ ’ or double-quotes “ ” (do not mixed
them).
• We recommend to use single quotes, but it is up to you.
26
OpenFOAM® directory organization
Looking for information in OpenFOAM® source code
• A few more advanced commands to find information in your OpenFOAM® installation.
• To find which tutorial files use the boundary condition slip:
• $> find $FOAM_TUTORIALS -type f | xargs grep -sl ‘ slip’
This command will look for all files inside the directory $FOAM_TUTORIALS, then the
output is used by grep to search for the string slip.
• To find where the source code for the boundary condition slip is located:
• $> find $FOAM_SRC -name “*slip*”
27
OpenFOAM® directory organization
Environment variables
• Remember, OpenFOAM® uses its own environment variables.
• OpenFOAM® environment settings are contained in the OpenFOAM-6/etc directory.
• If you installed OpenFOAM® in the default location, they should be in:
• $HOME/OpenFOAM/OpenFOAM-6/etc
• If you are running bash or ksh (if in doubt type in the terminal echo $SHELL), you sourced the
$WM_PROJECT_DIR/etc/bashrc file by adding the following line to your $HOME/.bashrc
file:
• source $HOME/OpenFOAM/OpenFOAM-6/etc/bashrc
28
Roadmap
29
Directory structure of an OpenFOAM® application/utility
32
Roadmap
33
Applications/utilities in OpenFOAM®
• OpenFOAM® is not a single executable.
• Depending of what you want to do, you will need to use a specific application and
there are many of them.
• If you are interested in knowing all the solvers, utilities, and libraries that come with
your OpenFOAM® distribution, read the applications and libraries section in the user
guide (chapter 3). In the directory $WM_PROJECT_DIR/doc you will find the
documentation in pdf format.
• You can also access the online user guide. Go to the link
http://cfd.direct/openfoam/user-guide/#contents, then go to chapter 3 (applications
and libraries).
• If you want to get help on how to run an application, type in terminal
• The option –help will not run the application, it will only show all the options
available.
• You can also get all the help you want from the source code.
34
Applications/utilities in OpenFOAM®
• You will find all the applications in the directory $FOAM_SOLVERS (use alias sol to
go there).
• You will find all the utilities in the directory $FOAM_UTILITIES (use alias util to go
there).
• For example, in the directory $FOAM_SOLVERS, you will find the directories containing
the source code for the solvers available in the OpenFOAM® installation (version 6):
• basic • financial
• combustion • heatTransfer
• compressible • incompressible
• discreteMethods • lagrangian
• DNS • multiphase
• electromagnetics • stressAnalysis
• adjointShapeOptimizationFoam • pimpleFoam
• boundaryFoam • pisoFoam
• icoFoam • shallowWaterFoam
• nonNewtonianIcoFoam • simpleFoam
• Inside each directory, you will find a file with the extension *.C and the same name
as the directory. This is the main file, where you will find the top-level source code
and a short description of the solver or utility.
• For example, in the file incompressible/icoFoam/icoFoam.C you will find the
following description:
36
Applications/utilities in OpenFOAM®
• Remember, OpenFOAM® is not a single executable.
• You will need to find the solver or utility that best fit what you want to do.
• A few solvers that we will use during this course:
• icoFOAM: laminar incompressible unsteady solver.
• simpleFOAM: incompressible steady solver for laminar/turbulent flows.
• pimpleFOAM: incompressible unsteady solver for laminar/turbulent flows.
• rhoSimpleFoam: compressible steady solver for laminar/turbulent flows.
• sonicFoam: unsteady compressible solver for high-speed flows (laminar/turbulent flows).
• interFoam: unsteady multiphase solver for separated flows using the VOF method
(laminar and turbulent flows).
• laplacianFoam: Laplace equation solver.
• potentialFoam: potential flow solver.
• scalarTransportFoam: steady/unsteady general transport equation solver.
• Take your time and explore the source code.
• Also, while exploring the source code be careful not to add unwanted modifications in the
original installation.
• If you modify the source code, be sure to do the modifications in your user directory instead of
the main source code. 37
Roadmap
38
Directory structure of an OpenFOAM® case
Directory structure of a general case
case_name • OpenFOAM® uses a very particular directory
├── 0 structure for running cases.
│ ├── p • You should always follow the directory structure,
│ └── U otherwise, OpenFOAM® will complain.
├── constant • To keep everything in order, the case directory is
│ ├── polyMesh often located in the path
$WM_PROJECT_USER_DIR/run.
│ │ ├── boundary
│ │ ├── faces • This is not compulsory but highly advisable. You can
copy the case files anywhere you want.
│ │ ├── neighbour
• The name of the case is given by the user (do not
│ │ ├── owner use white spaces or strange symbols).
│ │ └── points
• Depending of the solver or application you would like
│ └── transportProperties to use, you will need different files in each sub-
├── system directory.
│ ├── controlDict • Remember, you always run the applications and
│ ├── fvSchemes utilities in the top level of the case directory (the
│ └── fvSolution directory with the name case_name). Not in the
directory system, not in the directory constant, not
└── time_directories in the directory 0.
39
Directory structure of an OpenFOAM® case
Directory structure of a general case
case_name case_name: the name of the case is given by the user
├── 0 (do not use white spaces or strange symbols). This is
│ ├── p the top-level directory, where you run the applications
and utilities.
│ └── U
system: contains run-time control and solver
├── constant numerics.
│ ├── polyMesh
constant: contains physical properties,
│ │ ├── boundary turbulence modeling properties, advanced physics
│ │ ├── faces and so on.
│ │ ├── neighbour constant/polyMesh: contains the
│ │ ├── owner polyhedral mesh information.
│ │ └── points 0: contains boundary conditions (BC) and initial
│ └── transportProperties conditions (IC).
├── system time_directories: contains the solution and
│ ├── controlDict derived fields. These directories are created by the
solver automatically and according to the preset
│ ├── fvSchemes
saving frequency, e.g., 1, 2, 3, 4, … , 100.
│ └── fvSolution
└── time_directories
40
Roadmap
41
Running my first OpenFOAM® case setup blindfold
Before we start – Always remember the directory structure
case_name
├── 0
├── constant
│ └── polyMesh
├── system
└── time_directories
• To keep everything in order, the case directory is often located in the path
$WM_PROJECT_USER_DIR/run.
• This is not compulsory but highly advisable, you can put the case in any directory of your preference.
• The name of the case directory if given by the user (do not use white spaces).
• You run the applications and utilities in the top level of this directory.
• The directory system contains run-time control and solver numerics.
• The directory constant contains physical properties, turbulence modeling properties, advanced physics
and so on.
• The directory constant/polyMesh contains the polyhedral mesh information.
• The directory 0 contains boundary conditions (BC) and initial conditions (IC).
42
Running my first OpenFOAM® case setup blindfold
Before we start – Setting OpenFOAM® cases
• As you will see, it is quite difficult to remember all the dictionary files needed to run
each application.
• It is even more difficult to recall the compulsory and optional entries of each input file.
• When setting a case from scratch in OpenFOAM®, what you need to do is find a
tutorial or a case that close enough does what you want to do and then you can adapt
it to your physics.
• Having this in mind, you have two sources of information:
• $WM_PROJECT_DIR/tutorials
(The tutorials distributed with OpenFOAM®)
• $PTOFC
(The tutorials used during this training)
• If you use a GUI, things are much easier. However, OpenFOAM® does not come
with a native GUI interface.
• We are going to do things in the hard way (and maybe the smart way), we are going
to use the Linux terminal
43
Running my first OpenFOAM® case setup blindfold
Flow in a lid-driven square cavity – Re = 100
Incompressible flow
44
Running my first OpenFOAM® case setup blindfold
Workflow of the case
blockMesh
icoFoam functionObjects
sampling paraview
45
Running my first OpenFOAM® case setup blindfold
At the end of the day, you should get something like this
High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 47
Running my first OpenFOAM® case setup blindfold
$PTOFC/101OF/cavity2D
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
48
Running my first OpenFOAM® case setup blindfold
Loading OpenFOAM® environment
• If you are using the lab workstations, you will need to source OpenFOAM® (load
OpenFOAM® environment).
• To use PyFoam (a plotting utility) you will need to source it. Type in the terminal:
• $> anaconda3
• Remember, every time you open a new terminal window you need to source
OpenFOAM® and PyFoam.
• Also, you might need to load OpenFOAM® again after loading PyFoam.
• By default, when installing OpenFOAM® and PyFoam you do not need to do this.
This is our choice as we have many things installed and we want to avoid conflicts
between applications.
49
Running my first OpenFOAM® case setup blindfold
What are we going to do?
• We will use the lid-driven square cavity tutorial as a general example to show you how to set up
and run solvers and utilities in OpenFOAM®.
• In this tutorial we are going to generate the mesh using blockMesh.
• After generating the mesh, we will look for topological errors and assess the mesh quality. For
this we use the utility checkMesh. Later on, we are going to talk about what is a good mesh.
• Then, we will find the numerical solution using icoFoam, which is a transient solver for
incompressible, laminar flow of Newtonian fluids. By the way, we hope you did not forget where
to look for this information.
• And we will finish with some quantitative post-processing and qualitative visualization using
paraFoam and OpenFOAM® utilities.
• While we run this case, we are going to see a lot of information on the screen (standard output
stream or stdout), but it will not be saved. This information is mainly related to convergence of
the simulation, we will talk about this later on.
• A final word, we are going to use the solver icoFoam but have in mind that this is a very basic
solver with no modeling capabilities and limited post-processing features.
• Therefore, is better to use pisoFoam or pimpleFoam which are equivalent to icoFoam but
with many more features.
50
Running my first OpenFOAM® case setup blindfold
Running the case blindfold
• Let us run this case blindfold.
• Later we will study in details each file and directory.
• Remember, the variable $PTOFC is pointing to the path where you unpacked the
tutorials.
• You can create this environment variable or write down the path to the directory.
• In the terminal window type:
1. $> cd $PTOFC/101OF/cavity
2. $> ls –l
3. $> blockMesh
4. $> checkMesh
5. $> icoFoam
6. $> postProcess -func sampleDict -latestTime
7. $> gnuplot gnuplot/gnuplot_script
8. $> paraFoam
51
Running my first OpenFOAM® case setup blindfold
Running the case blindfold
• In step 1 we go to the case directory. Remember, $PTOFC is pointing to the path where you
unpacked the tutorials.
• In step 2 we just list the directory structure (this step is optional). Does it look familiar to you? In
the directory 0 you will the initial and boundary conditions, in the constant directory you will
find the mesh information and physical properties, and in the directory system you will find the
dictionaries that controls the numerics, runtime parameters and sampling.
• In step 3 we generate the mesh.
• In step 4 we check the mesh quality. We are going to address how to assess mesh quality later
on.
• In step 5 we run the simulation. This will show a lot information on the screen, the standard
output stream will not be saved.
• In step 6 we use the utility postProcess to do some sampling only of the last saved solution
(the latestTime flag). This utility will read the dictionary file named sampleDict located in
the directory system.
• In step 7 we use a gnuplot script to plot the sampled values. Feel free to take a look and reuse
this script.
• Finally, in step 8 we visualize the solution using paraFoam. In the next slides we are going to
briefly explore this application.
52
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam
Menu Bar
Toolbars
Pipeline Browser
Properties panel
Apply button
Press this button to
load the case or to
apply a filter
3D View/Canvas
Advanced Toggle
53
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Toolbars
• Main Controls
• Representation Toolbar
• Common Filters
55
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – 3D View and mouse interaction
Select view orientation in the Camera Controls
Rotate
Zoom
Pan
Zoom
3D View/Canvas
56
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Fields visualization
Select Last Frame in the VCR Controls Current Time Controls
57
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters
• Filters are functions that generate, extract or derive features from the input data.
• They are attached to the input data.
• You can access the most commonly used filters from the Common Filters toolbar
• You can access all the filters from the menu Filter.
58
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters
59
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Slice filter
4. Press Apply
60
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Glyph filter
4. Color the colors using Solid Color
1. Select the Glyph filter. This
filter will be applied on the
Slice1 filter
3. Press Apply
2. Filter options
61
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Plot Over Line filter
1.a. Select the Plot Over Line
filter.
(0.5, 1, 1)
3. Press Apply
(0.5, 0, 1)
2. Enter the coordinates of the line
Line
62
Running my first OpenFOAM® case setup blindfold
Crash introduction to paraFoam – Filters
4. Optional – Use the VCR Control to change the frame.
The line chart view will be updated automatically
1. Click on the line chart view (the blue frame indicates that it is the active view)
63
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• In the previous case, we ran the simulation but we did not save the standard output
stream (stdout) in a log file.
• Our advice is to always save the standard output stream (stdout) in a log file.
• It is of interest to always save the log as if something goes wrong and you would like
to do troubleshooting, you will need this information.
• Also, if you are interested in plotting the residuals you will need the log file.
• By the way, if at any point you ask us what went wrong with your simulation, it is likely
that we will ask you for this file.
64
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• There are many ways to save the log files.
• From now on, we will use the Linux tee command to save log files.
• To save a log file of the simulation or the output of any utility, you can proceed as
follows:
1. $> foamCleanTutorials
2. $> blockMesh | tee log.blockMesh
3. $> checkMesh | tee log.checkMesh
4. $> icoFoam | tee log.icoFoam
• You can use your favorite text editor to read the log file (e.g., gedit, vi, emacs).
65
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• In step 1 we erase the mesh and all the folders, except for 0, constant and system. This
script comes with your OpenFOAM® installation.
• In step 2, we generate the mesh using the meshing tool blockMesh. We also redirect the
standard output to an ascii file with the name log.blockMesh (it can be any name). The tee
command will redirect the screen output to the file log.blockMesh and at the same time will
show you the information on the screen.
• In step 3 we check the mesh quality. We also redirect the standard output to an ascii file with the
name log.checkMesh (it can be any name).
• In step 4 we run the simulation. We also redirect the standard output to an ascii file with the
name log.icoFoam (it can be any name). Remember, the tee command will redirect the
screen output to the file log.icoFoam and at the same time will show you the information on
the screen.
• To postprocess the information contained in the solver log file log.icoFoam, we can use the
utility foamLog. Type in the terminal:
• $> foamLog log.icoFoam
• This utility will extract the information inside the file log.icoFoam. The extracted information is
saved in an editable/plottable format in the directory logs.
• At this point we can use gnuplot to plot the residuals. Type in the terminal:
• $> gnuplot 66
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• To plot the information extracted with foamLog using gnuplot, we can proceed as
follows (remember, at this point we are using the gnuplot prompt):
1. gnuplot> set logscale y
Set log scale in the y axis
3. gnuplot> plot ‘logs/p_0’ using 1:2 with lines, ‘logs/pFinalRes_0’ using 1:2 with lines
Here we are plotting to different files. You can concatenate files using comma (,)
4. gnuplot> reset
To reset the scales
7. gnuplot> plot [30:50][] ‘logs/Ux_0’ u 1:2 w l title ‘Ux’,‘logs/Uy_0’ u 1:2 w l title ‘Uy’
Set the x range from 30 to 50 and plot tow files and set legend titles
8. gnuplot> exit
To exit gnuplot
67
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files
• The output of step 3 is the following:
• The fact that the initial residuals (red line) are dropping to the same value of the final
residuals (monotonic convergence), is a clear indication of a steady behavior.
68
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files and plotting the residuals
• It is also possible to plot the log information on the fly.
• The easiest way to do this is by using PyFoam (you will need to install it):
• $> pyFoamPlotRunner.py [options] <foamApplication>
• If you are using the lab workstations, you will need to source PyFoam. To source PyFoam, type in the
terminal:
• $> anaconda3
• If you need help or want to know all the options available,
• $> pyFoamPlotRunner.py –-help
• To run this case with pyFoamPlotRunner.py, in the terminal type:
• $> pyFoamPlotRunner.py icoFoam
• If you do not feel comfortable using pyFoamPlotRunner.py to run the solver, it is also possible to plot the
information saved in the log file using PyFoam.
• To do so you will need to use the utility pyFoamPlotWatcher.py. For example,
• $> icoFoam | tee log.icoFoam
• Then, in a new terminal window launch pyFoamPlotWatcher, as follows,
• $> pyFoamPlotWatcher.py log.icoFoam
• You can also use pyFoamPlotWatcher.py to plot the information saved in an old log file.
69
Running my first OpenFOAM® case setup blindfold
Running the case blindfold with log files and plotting the residuals
• This is a screenshot on my computer. In this case, pyFoamPlotRunner is plotting
the initial residuals and continuity errors on the fly.
70
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• Your simulation will automatically stop at the time value you set using the keyword endTime in
the controlDict dictionary.
endTime 50;
• If for any reason you want to stop your simulation before reaching the value set by the keyword
endTime, you can change this value to a number lower than the current simulation time (you
can use 0 for instance). This will stop your simulation, but it will not save your last time-step or
iteration, so be careful.
1 /*--------------------------------*- C++ -*----------------------------------*\
2 | ========= | |
3 | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
4 | \\ / O peration | Version: 6.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 }
15 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
16
17 application icoFoam;
18
19 startFrom startTime;
20
21 startTime 0;
22
23 stopAt endTime;
24
25 endTime 50;
71
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• If you want to stop the simulation and save the solution, in the controlDict dictionary made
the following modification,
stopAt writeNow;
This will stop your simulation and will save the current time-step or iteration.
72
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• The previous modifications can be done on-the-fly, but you will need to set the
keyword runTimeModifiable to true in the controlDict dictionary.
• By setting the keyword runTimeModifiable to true, you will be able to modify most of
the dictionaries on-the-fly.
44
45 runTimeModifiable true;
46
73
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• You can also kill the process. For instance, if you did not launch the solver in background, go to its terminal
window and press ctrl-c. This will stop your simulation, but it will not save your last time-step or iteration, so
be careful.
• If you launched the solver in background, just identify the process id using top or htop (or any other process
manager) and terminate the associated process. Again, this will not save your last time-step or iteration.
• To identify the process id of the OpenFOAM® solver or utility, just read screen. At the beginning of the output
screen, you will find the process id number.
/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 6.x |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 4.x-e964d879e2b3
Exec : icoFoam
Date : Mar 11 2017
Time : 23:21:50
Host : "linux-ifxc"
PID : 3100 Process id number
Case : /home/joegi/my_cases_course/5x/101OF/cavity
nProcs : 1
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
74
Running my first OpenFOAM® case setup blindfold
Stopping the simulation
• When working locally, we usually proceed in this way:
This will run the solver icoFoam (by the way, this works for any solver or utility), it will save the
standard output stream in the file log.icofoam and will show the solver output on the fly.
• If at any moment we want to stop the simulation, and we are not interested in saving the last
time-step, we press ctrl-c.
• If we are interested in saving the last time step, we modify the controlDict dictionary and
add the following keyword
stopAt writeNow;
• Remember, this modification can be done on the fly. However, you will need to set the keyword
runTimeModifiable to yes in the controlDict dictionary.
75
Running my first OpenFOAM® case setup blindfold
Cleaning the case folder
• If you want to erase the mesh and the solution in the current case folder, you can type in the
terminal,
$> foamCleanTutorials
If you are running in parallel, this will also erase the processorN directories. We will talk about
running in parallel later.
• If you are looking to only erase the mesh, you can type in the terminal,
$> foamCleanPolyMesh
• If you are only interested in erasing the saved solutions, in the terminal type,
$> foamListTimes -rm
• If you are running in parallel and you want to erase the solution saved in the processorN
directories, type in the terminal,
$> foamListTimes –rm -processor
76
Roadmap
77
A deeper view to my first OpenFOAM® case setup
• We will take a close look at what we did by looking at the case files.
• The case directory originally contains the following sub-directories: 0, constant, and
system. After running icoFoam it also contains the time step directories 1, 2, 3,
..., 48, 49, 50, the post-processing directory postProcessing, and the
log.icoFoam file (if you chose to redirect the standard output stream).
• The time step directories contain the values of all the variables at those time
steps (the solution). The 0 directory is thus the initial condition and boundary
conditions.
• The constant directory contains the mesh and dictionaries for thermophysical,
turbulence models and advanced physical models.
• The system directory contains settings for the run, discretization schemes and
solution procedures.
• The postProcessing directory contains the information related to the
functionObjects (we are going to address functionObjects later).
• The icoFoam solver reads these files and runs the case according to those
settings.
78
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.
79
A deeper view to my first OpenFOAM® case setup
80
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)
• In this directory you will find the sub-directory polyMesh and the dictionary file
transportProperties.
• The transportProperties file is a dictionary for the dimensioned scalar nu, or the
kinematic viscosity.
1 Mass Kilogram kg
2 Length meters m
3 Time second s
4 Temperature Kelvin K
6 Current ampere A
82
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)
17 nu nu [ 0 2 -1 0 0 0 0 ] 0.01;
[ 0 m^2 s^-1 0 0 0 0 ]
Which is equivalent to
83
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)
• In this case, as we are working with an incompressible flow, we only need to define
the kinematic viscosity.
• Later on, we will ask you to change the Reynolds number, to do so you can change
the value of nu. Remember,
• You can also change the free stream velocity U or the reference length L.
84
A deeper view to my first OpenFOAM® case setup
The constant directory
(and by the way, open each file and go thru its content)
• Depending on the physics involved and models used, you will need to define more
variables in the dictionary transportProperties.
• For instance, for a multiphase case you will need to define the density rho and
kinematic viscosity nu for each single phase. You will also need to define the surface
tension .
• Also, depending of your physical model, you will find more dictionaries in the constant
directory.
• For example, if you need to set gravity, you will need to create the dictionary g.
• If you work with compressible flows you will need to define the dynamic viscosity mu,
and many other physical properties in the dictionary thermophysicalProperties.
• As we are not dealing with compressible flows (for the moment), we are not going into
details.
85
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh directory
(and by the way, open each file and go thru its content)
• In this case, the polyMesh directory is initially empty. After generating the mesh, it
will contain the mesh in OpenFOAM® format.
• To generate the mesh in this case, we use the utility blockMesh. This utility reads
the dictionary blockMeshDict located in the system folder.
• We will briefly address a few important inputs of the blockMeshDict dictionary.
• Do not worry, we are going to revisit this dictionary during the meshing session.
• However, have in mind that rarely you will use this utility to generate a mesh for
complex geometries.
• Go to the directory system and open blockMeshDict dictionary with your favorite
text editor, we will use gedit.
86
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary
• The blockMeshDict dictionary first defines a list with a number of vertices:
• The keyword convertToMeters (line 17), is a scaling factor. In this case
17 convertToMeters 1;
18
we do not scale the dimensions.
19 xmin 0;
20 xmax 1; • In the section vertices (lines 37-58), we define the vertices coordinates of
21 ymin 0; the geometry. In this case, there are eight vertices defining the geometry.
22 ymax 1;
23 zmin 0;
OpenFOAM® always uses 3D meshes, even if the simulation is 2D.
24 zmax 1;
25 • We can directly define the vertex coordinates in the section vertices
26 xcells 20; (commented lines 49-56), or we can use macro syntax.
27 ycells 20;
28 zcells 1; • Using macro syntax we first define a variable and its value (lines 19-24),
29
37 vertices and then we can use them by adding the symbol $ to the variable name
38 ( (lines 39-46).
39 ($xmin $ymin $zmin) //vertex 0
40 ($xmax $ymin $zmin) //vertex 1 • In lines 26-28, we define a set of variables that will be used at a later time.
41 ($xmax $ymax $zmin) //vertex 2
42 ($xmin $ymax $zmin) //vertex 3 These variables are related to the number of cells in each direction.
43 ($xmin $ymin $zmax) //vertex 4
44 ($xmax $ymin $zmax) //vertex 5 • Finally, notice that the vertex numbering starts from 0 (as the counters in
45 ($xmax $ymax $zmax) //vertex 6 c++). This numbering applies for blocks as well.
46 ($xmin $ymax $zmax) //vertex 7
47
48 /*
49 (0 0 0)
50 (1 0 0)
51 (1 1 0)
52 (0 1 0)
53 (0 0 0.1)
54 (1 0 0.1)
55 (1 1 0.1)
56 (0 1 0.1)
57 */
58 );
87
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary
• The blockMeshDict dictionary also defines the boundary patches:
• To sum up, the blockMeshDict dictionary generates in this case a single block with:
• X/Y/Z dimensions: 1.0/1.0/1.0
• Cells in the X, Y and Z directions: 20 x 20 x 1 cells.
• One single hex block with straight lines.
• Patch type wall and patch name fixedWalls at three sides.
• Patch type wall and patch name movingWall at one side.
• Patch type empty and patch name frontAndBack patch at two sides.
• If you are interested in visualizing the actual block topology, you can use paraFoam
as follows,
• $> paraFoam –block
89
A deeper view to my first OpenFOAM® case setup
The system/blockMeshDict dictionary
90
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
• First of all, this file is automatically generated after you create the mesh
using blockMesh or snappyHexMesh, or when you convert the mesh from
a third-party format.
• In this file, the geometrical information related to the base type patch of
each boundary (or surface patch) of the domain is specified.
• The base type boundary condition is the actual surface patch where we are
going to apply a numerical type boundary condition (or numerical boundary
condition).
• The numerical type boundary condition assign a field value to the surface
patch (base type).
• We define the numerical type patch (or the value of the boundary
condition), in the directory 0 or time directories.
91
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
fixedWall
fixedWall
34 frontAndBack
35 {
36 type empty;
37 inGroups 1(empty);
38 nFaces 800;
39 startFace 840;
40 }
41 )
frontAndBack
fixedWall
92
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
18 3
19 ( Name and type of the surface patches
20 movingWall Name
21 {
22 type wall; Type • The name and type of the patch is given by
23 inGroups 1(wall);
24 nFaces 20; the user.
25 startFace 760;
26 } • In this case the name and type was assigned
27 fixedWalls in the dictionary blockMeshDict.
28 {
29 type wall; • You can change the name if you do not like it.
30 inGroups 1(wall);
31 nFaces 60; Do not use strange symbols or white spaces.
32 startFace 780;
33 } • You can also change the base type. For
34 frontAndBack instance, you can change the type of the
35 {
36 type empty;
patch movingWall from wall to patch.
37 inGroups 1(empty);
38 nFaces 800;
• When converting the mesh from a third party
39 startFace 840; format, OpenFOAM® will try to recover the
40 } information from the original format. But it
41 )
might happen that it does not recognizes the
base type and name of the original file. In this
case you will need to modify this file manually.
93
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
18 3 inGroups keyword
19 ( • This keyword is optional. You can erase this information safely.
20 movingWall
21 { • It is used to group patches during visualization in
22 type wall; ParaView/paraFoam. If you open this mesh in paraFoam you will
23 inGroups 1(wall); see that there are two groups, namely: wall and empty.
24 nFaces 20;
25 startFace 760; • As usual, you can change the name.
26 } • If you want to put a surface patch in two groups, you can proceed
27 fixedWalls
as follows:
28 {
29 type wall; 2(wall wall1)
30 inGroups 1(wall);
31 nFaces 60;
In this case the surface patch belongs to the groups wall and
32 startFace 780; wall1.
33 } • Groups can have more than one patch.
34 frontAndBack
35 {
36 type empty; nFaces and startFace keywords
37 inGroups 1(empty);
38 nFaces 800; • Unless you know what you are doing, you do not need to
39 startFace 840; modify this information.
40 }
41 ) • This information is related to the starting face and ending face of
the boundary patch in the mesh data structure.
• This information is created automatically when generating the
mesh or converting the mesh.
94
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
• There are a few base type patches that are constrained or paired. This means that the type
should be the same in the boundary file and in the numerical boundary condition defined in the
field files, e.g., the files 0/U and 0/p.
• In this case, the base type of the patch frontAndBack (defined in the file boundary), is
consistent with the numerical type patch defined in the field files 0/U and 0/p. They are of
the type empty.
• Also, the base type of the patches movingWall and fixedWalls (defined in the file boundary),
is consistent with the numerical type patch defined in the field files 0/U and 0/p.
• This is extremely important, especially if you are converting meshes as not always the type of
the patches is set as you would like.
• Hence, it is highly advisable to do a sanity check and verify that the base type of the patches
(the type defined in the file boundary), is consistent with the numerical type of the patches
(the patch type defined in the field files contained in the directory 0 (or whatever time directory
you defined the boundary and initial conditions).
• If the base type and numerical type boundary conditions are not consistent, OpenFOAM® will
complain.
• Do not worry, we are going to address boundary conditions later on.
95
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
symmetry symmetry
symmetryPlane symmetryPlane
empty empty
wedge wedge
cyclic cyclic
processor processor
96
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
• The base type patch can be any of the numerical or derived type
boundary conditions available in OpenFOAM®. Mathematically speaking;
they can be Dirichlet, Neumann or Robin boundary conditions.
fixedValue
zeroGradient
inletOutlet
slip
patch
totalPressure
supersonicFreeStream
and so on …
Refer to the doxygen documentation for a list of all numerical
type boundary conditions available.
97
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
type fixedValue;
wall zeroGradient
value uniform (U V W);
• This boundary condition is not contained in the patch base type boundary
condition group, because specialize modeling options can be used on this
boundary condition.
• An example is turbulence modeling, where turbulence can be generated or
dissipated at the walls.
98
A deeper view to my first OpenFOAM® case setup
The constant/polyMesh/boundary dictionary
• The name of the base type boundary condition and the name of the
numerical type boundary condition needs to be the same, if not,
OpenFOAM® will complain.
• Pay attention to this, specially if you are converting the mesh from another
format.
• As you can see, all the names are the same across all the dictionary files.
99
A deeper view to my first OpenFOAM® case setup
The system directory
(and by the way, open each file and go thru its content)
101
A deeper view to my first OpenFOAM® case setup
The controlDict dictionary
• So how do we know what options are available for each keyword?
• The hard way is to refer to the source code.
• The easy way is to use the banana method.
17 application icoFoam;
18 • So what is the banana method? This method consist in inserting a dummy word
19 startFrom startTime;
20
(that does not exist in the installation) and let OpenFOAM® list the available
21 startTime 0; options.
22
23 stopAt banana; • For example. If you add banana in line 23, you will get this output:
24
25 endTime 50;
banana is not in enumeration
26 4
27 deltaT 0.01;
28 (
29 writeControl runTime;
30 nextWrite
31 writeInterval 1;
32 writeNow
33 purgeWrite 0;
34
noWriteNow
35 writeFormat ascii; endTime
36
37 writePrecision 8; )
38
39 writeCompression off; • So your options are nextWrite, writeNow, noWriteNow, endTime
40
41 timeFormat general; • And how do we know that banana does not exist in the source code? Just type in
42 the terminal:
43 timePrecision 6;
44 • $> src
45 runTimeModifiable true;
• $> grep –r –n banana .
• If you see some bananas in your output someone is messing around with your
installation.
• Remember, you can use any dummy word, but you have to be sure that it does
not exist in OpenFOAM®.
102
A deeper view to my first OpenFOAM® case setup
The controlDict dictionary
103
A deeper view to my first OpenFOAM® case setup
The fvSchemes dictionary
17 solvers
• The fvSolution dictionary contains the instructions of how
18 { to solve each discretized linear equation system. The equation
19 p
20 { solvers, tolerances, and algorithms are controlled from the sub-
21 solver PCG;
22 preconditioner DIC;
dictionary solvers.
23 tolerance 1e-06;
24 relTol 0; • In the dictionary file fvSolution (and depending on the solver
39 }
you are using), you will find the additional sub-dictionaries
40 PISO, PIMPLE, SIMPLE, and relaxationFactors. These
41 pFinal
42 { entries will be described later.
43 $p;
44 relTol 0; • As for the controlDict and fvSchemes dictionaries, the
45 }
46 parameters can be changed on-the-fly.
47 U
48 { • Also, if you want to know what options are available just use
49 solver smoothSolver;
50 smoother symGaussSeidel; the banana method.
51 tolerance 1e-08;
52 relTol 0; • In this case, to solve the pressure (p) we are using the PCG
53 }
54 } method, with the preconditioner DIC, an absolute tolerance
55
56 PISO
equal to 1e-06 and a relative tolerance relTol equal to 0.
57 {
58 nCorrectors 1; • The entry pFinal refers to the final pressure correction (notice
59 nNonOrthogonalCorrectors 0;
60 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
62 }
effort in the last iteration.
105
A deeper view to my first OpenFOAM® case setup
The fvSolution dictionary
17 solvers
• To solve U we are using the smoothSolver method, with the
18 { smoother symGaussSeidel, an absolute tolerance equal to
19 p
20 { 1e-08 and a relative tolerance relTol equal to 0.
21 solver PCG;
22 preconditioner DIC; • The solvers will iterative until reaching any of the tolerance
23 tolerance 1e-06;
24 relTol 0; values set by the user or reaching a maximum value of
39 }
iterations (optional entry).
40
41 pFinal • FYI, solving for the velocity is relative inexpensive, whereas
42 {
43 $p;
solving for the pressure is expensive.
44 relTol 0;
45 } • The PISO sub-dictionary contains entries related to the
46
47 U
pressure-velocity coupling method (the PISO method).
48 {
49 solver smoothSolver; • In this case we are doing only one PISO correction and no
50 smoother symGaussSeidel;
51 tolerance 1e-08;
orthogonal corrections.
52 relTol 0;
53 } • You need to do at least one PISO loop (nCorrectors).
54 }
55
56 PISO
57 {
58 nCorrectors 1;
59 nNonOrthogonalCorrectors 0;
60 pRefCell 0;
61 pRefValue 0;
62 }
106
A deeper view to my first OpenFOAM® case setup
The system directory
(optional dictionary files)
• In the system directory you will also find these two additional files:
• decomposeParDict
• sampleDict
107
A deeper view to my first OpenFOAM® case setup
The sampleDict dictionary
Type of sampling, sets will sample along a line.
Format of the output file, raw format is a generic format
17 type sets; that can be read by many applications. The output file is
18
19 setFormat raw;
human readable (ascii format).
20
23 interpolationScheme cellPointFace; Interpolation method at the solution level (location of the
24
26 fields interpolation points).
27 (
28 U Fields to sample.
29 );
30
31 sets
32 (
33 Sample method. How to interpolate the solution to the
34 l1
35 {
sample entity (line in this case)
38 type lineFace;
43 axis x;
44 start ( -1 0.5 0); Location of the sample line. We define start and end
45 end ( 2 0.5 0); point, and the axis of the sampling.
46 }
47
48 l2
49 {
52 type lineFace; Sample method from the solution to the line.
57 axis y;
58 start (0.5 -1 0);
59 end (0.5 2 0);
60 }
61
62 );
Location of the sample line. We define start and end
point, and the axis of the sampling.
108
A deeper view to my first OpenFOAM® case setup
The sampleDict dictionary
• 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):
110
A deeper view to my first OpenFOAM® case setup
The 0 directory
(and by the way, open each file and go thru its content)
• The 0 directory contains the initial and boundary conditions for all primitive variables,
in this case p and U. The U file contains the following information (velocity):
• 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):
112
A deeper view to my first OpenFOAM® case setup
The 0 directory
(and by the way, open each file and go thru its content)
• The 0 directory contains the initial and boundary conditions for all primitive variables,
in this case p and U. The p file contains the following information (modified pressure):
113
A deeper view to my first OpenFOAM® case setup
with units
114
A deeper view to my first OpenFOAM® case setup
• Coming back to the headers, and specifically the headers related to the field variable
dictionaries (e.g. U, p, gradU, and so on).
• In the header of the field variables, the class type should be consistent with the type
of field variable you are using.
• Be careful with this, specially if you are copying and pasting files.
• If the field variable is a scalar, the class should be volScalarField.
115
A deeper view to my first OpenFOAM® case setup
• If the field variable is a vector, the class should be volVectorField.
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 6.x |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
object U;
}
• If the field variable is a tensor (e.g. the velocity gradient tensor), the class should be
volTensorField.
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 6.x |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volTensorField;
object gradU;
} 116
A deeper view to my first OpenFOAM® case setup
The output screen
• Finally, let us talk about the output screen, which shows a lot of information.
Velocity residuals
Simulation time
Courant number
Pressure residuals
No orthogonal corrections
Only one PISO correction
Execution time (wall time)
Continuity errors
Additional information
End of the simulation Minimum and maximum values of each field
117
A deeper view to my first OpenFOAM® case setup
The output screen
• By default, OpenFOAM® does not show the minimum and maximum information. To print out this information,
we use functionObjects. We are going to address functionObjects in detail when we deal with post-
processing and sampling.
• But for the moment, what we need to know is that we add functionObjects at the end of the controlDict
dictionary. In this case, we are using a functionObject that prints the minimum and maximum information of
the selected fields.
• This information complements the residuals information and it is saved in the postProcessing directory. It
gives a better indication of stability, boundedness and consistency of the solution.
49 functions
50 {
51 Name of the folder where the output of
52 /////////////////////////////////////////////////////////////////////////// the functionObject will be saved
53
54 minmaxdomain
55 {
56 type fieldMinMax; functionObject to use
57
58 functionObjectLibs ("libfieldFunctionObjects.so");
59
60 enabled true; //true or false Turn on/off functionObject
61
62 mode component;
63
64 writeControl timeStep;
65 writeInterval 1; Output interval of functionObject
66
67 log true; Save output of the functionObject in a ascii file
68
69 fields (p U); Field variables to sample
70 }
91
92 };
118
A deeper view to my first OpenFOAM® case setup
The output screen
• Another very important output information is the CFL or Courant number.
• The Courant number imposes the CFL number condition, which is the maximum allowable
CFL number a numerical scheme can use. For the n - dimensional case, the CFL number
condition becomes,
• In OpenFOAM®, most of the solvers are implicit, which means they are unconditionally
stable. In other words, they are not constrained to the CFL number condition.
• However, the fact that you are using a numerical method that is unconditionally stable, does
not mean that you can choose a time step of any size.
• The time-step must be chosen in such a way that it resolves the time-dependent features, and it
maintains the solver stability.
• For the moment and for the sake of simplicity, let us try to keep the CFL number below 5.0 and
preferably close to 1.0 (for good accuracy).
• Other properties of the numerical method that you should observe are: conservationess,
boundedness, transportiveness, and accuracy. We are going to address these properties and
the CFL number when we deal with the FVM theory. 119
A deeper view to my first OpenFOAM® case setup
The output screen
• To control the CFL number you can change the time step or you can change the mesh.
• The easiest way is by changing the time step.
• For a time step of 0.01 seconds, this is the output you should get for this case,
Time = 49.99
CFL number at
Courant Number mean: 0.044365026 max: 0.16800273
time step n - 1
smoothSolver: Solving for Ux, Initial residual = 1.1174405e-09, Final residual = 1.1174405e-09, No Iterations 0
smoothSolver: Solving for Uy, Initial residual = 1.4904251e-09, Final residual = 1.4904251e-09, No Iterations 0
DICPCG: Solving for p, Initial residual = 6.7291723e-07, Final residual = 6.7291723e-07, No Iterations 0
time step continuity errors : sum local = 2.5096865e-10, global = -1.7872395e-19, cumulative = 2.6884327e-18
ExecutionTime = 4.47 s ClockTime = 5 s
Time = 50
CFL number at
Courant Number mean: 0.044365026 max: 0.16800273
smoothSolver: Solving for Ux, Initial residual = 1.0907508e-09, Final residual = 1.0907508e-09, No Iterations 0 time step n
smoothSolver: Solving for Uy, Initial residual = 1.4677462e-09, Final residual = 1.4677462e-09, No Iterations 0
DICPCG: Solving for p, Initial residual = 1.0020944e-06, Final residual = 1.0746895e-07, No Iterations 1
time step continuity errors : sum local = 4.0107145e-11, global = -5.0601748e-20, cumulative = 2.637831e-18
ExecutionTime = 4.47 s ClockTime = 5 s
120
A deeper view to my first OpenFOAM® case setup
The output screen
• To control the CFL number you can change the time step or you can change the mesh.
• The easiest way is by changing the time step.
• For a time step of 0.1 seconds, this is the output you should get for this case,
Time = 49.9
CFL number at
Courant Number mean: 0.4441161 max: 1.6798756
time step n - 1
smoothSolver: Solving for Ux, Initial residual = 0.00016535808, Final residual = 2.7960145e-09, No Iterations 5
smoothSolver: Solving for Uy, Initial residual = 0.00015920267, Final residual = 2.7704949e-09, No Iterations 5
DICPCG: Solving for p, Initial residual = 0.0015842846, Final residual = 5.2788554e-07, No Iterations 26
time step continuity errors : sum local = 8.6128916e-09, global = 3.5439859e-19, cumulative = 2.4940081e-17
ExecutionTime = 0.81 s ClockTime = 1 s
Time = 50
CFL number at
Courant Number mean: 0.44411473 max: 1.6798833
smoothSolver: Solving for Ux, Initial residual = 0.00016378098, Final residual = 2.7690608e-09, No Iterations 5 time step n
smoothSolver: Solving for Uy, Initial residual = 0.00015720331, Final residual = 2.7354499e-09, No Iterations 5
DICPCG: Solving for p, Initial residual = 0.0015662416, Final residual = 5.2290439e-07, No Iterations 26
time step continuity errors : sum local = 8.5379223e-09, global = -3.6676527e-19, cumulative = 2.4573316e-17
ExecutionTime = 0.81 s ClockTime = 1 s
121
A deeper view to my first OpenFOAM® case setup
The output screen
• To control the CFL number you can change the time step or you can change the mesh.
• The easiest way is by changing the time step.
• For a time step of 0.5 seconds, this is the output you should get for this case,
Time = 2
CFL number at
Courant Number mean: 1.6828931 max: 5.6061178
time step n - 1
smoothSolver: Solving for Ux, Initial residual = 0.96587058, Final residual = 4.9900041e-09, No Iterations 27
smoothSolver: Solving for Uy, Initial residual = 0.88080685, Final residual = 9.7837781e-09, No Iterations 25
DICPCG: Solving for p, Initial residual = 0.95568243, Final residual = 7.9266324e-07, No Iterations 33
time step continuity errors : sum local = 6.3955627e-06, global = 1.3227253e-17, cumulative = 1.4125109e-17
ExecutionTime = 0.04 s ClockTime = 0 s
122
A deeper view to my first OpenFOAM® case setup
The output screen
• Another output you should monitor are the continuity errors.
• These numbers should be small (it does not matter if they are negative or positive).
• If these values increase in time (about the order of 1e-2), you better control the case setup because
something is wrong.
• The continuity errors are defined in the following file
$WM_PROJECT_DIR/src/finiteVolume/cfdTools/incompressible/continuityErrs.H
Time = 50
123
A deeper view to my first OpenFOAM® case setup
Error output
• If you forget a keyword or a dictionary file, give a wrong option to a compulsory or optional entry,
misspelled something, add something out of place in a dictionary, use the wrong dimensions,
forget a semi-colon and so on, OpenFOAM® will give you the error FOAM FATAL IO ERROR.
• This error does not mean that the actual OpenFOAM® installation is corrupted. It is telling you
that you are missing something or something is wrong in a dictionary.
• Maybe the guys of OpenFOAM® went a little bit extreme here.
/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 6.x |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 5.x-5d8318b22cbe
Exec : icoFoam
Date : Nov 02 2014
Time : 00:33:41
Host : "linux-cfd"
PID : 3675
Case : /home/cfd/my_cases_course/cavity
nProcs : 1
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time
124
A deeper view to my first OpenFOAM® case setup
Error output
• Also, before entering into panic read carefully the output screen because OpenFOAM® is telling
you what is the error and how to correct it.
Build : 6.x-5d8318b22cbe
Exec : icoFoam
Date : Nov 02 2014
Time : 00:33:41
Host : "linux-cfd"
PID : 3675
Case : /home/cfd/my_cases_course/cavity
nProcs : 1
sigFpe : Enabling floating point exception trapping (FOAM_SIGFPE).
fileModificationChecking : Monitoring run-time modified files using timeStampMaster
allowSystemOperations : Allowing user-supplied system call operations
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Create time
FOAM exiting
125
A deeper view to my first OpenFOAM® case setup
Error output
• It is very important to read the screen and understand the output.
• Train yourself to identify the errors. Hereafter we list a few possible errors.
• Missing compulsory file p
FOAM exiting
126
A deeper view to my first OpenFOAM® case setup
Error output
• Mismatching patch name in file p
FOAM exiting
FOAM exiting
127
A deeper view to my first OpenFOAM® case setup
Error output
• Missing entry in file fvSolution at keyword PISO
--> FOAM FATAL IO ERROR:
"ill defined primitiveEntry starting at keyword 'PISO' on line 68 and ending at line 68"
FOAM exiting
FOAM aborting
#0 Foam::error::printStack(Foam::Ostream&) at ??:?
#1 Foam::error::abort() at ??:?
#2 void Foam::checkMethod<Foam::Vector<double> >(Foam::fvMatrix<Foam::Vector<double> > const&,
Foam::fvMatrix<Foam::Vector<double> > const&, char const*) at ??:?
#3 ? at ??:?
#4 ? at ??:?
#5 __libc_start_main in "/lib64/libc.so.6"
#6 ? at /home/abuild/rpmbuild/BUILD/glibc-2.19/csu/../sysdeps/x86_64/start.S:125
Aborted 128
A deeper view to my first OpenFOAM® case setup
Error output
• Missing keyword deltaT in file controlDict
FOAM exiting
• Missing file points in directory polyMesh. Likely you are missing the mesh.
From function Time::findInstance(const fileName&, const word&, const IOobject::readOption, const word&)
in file db/Time/findInstance.C at line 203.
FOAM exiting
129
A deeper view to my first OpenFOAM® case setup
Error output
• Unknown boundary condition type.
74
(
SRFFreestreamVelocity
SRFVelocity
SRFWallVelocity
activeBaffleVelocity
...
...
...
variableHeightFlowRateInletVelocity
waveTransmissive
wedge
zeroGradient
)
FOAM exiting
130
A deeper view to my first OpenFOAM® case setup
Error output
• This one is specially hard to spot
/*---------------------------------------------------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 6.x |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
Build : 6.x-5d8318b22cbe
Exec : icoFoam
Date : Nov 02 2014
Time : 00:33:41
Host : "linux-cfd"
PID : 3675
fileName::stripInvalid() called for invalid fileName /home/cfd/my_cases_course/cavity0
For debug level (= 2) > 1 this is considerd fatal
Aborted
• This error is related to the name of the working directory. In this case the name of the
working directory is cavity 0 (there is a blank space between the word cavity and
the number 0).
• Do not use blank spaces or funny symbols when naming directories and files.
• Instead of cavity 0 you could use cavity_0.
131
A deeper view to my first OpenFOAM® case setup
Error output
• You should worry about the SIGFPE error signal. This error signal indicates that something
went really wrong (erroneous arithmetic operation).
• This message (that seems a little bit difficult to understand), is giving you a lot information.
• For instance, this output is telling us that the error is due to SIGFPE and the class associated to
the error is lduMatrix. It is also telling you that the GAMGSolver solver is the affected one
(likely the offender is the pressure).
#0 Foam::error::printStack(Foam::Ostream&) at ??:?
#1 Foam::sigFpe::sigHandler(int) at ??:?
#2 in "/lib64/libc.so.6"
#3 Foam::DICPreconditioner::calcReciprocalD(Foam::Field<double>&, Foam::lduMatrix const&) at ??:?
#4 Foam::DICSmoother::DICSmoother(Foam::word const&, Foam::lduMatrix const&, Foam::FieldField<Foam::Field, double>
const&, Foam::FieldField<Foam::Field, double> const&, Foam::UPtrList<Foam::lduInterfaceField const> const&) at ??:?
#5 Foam::lduMatrix::smoother::addsymMatrixConstructorToTable<Foam::DICSmoother>::New(Foam::word const&,
Foam::lduMatrix const&, Foam::FieldField<Foam::Field, double> const&, Foam::FieldField<Foam::Field, double> const&,
Foam::UPtrList<Foam::lduInterfaceField const> const&) at ??:?
#6 Foam::lduMatrix::smoother::New(Foam::word const&, Foam::lduMatrix const&, Foam::FieldField<Foam::Field, double>
const&, Foam::FieldField<Foam::Field, double> const&, Foam::UPtrList<Foam::lduInterfaceField const> const&,
Foam::dictionary const&) at ??:?
#7 Foam::GAMGSolver::initVcycle(Foam::PtrList<Foam::Field<double> >&, Foam::PtrList<Foam::Field<double> >&,
Foam::PtrList<Foam::lduMatrix::smoother>&, Foam::Field<double>&, Foam::Field<double>&) const at ??:?
#8 Foam::GAMGSolver::solve(Foam::Field<double>&, Foam::Field<double> const&, unsigned char) const at ??:?
#9 Foam::fvMatrix<double>::solveSegregated(Foam::dictionary const&) at ??:?
#10 Foam::fvMatrix<double>::solve(Foam::dictionary const&) at ??:?
#11
at ??:?
#12 __libc_start_main in "/lib64/libc.so.6"
#13
at /home/abuild/rpmbuild/BUILD/glibc-2.17/csu/../sysdeps/x86_64/start.S:126
Floating point exception 132
A deeper view to my first OpenFOAM® case setup
Dictionary files general features
/*
// This is a line comment This is a block comment
*/
• As in C++, you can use the #include directive in your dictionaries (do not forget to create the respective include file):
#include “ n t C nd t n ”
133
A deeper view to my first OpenFOAM® case setup
Dictionary files general features
U Sub-dictionary U
{
solver PBiCGStab;
preconditioner DILU;
tolerance 1e-06;
relTol 0;
}
…
…
…
} 135
A deeper view to my first OpenFOAM® case setup
Dictionary files general features
• Macro expansion.
• We first declare a variable (x = 10) and then we use it through the $ macro substitution ($x).
type fixedValue;
value uniform $scalarField; //Use declared variable
• You can use macro expansion to duplicate and access variables in dictionaries
“( eft|r ght|t )W ”
{
type fixedValue;
value uniform (0 0 0);
}
“.*W ”
{
type fixedValue;
value uniform (0 0 0);
}
• Inline calculations.
• You can use the directive #calc to do inline calculations, the syntax is as follows:
X = 10.0; //Declare variable
Y = 3.0; //Declare variable
• With inline calculations you can access all the mathematical functions available in C++.
• Macro expansions and inline calculations are very useful to parametrize dictionaries and avoid repetitive tasks.
• Switches: they are used to enable or disable a function or a feature in the dictionaries.
• Switches are logical values. You can use the following values:
Switches
false true
off on
no yes
n y
f t
none true
• You can find all the valid switches in the following file:
OpenFOAM-6/src/OpenFOAM/primitives/bools/Switch/Switch.C 138
A deeper view to my first OpenFOAM® case setup
Solvers and utilities help
• If you need help about a solver or utility, you can use the option –help. For
instance:
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.
139
A deeper view to my first OpenFOAM® case setup
Solvers and utilities help
• To get more information about the boundary conditions, post-processing utilities, and the API read the
Doxygen documentation.
• If you did not compile the Doxygen documentation, you can access the information online,
http://cpp.openfoam.org/v6/
API documentation
140
A deeper view to my first OpenFOAM® case setup
Exercises
• Run the case with Re = 10 and Re = 1000. Feel free to change any variable to achieve the Re value (velocity,
viscosity or length). Do you see an unsteady behavior in any of the cases? What about the computing time,
what simulation is faster?
• Run the tutorial with Re = 100, a mesh with 120 x 120 x 1 cells, and using the default setup (original
controlDict, fvSchemes and fvSolution). Did the simulation converge? Did it crash? Any comments.
• If your simulation crashed, try to solve the problem.
(Hint: try to reduce the time-step to get a CFL less than 1)
• Besides reducing the time-step, can you find another solution?
(Hint: look at the PISO options)
• Change the base type of the boundary patch movingWall to patch. (the boundary file). Do you get the same
results? Can you comment on this?
• Try to extent the problem to 3D and use a uniform mesh (20 x 20 x 20). Compare the solution at the mid
section of the 3D simulation with the 2D solution. Are the solutions similar?
• How many time discretization schemes are there in OpenFOAM®? Try to use a different discretization
scheme.
• Run the simulation using Gauss upwind instead of Gauss linear for the term div(phi,U) (fvSchemes). Do
you get the same quantitative results?
• Sample the field variables U and P at a different location and plot the results using gnuplot.
• What density value do you think we were using? What about dynamic viscosity?
Hint: the physical pressure is equal to the modified pressure and
141
Roadmap
142
3D Dam break – Free surface flow
blockMesh
+
snappyHexMesh
setFields
interFoam functionObjects
sampling paraview
144
3D Dam break – Free surface flow
At the end of the day, you should get something like this
145
3D Dam break – Free surface flow
146
3D Dam break – Free surface flow
$PTOFC/101OF/3d_damBreak
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
147
3D Dam break – Free surface flow
148
3D Dam break – Free surface flow
The constant directory
• g
• transportProperties
• turbulenceProperties
149
3D Dam break – Free surface flow
The g dictionary file
150
3D Dam break – Free surface flow
The transportProperties dictionary file
Primary phase
151
3D Dam break – Free surface flow
The turbulenceProperties dictionary file
• In this dictionary file we select what model we would like to use (laminar or
turbulent).
• This dictionary is compulsory.
• In this case we use a RANS turbulence model (kEpsilon).
17 simulationType RAS;
18
19 RAS
20 {
21 RASModel kEpsilon;
22
23 turbulence on;
24
25 printCoeffs on;
26 }
152
3D Dam break – Free surface flow
The 0 directory
• In this directory, we will find the dictionary files that contain the boundary and
initial conditions for all the primitive variables.
• As we are solving the incompressible RANS Navier-Stokes equations using
the VOF method, we will find the following field files:
153
3D Dam break – Free surface flow
The file 0/alpha.water
17 dimensions [0 0 0 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0; for the non-dimensional scalar field alpha.water
20
21 boundaryField
22 { • This file is named alpha.water, because the
23 front primary phase is water (we defined the primary
24 {
25 type zeroGradient; phase in the transportProperties dictionary).
26 }
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 }
31 left domain at time 0. Later, we will initialize the water
32 { column and this file will be overwritten with a non-
33 type zeroGradient;
34 } uniform field for the internalField.
35 right
36
37
{
type zeroGradient;
• For the front, back, left, right, bottom and
38 } stlSurface patches we are using a zeroGradient
39 bottom
40 { boundary condition (we are just extrapolating the
41 type zeroGradient; internal values to the boundary face).
42 }
43 top
44 { • For the top patch we are using an inletOutlet
45 type inletOutlet; boundary condition. This boundary condition avoids
46 inletValue uniform 0;
47 value uniform 0; backflow into the domain. If the flow is going out it
48 }
49 stlSurface will use zeroGradient and if the flow is coming back
50 { it will assign the value set in the keyword inletValue
51 type wall;
52 } (line 46).
53
54 }
154
3D Dam break – Free surface flow
The file 0/p_rgh
17 dimensions [1 -1 -2 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0;
20 for the dimensional scalar field p_rgh. The
21 boundaryField dimensions of this field are given in Pascal (line 17)
22 {
23 front
24 { • This scalar field contains the value of the static
25 type fixedFluxPressure;
26 value uniform 0;
pressure field minus the hydrostatic component.
27 }
28 back • This field is initialize as 0 in the whole domain (line
33 left
19).
38 right • For the front, back, left, right, bottom and
43 bottom
stlSurface patches we are using a
fixedFluxPressure boundary condition (refer to the
48 top
49 { source code or doxygen documentation to know
50 type totalPressure;
51 p0 uniform 0;
more about this boundary condition).
52 U U;
53 phi phi; • For the top patch we are using the totalPressure
54 rho rho;
55 psi none;
boundary condition (refer to the source code or
56 gamma 1; doxygen documentation to know more about this
57 value uniform 0;
58 } boundary condition).
59 stlSurface
60 {
61 type fixedFluxPressure;
62 value uniform 0;
63 }
64
65 }
155
3D Dam break – Free surface flow
The file 0/U
17 dimensions [0 -1 -1 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform (0 0 0);
20 for the dimensional vector field U.
21 boundaryField
22 { • We are using uniform initial conditions and the
23 front
24 { numerical value is (0 0 0) (keyword internalField in
25 type fixedValue;
26 value uniform (0 0 0);
line 19).
27 }
28 back • The front, back, left, right, bottom and stlSurface
33 left
patches are no-slip walls, therefore we impose a
fixedValue boundary condition with a value of (0 0 0)
38 right
at the wall.
43 bottom
• For the top patch we are using the
48 top
49 { pressureInlterOutletVelocity boundary condition
50 type pressureInletOutletVelocity;
51 value uniform (0 0 0);
(refer to the source code or doxygen documentation
52 } to know more about this boundary condition).
53 stlSurface
54 {
55 type fixedValue;
56 value uniform (0 0 0);
57 }
58
59 }
156
3D Dam break – Free surface flow
The file 0/k
17 dimensions [0 2 -2 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0.1;
20 for the dimensional scalar field k.
21 boundaryField
22 { • This scalar (turbulent kinetic energy), is related to the
23 “(front|back|left|right|bottom|stlSurface)”
24 { turbulence model.
25 type kqRWallFunction;
26 value $internalField; • This field is initialize as 0.1 in the whole domain, and
27 }
28 all the boundary patches take the same value
29 top
30 {
($internalField).
31 type inletOutlet;
32 inletValue $internalField; • For the front, back, left, right, bottom and
33 value $internalField;
34 }
stlSurface patches we are using a
35 kqRWallFunction boundary condition, which applies
36 }
a wall function at the walls (refer to the source code
or doxygen documentation to know more about this
boundary condition).
• For the top patch we are using the inletOutlet
boundary condition, this boundary condition handles
backflow (refer to the source code or doxygen
documentation to know more about this boundary
condition).
• We will deal with turbulence modeling later.
157
3D Dam break – Free surface flow
The file 0/epsilon
17 dimensions [0 2 -3 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0.1;
20 for the dimensional scalar field epsilon.
21 boundaryField
22 { • This scalar (rate of dissipation of turbulence energy),
23 “(front|back|left|right|bottom|stlSurface)”
24 { is related to the turbulence model.
25 type epsilonWallFunction;
26 value $internalField; • This field is initialize as 0.1 in the whole domain, and
27 }
28 all the boundary patches take the same value
29 top
30 {
($internalField).
31 type inletOutlet;
32 inletValue $internalField; • For the front, back, left, right, bottom and
33 value $internalField;
34 }
stlSurface patches we are using a
35 epsilonWallFunction boundary condition, which
36 }
applies a wall function at the walls (refer to the
source code or doxygen documentation to know
more about this boundary condition).
• For the top patch we are using the inletOutlet
boundary condition, this boundary condition handles
backflow (refer to the source code or doxygen
documentation to know more about this boundary
condition).
• We will deal with turbulence modeling later.
158
3D Dam break – Free surface flow
The file 0/nut
17 dimensions [0 2 -1 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform 0;
20 for the dimensional scalar field nut.
21 boundaryField
22 { • This scalar (turbulent viscosity), is related to the
23 “(front|back|left|right|bottom|stlSurface)”
24 { turbulence model.
25 type nutkWallFunction;
26 value $internalField; • This field is initialize as 0 in the whole domain, and
27 }
28 all the boundary patches take the same value
29 top
30 {
($internalField).
31 type calculated;
32 value $internalField;; • For the front, back, left, right, bottom and
33 }
34
stlSurface patches we are using a
35 } nutkWallFunction boundary condition, which applies
a wall function at the walls (refer to the source code
or doxygen documentation to know more about this
boundary condition).
• For the top patch we are using the calculated
boundary condition, this boundary condition
computes the value of nut from k and epsilon (refer to
the source code or doxygen documentation to know
more about this boundary condition).
• We will deal with turbulence modeling later.
159
3D Dam break – Free surface flow
The system directory
160
3D Dam break – Free surface flow
The controlDict dictionary
• This case starts from time 0 (startTime), and it will run up to 8
17 application interFoam; seconds (endTime).
18
19
20
startFrom startTime;
• The initial time step of the simulation is 0.0001 seconds
21 startTime 0; (deltaT).
22
23
24
stopAt endTime;
• It will write the solution every 0.02 seconds (writeInterval) of
25 endTime 8; simulation time (runTime). It will automatically adjust the time
26
27 deltaT 0.0001; step (adjustableRunTime), in order to save the solution at the
28
29 writeControl adjustableRunTime;
precise write interval.
30
31 writeInterval 0.02; • It will keep all the solution directories (purgeWrite).
32
33 purgeWrite 0; • It will save the solution in ascii format (writeFormat).
34
35 writeFormat ascii;
36 • The write precision is 8 digits (writePrecision). It will only save
37 writePrecision 8; eight digits in the output files.
38
39 writeCompression uncompressed;
40 • And as the option runTimeModifiable is on, we can modify all
41 timeFormat general; these entries while we are running the simulation.
42
43 timePrecision 8;
44 • In line 47 we turn on the option adjustTimeStep. This option
45 runTimeModifiable yes;
46
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).
161
3D Dam break – Free surface flow
The controlDict dictionary
144 };
162
3D Dam break – Free surface flow
The controlDict dictionary
144 };
163
3D Dam break – Free surface flow
The controlDict dictionary
144 };
Sampling locations
(probeLocations)
164
3D Dam break – Free surface flow
The controlDict dictionary
165
3D Dam break – Free surface flow
The fvSchemes dictionary
• In this case, for time discretization (ddtSchemes) we are
17 ddtSchemes using the Euler method.
18 {
19 default Euler; • For gradient discretization (gradSchemes) we are using the
21 }
22
Gauss linear as the default method and slope limiters
23 gradSchemes (cellLimited) for the velocity gradient or grad(U).
24 {
25 default Gauss linear; • For the discretization of the convective terms (divSchemes)
26 grad(U) cellLimited Gauss linear 1;
27 } we are using linearUpwindV interpolation method for the
28
29 divSchemes
term div(rhoPhi,U).
30
31
{
div(rhoPhi,U) Gauss linearUpwindV grad(U);
• For the term div(phi,alpha) we are using vanLeer
32 div(phi,alpha) Gauss vanLeer; interpolation. For the term div(phirb,alpha) we are using
33 div(phirb,alpha) Gauss linear;
35 div(phi,k) Gauss upwind; linear interpolation. These terms are related to the volume
36 div(phi,epsilon) Gauss upwind; fraction equation.
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 snGradSchemes
51 {
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
solution that is second order accurate. 166
3D Dam break – Free surface flow
The fvSolution dictionary
167
3D Dam break – Free surface flow
The fvSolution dictionary
168
3D Dam break – Free surface flow
The fvSolution dictionary
169
3D Dam break – Free surface flow
The system directory
• In the system directory you will find the following optional dictionary files:
• decomposeParDict
• setFieldsDict
170
3D Dam break – Free surface flow
The setFieldsDict dictionary
• This dictionary file is located in the directory system.
• In lines 17-20 we set the default value to be 0 in the whole
17 defaultFieldValues domain (no water).
18 (
19
20 );
volScalarFieldValue alpha.water 0
• In lines 22-32, we initialize a rectangular region (box)
21 containing water (alpha.water 1).
22 regions
23
24
(
boxToCell
• In this case, setFields will look for the dictionary file
25 { alpha.water and it will overwrite the original values
26 box (1.992 -10 0) (5 10 0.55);
27 fieldValues according to the regions defined in setFieldsDict.
28 (
29 volScalarFieldValue alpha.water 1 • We initialize the water phase because is the primary phase in
30 );
31 } the dictionary transportProperties.
32 );
• If you are interested in initializing the vector field U, you can
proceed as follows volVectorFieldValue U (0 0 0)
Air
alpha.water = 0
Water
alpha.water = 1
boxToCell region
171
3D Dam break – Free surface flow
The decomposeParDict dictionary
• This dictionary file is located in the directory system.
• This dictionary is used to decompose the domain in order to run in parallel.
• The keyword numberOfSubdomains (line 17) is used to set the number of cores we want to use in the
parallel simulation.
• In this dictionary we also set the decomposition method (line 19).
• Most of the times the scotch method is fine.
• In this case we set the numberOfSubdomains to 4, therefore we will run in parallel using 4 cores.
17 numberOfSubdomains 4;
18
19 method scotch;
20
• When you run in parallel, the solution is saved in the directories processorN, where N stands for processor
number. In this case you will find the following directories with the decomposed mesh and solution:
processor0, processor1, processor2, and processor3.
172
3D Dam break – Free surface flow
1. $> foamCleanTutorials
2. $> rm –rf 0
3. $> blockMesh
4. $> surfaceFeatureExtract
5. $> snappyHexMesh -overwrite
6. $> createPatch -dict system/createPatchDict.0 -overwrite
7. $> createPatch -dict system/createPatchDict.1 -overwrite
8. $> checkMesh
9. $> paraFoam
173
3D Dam break – Free surface flow
1. $> rm –rf 0
2. $> cp –r 0_org 0
3. $> setFields
4. $> paraFoam
5. $> decomposePar
6. $> mpirun –np 4 interFoam –parallel | tee log.interFoam
7. $> reconstructPar
8. $> paraFoam
174
3D Dam break – Free surface flow
175
3D Dam break – Free surface flow
• To plot the sampled data using gnuplot you can proceed as follows. To enter to the
gnuplot prompt type in the terminal:
1. $> gnuplot
177
3D Dam break – Free surface flow
2. Select alpha.water in
the Active Variable drop-
down menu
Air Water
alpha.water = 0 alpha.water = 1
Interface
alpha.water = 0.5
179
3D Dam break – Free surface flow
4. Press apply
180
3D Dam break – Free surface flow
4. Press apply
181
3D Dam break – Free surface flow
Exercises
• Instead of using the boundary condition totalPressure and pressureInletOutletVelocity for the patch top, try
to use zeroGradient. Do you get the same results? Any comments?
(Hint: this combination of boundary conditions will give you an error, read carefully the screen, you
will need to add a fix in the file fvSolution)
• Instead of using the boundary condition fixedFluxPressure for the walls, try to use zeroGradient. Do you get
the same results? Any comments?
• Run the simulation in a close domain. Does the volume integral of alpha.water remains the same? Why the
value is not constant when the domain is open?
• Use a functionObject to measure the average pressure at the obstacle.
• How many initialization methods are there available in the dictionary setFieldsDict?
(Hint: use the banana method)
• Run the simulation using Gauss upwind instead of Gauss vanLeer for the term div(phi,alpha) (fvSchemes).
Do you get the same quantitative results?
• Run a numerical experiment for cAlpha equal to 0, 1, and 2. Do you see any difference in the solution? What
about computing time?
• Use the solver GAMG instead of using the solver PCG for the variable p_rgh. Do you see any difference on
the solution or computing time?
• Increase the number of nOuterCorrector to 2 and study the output screen. What difference do you see?
• Turn off the MULES corrector (MULESCorr). Do you see any difference on the solution or computing time?
• If you set the gravity vector to (0 0 0), what do you think will happen?
• Try to break the solver and identify the cause of the error. You are free to try any kind of setup.
182
Roadmap
183
Flow past a cylinder – From laminar to turbulent flow
184
Flow past a cylinder – From laminar to turbulent flow
Flow around a cylinder – 10 < Re < 2 000 000
Incompressible and compressible flow
185
Flow past a cylinder – From laminar to turbulent flow
Workflow of the case
blockMesh
Or
fluentMeshToFoam
icoFoam
NOTE: pisoFoam
One single mesh can be used with all
solvers and utilities pimpleFoam
pimpleDyMFoam
simpleFoam
functionObjects
rhoPimpleFoam
interFoam
sonicFoam
potentialFoam
mapFields
postProcessing
utilities
sampling paraview
186
Flow past a cylinder – From laminar to turbulent flow
Strouhal number
187
Flow past a cylinder – From laminar to turbulent flow
Some experimental (E) and numerical (N) results of the flow past a circular
cylinder at various Reynolds numbers
[1] D. Tritton. Experiments on the flow past a circular cylinder at low Reynolds numbers. Journal of Fluid Mechanics, 6:547-567, 1959.
[2] M. Cuntanceau and R. Bouard. Experimental determination of the main features of the viscous flow in the wake of a circular cylinder in uniform translation. Part 1. Steady flow. Journal of Fluid
Mechanics, 79:257-272, 1973.
[3] D. Rusell and Z. Wang. A cartesian grid method for modeling multiple moving objects in 2D incompressible viscous flow. Journal of Computational Physics, 191:177-205, 2003.
[4] D. Calhoun and Z. Wang. A cartesian grid method for solving the two-dimensional streamfunction-vorticity equations in irregular regions. Journal of Computational Physics. 176:231-275, 2002.
[5] T. Ye, R. Mittal, H. Udaykumar, and W. Shyy. An accurate cartesian grid method for viscous incompressible flows with complex immersed boundaries. Journal of Computational Physics,
156:209-240, 1999.
[6] B. Fornberg. A numerical study of steady viscous flow past a circular cylinder. Journal of Fluid Mechanics, 98:819-855, 1980.
[7] J. Guerrero. Numerical simulation of the unsteady aerodynamics of flapping flight. PhD Thesis, University of Genoa, 2009.
188
Flow past a cylinder – From laminar to turbulent flow
Some experimental (E) and numerical (N) results of the flow past a circular
cylinder at various Reynolds numbers
[1] Russel and Wang (N) 1.38 ± 0.007 ± 0.322 1.29 ± 0.022 ± 0.50
[2] Calhoun and Wang (N) 1.35 ± 0.014 ± 0.30 1.17 ± 0.058 ± 0.67
[3] Braza et al. (N) 1.386± 0.015 ± 0.25 1.40 ± 0.05 ± 0.75
[4] Choi et al. (N) 1.34 ± 0.011 ± 0.315 1.36 ± 0.048 ± 0.64
[5] Liu et al. (N) 1.35 ± 0.012 ± 0.339 1.31 ± 0.049 ± 0.69
[1] D. Rusell and Z. Wang. A cartesian grid method for modeling multiple moving objects in 2D incompressible viscous flow. Journal of Computational Physics, 191:177-205, 2003.
[2] D. Calhoun and Z. Wang. A cartesian grid method for solving the two-dimensional streamfunction-vorticity equations in irregular regions. Journal of Computational Physics. 176:231-275, 2002.
[3] M. Braza, P. Chassaing, and H. Hinh. Numerical study and physical analysis of the pressure and velocity fields in the near wake of a circular cylinder. Journal of Fluid Mechanics, 165:79-130,
1986.
[4] J. Choi, R. Oberoi, J. Edwards, an J. Rosati. An immersed boundary method for complex incompressible flows. Journal of Computational Physics, 224:757-784, 2007.
[5] C. Liu, X. Zheng, and C. Sung. Preconditioned multigrid methods for unsteady incompressible flows. Journal of Computational Physics, 139:33-57, 1998.
[6] J. Guerrero. Numerical Simulation of the unsteady aerodynamics of flapping flight. PhD Thesis, University of Genoa, 2009.
189
Flow past a cylinder – From laminar to turbulent flow
At the end of the day, you should get something like this
190
Flow past a cylinder – From laminar to turbulent flow
At the end of the day, you should get something like this
$PTOFC/101OF/vortex_shedding
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
192
Flow past a cylinder – From laminar to turbulent flow
What are we going to do?
• We will use this case to learn how to use different solvers and utilities.
• Remember, different solvers have different input dictionaries.
• We will learn how to convert the mesh from a third party software.
• We will learn how to use setFields to initialize the flow field and accelerate the
convergence.
• We will learn how to map a solution from a coarse mesh to a fine mesh.
• We will learn how to setup a compressible solver.
• We will learn how to setup a turbulence case.
• We will use gnuplot to plot and compute the mean values of the lift and drag
coefficients.
• We will visualize unsteady data.
193
Flow past a cylinder – From laminar to turbulent flow
Running the case
• Let us first convert the mesh from a third-party format (Fluent format).
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c2
• In the terminal window type:
1. $> foamCleanTutorials
2. $> fluent3DMeshToFoam ../../../meshes_and_geometries/vortex_shedding/ascii.msh
3. $> checkMesh
4. $> paraFoam
• In step 2, we convert the mesh from Fluent format to OpenFOAM® format. Have in
mind that the Fluent mesh must be in ascii format.
• If we try to open the mesh using paraFoam (step 4), it will crash. Can you tell what is
the problem by just reading the screen?
194
Flow past a cylinder – From laminar to turbulent flow
Running the case
• To avoid this problem, type in the terminal,
• Basically, the problem is related to the names and type of the patches in the file
boundary and the boundary conditions (U, p). Notice that OpenFOAM® is telling you
what and where is the error.
FOAM exiting
195
Flow past a cylinder – From laminar to turbulent flow
• Remember, when converting meshes the name and type of the patches are not
always set as you would like, so it is always a good idea to take a look at the file
boundary and modify it according to your needs.
• Let us modify the boundary dictionary file.
• In this case, we would like to setup the following numerical type boundary
conditions.
196
Flow past a cylinder – From laminar to turbulent flow
The boundary dictionary file
197
Flow past a cylinder – From laminar to turbulent flow
The boundary dictionary file
198
Flow past a cylinder – From laminar to turbulent flow
• At this point, check that the name and type of the base type boundary conditions
and numerical type boundary conditions are consistent. If everything is ok, we are
ready to go.
• Do not forget to explore the rest of the dictionary files, namely:
• 0/p (p is defined as relative pressure)
• 0/U
• constant/transportProperties
• system/controlDict
• system/fvSchemes
• system/fvSolution
• Reminder:
• The diameter of the cylinder is 2.0 m.
• And we are targeting for a Re = 200.
199
Flow past a cylinder – From laminar to turbulent flow
Running the case
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c2
• In the folder c1 you will find the same setup, but to generate the mesh we use
blockMesh (the mesh is identical).
• To run this case, in the terminal window type:
5. $> paraFoam
200
Flow past a cylinder – From laminar to turbulent flow
Running the case
• In step 1 we use the utility renumberMesh to make the linear system more diagonal
dominant, this will speed-up the linear solvers. This is inexpensive (even for large
meshes), therefore is highly recommended to always do it.
• In step 2 we run the simulation and save the log file. Notice that we are sending the
job to background.
• In step 3 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
job is running in background, we can launch this utility in the same terminal tab.
• In step 4 we use the gnuplot script scripts0/plot_coeffs to plot the force
coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
• The force coefficients are computed using functionObjects.
• After the simulation is over, we use paraFoam to visualize the results. Remember to
use the VCR Controls to animate the solution.
• In the folder c1 you will find the same setup, but to generate the mesh we use
blockMesh (the mesh is identical).
201
Flow past a cylinder – From laminar to turbulent flow
• At this point try to use the following utilities. In the terminal type:
• $> postProcess –func vorticity –noZero
This utility will compute and write the vorticity field. The –noZero option means do not compute the vorticity field for the
solution in the directory 0. If you do not add the –noZero option, it will compute and write the vorticity field for all the
saved solutions, including 0
• $> postprocess –func 'grad(U)' –latestTime
This utility will compute and write the velocity gradient or grad(U) in the whole domain (including at the walls). The
–latestTime option means compute the velocity gradient only for the last saved solution.
• $> postprocess –func 'grad(p)'
This utility will compute and write the pressure gradient or grad(U) in the whole domain (including at the walls).
• $> foamToVTK –time 50:300
This utility will convert the saved solution from OpenFOAM® format to VTK format. The –time 50:300 option means
convert the solution to VTK format only for the time directories 50 to 300
This utility will compute and write the divergence of the velocity field or grad(U) in the whole domain (including at the
walls).
• $> pisoFoam -postProcess -func CourantNo
This utility will compute and write the Courant number. This utility needs to access the solver database for the physical
properties and additional quantities, therefore we need to tell what solver we are using. As the solver icoFoam does not
accept the option –postProcess, we can use the solver pisoFoam instead. Remember, icoFoam is a fully laminar
solver and pisoFoam is a laminar/turbulent solver.
• $> pisoFoam -postProcess -func wallShearStress
This utility will compute and write the wall shear stresses at the walls. As no arguments are given, it will save the wall
shear stresses for all time steps.
202
Flow past a cylinder – From laminar to turbulent flow
Non-uniform field initialization
• In the previous case, it took about 150 seconds of simulation time to onset the instability.
• If you are not interested in the initial transient or if you want to speed-up the computation, you
can add a perturbation in order to trigger the onset of the instability.
• Let us use the utility setFields to initialize a non-uniform flow.
• This case is already setup in the directory ,
$PTOFC/101OF/vortex_shedding/c3
• As you saw in the previous example, icoFoam is a very basic solver that does not have access
to all the advanced modeling or postprocessing capabilities that comes with OpenFOAM®.
• Therefore, instead of using icoFoam we will use pisoFoam (or pimpleFoam) from now on.
• To run the solver pisoFoam (or pimpleFoam) starting from the directory structure of an
icoFoam case, you will need to add the followings modifications:
• Add the file turbulenceProperties in the directory constant.
• Add the transportModel to be used in the file constant/transportProperties.
• Add the entry div((nuEff*dev2(T(grad(U))))) Gauss linear; to the dictionary
system/fvSchemes in the section divSchemes (this entry is related to the Reynodls
stresses).
203
Flow past a cylinder – From laminar to turbulent flow
• Let us run the same case but using a non-uniform field
The setFieldsDict dictionary
• This dictionary file is located in the directory system.
17 defaultFieldValues • In lines 17-20 we set the default value of the velocity vector
18 (
19 volVectorFieldValue U (1 0 0) to be (0 0 0) in the whole domain.
20 );
21 • In lines 24-31, we initialize a rectangular region (box) just
22 regions
23 ( behind the cylinder with a velocity vector equal to (0.98480
24 boxToCell 0.17364 0)
25 {
26 box (0 -100 -100) (100 100 100);
27 fieldValues • In this case, setFields will look for the dictionary file U
28 ( and it will overwrite the original values according to the
29 volVectorFieldValue U (0.98480 0.17364 0)
30 ); regions defined in setFieldsDict.
31 }
32 );
boxToCell region
U (0.98480 0.17364 0)
U (1 0 0)
204
Flow past a cylinder – From laminar to turbulent flow
• Let us run the same case but using a non-uniform field.
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c3
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. Hereafter, we will
use blockMesh.
• To run this case, in the terminal window type:
1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0 > /dev/null 2>&1
4. $> cp –r 0_org/ 0
5. $> setFields
6. $> renumberMesh -overwrite
7. $> pisoFoam | tee log.pisofoam
$> pyFoamPlotWatcher.py log.pisofoam
8.
You will need to launch this script in a different terminal
206
Flow past a cylinder – From laminar to turbulent flow
Does non-uniform field initialization make a difference?
• A picture is worth a thousand words. No need to tell you yes, even if the solutions are
slightly different.
• This bring us to the next subject, for how long should we run the simulation?
207
Flow past a cylinder – From laminar to turbulent flow
For how long should run the simulation?
208
Flow past a cylinder – From laminar to turbulent flow
What about the residuals?
209
Flow past a cylinder – From laminar to turbulent flow
How to compute force coefficients
210
Flow past a cylinder – From laminar to turbulent flow
Can we compute basic statistics of the force coefficients using gnuplot?
• Yes we can. Enter the gnuplot prompt and type:
4. gnuplot> exit
To exit gnuplot
211
Flow past a cylinder – From laminar to turbulent flow
On the solution accuracy
17 ddtSchemes
• At the end of the day we want a solution that is second order
18 { accurate.
20 default backward;
22
23
}
• We define the discretization schemes (and therefore the
24 gradSchemes accuracy) in the dictionary fvSchemes.
25 {
29
35 }
default cellLimited leastSquares 1;
• In this case, for time discretization (ddtSchemes) we are
36 using the backward method.
37 divSchemes
38
39
{
default none;
• For gradient discretization (gradSchemes) we are using the
43 div(phi,U) Gauss linearUpwindV default; leastSquares method with slope limiters (cellLimited) for all
48 div((nuEff*dev2(T(grad(U))))) Gauss linear;
49 } terms (default option).
50
51 laplacianSchemes • Sometimes adding a gradient limiter to the pressure gradient
52 {
53 default Gauss linear limited 1; or grad(p) can be too diffusive, so it is better not to use
54 }
55
gradient limiters for grad(p), e.g., grad(p) leastSquares.
56 interpolationSchemes
57 { • For the discretization of the convective terms (divSchemes)
58 default linear;
59 }
we are using linearUpwindV interpolation method for the
60 term div(rho,U).
61 snGradSchemes
62
63
{
default limited 1;
• For the discretization of the Laplacian (laplacianSchemes
64 } and snGradSchemes) we are using the Gauss linear
limited 1 method
• In overall, this method is second order accurate (this is what
we want).
212
Flow past a cylinder – From laminar to turbulent flow
On the solution tolerance and linear solvers
17 solvers
• We define the solution tolerance and linear solvers in the
18 { dictionary fvSolution.
31 p
32
33
{
solver GAMG;
• To solve the pressure (p) we are using the GAMG method
34 tolerance 1e-6; with an absolute tolerance of 1e-6 and a relative tolerance
35 relTol 0;
36 smoother GaussSeidel; relTol of 0.01.
37 nPreSweeps 0;
38 nPostSweeps 2; • The entry pFinal refers to the final correction of the PISO
39 cacheAgglomeration on;
40 agglomerator faceAreaPair; loop. It is possible to use a tighter convergence criteria only
41 nCellsInCoarsestLevel 100; in the last iteration.
42 mergeLevels 1;
43 }
44 • To solve U we are using the solver PBiCGStab and the DILU
45 pFinal
46 {
preconditioner, with an absolute tolerance of 1e-8 and a
47 $p; relative tolerance relTol of 0 (the solver will stop iterating
48 relTol 0;
49 } when it meets any of the conditions).
50
51 U • Solving for the velocity is relative inexpensive, whereas
52 {
53 solver PBiCGStab; solving for the pressure is expensive.
54 preconditioner DILU;
55 tolerance 1e-08; • The PISO sub-dictionary contains entries related to the
56 relTol 0;
57 } pressure-velocity coupling (in this case the PISO method).
69 }
70
Hereafter we are doing two PISO correctors (nCorrectors)
71 PISO and two non-orthogonal corrections
72 {
73 nCorrectors 2; (nNonOrthogonalCorrectors).
74 nNonOrthogonalCorrectors 2;
77 }
213
Flow past a cylinder – From laminar to turbulent flow
On the runtime parameters
17 application pisoFoam;
• This case starts from the latest saved solution (startFrom).
18
20 startFrom latestTime; • In this case as there are no saved solutions, it will start from
21
22 startTime 0;
0 (startTime).
23
24 stopAt endTime; • It will run up to 350 seconds (endTime).
26
27 endTime 350; • The time step of the simulation is 0.05 seconds (deltaT). The
28
29 deltaT 0.05; time step has been chosen in such a way that the Courant
30
31 writeControl runTime;
number is less than 1
32
33 writeInterval 1; • It will write the solution every 1 second (writeInterval) of
34
35 purgeWrite 0;
simulation time (runTime).
36
37 writeFormat ascii; • It will keep all the solution directories (purgeWrite).
38
39
40
writePrecision 8; • It will save the solution in ascii format (writeFormat).
41 writeCompression off;
42 • The write precision is 8 digits (writePrecision).
43 timeFormat general;
44 • And as the option runTimeModifiable is on, we can modify
45 timePrecision 6;
46 all these entries while we are running the simulation.
47 runTimeModifiable true;
214
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the pisoFoam solver.
nCorrector 1
Time = 350
Courant number
Courant Number mean: 0.11299953 max: 0.87674198
DILUPBiCG: Solving for Ux, Initial residual = 0.0037946307, Final residual = 4.8324843e-09, No Iterations 3
DILUPBiCG: Solving for Uy, Initial residual = 0.011990022, Final residual = 5.8815028e-09, No Iterations 3
GAMG: Solving for p, Initial residual = 0.022175872, Final residual = 6.2680545e-07, No Iterations 14
GAMG: Solving for p, Initial residual = 0.0033723932, Final residual = 5.8494331e-07, No Iterations 8
nNonOrthogonalCorrectors 2
GAMG: Solving for p, Initial residual = 0.0010074964, Final residual = 4.4726195e-07, No Iterations 7
time step continuity errors : sum local = 1.9569266e-11, global = -3.471923e-14, cumulative = -2.8708402e-10
GAMG: Solving for p, Initial residual = 0.0023505548, Final residual = 9.9222424e-07, No Iterations 8
GAMG: Solving for p, Initial residual = 0.00045248026, Final residual = 7.7250386e-07, No Iterations 6
GAMG: Solving for p, Initial residual = 0.00014664077, Final residual = 4.5825218e-07, No Iterations 5 pFinal
time step continuity errors : sum local = 2.0062733e-11, global = 1.2592813e-13, cumulative = -2.8695809e-10
ExecutionTime = 746.46 s ClockTime = 807 s
215
Flow past a cylinder – From laminar to turbulent flow
Let us use a potential solver to find a quick solution
• In this case we are going to use the potential solver potentialFoam (remember potential
solvers are inviscid, irrotational and incompressible)
• This solver is super fast and it can be used to find a solution to be used as initial conditions
(non-uniform field) for an incompressible solver.
• A good initial condition will accelerate and improve the convergence rate.
• This case is already setup in the directory
$PTOFC/101OF/vortex_shedding/c4
216
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us use a potential solver to find a quick solution
1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> potentialFoam –noFunctionObjects –initialiseUBCs –writep -writePhi
6. $> paraFoam
217
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us use a potential solver to find a quick solution
• In step 2 we generate the mesh using blockMesh. The name and type of the
patches are already set in the dictionary blockMeshDict so there is no need to
modify the boundary file.
• In step 4 we copy the original files to the directory 0. We do this to keep a backup of
the original files as they will be overwritten by the solver potentialFoam.
• In step 5 we run the solver. We use the option –noFunctionObjects to avoid
conflicts with the functionobjects. The options –writep and –writePhi will write
the pressure field and fluxes respectively.
• At this point, if you want to use this solution as initial conditions for an incompressible
solver, just copy the files U and p into the start directory of the incompressible case
you are looking to run. Have in mind that the meshes need to be the same.
• Be careful with the name and type of the boundary conditions, they should be same
between the potential case and incompressible case.
218
Flow past a cylinder – From laminar to turbulent flow
Potential solution
• Using a potential solution as initial conditions is much better than using a uniform
flow. It will speed up the solution and it will give you more stability.
• Finding a solution using the potential solver is inexpensive.
219
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the potentialFoam solver.
• The output of this solver is also a good indication of the sensitivity of the mesh quality
to gradients computation. If you see that the number of iterations are dropping
iteration after iteration, it means that the mesh is fine.
• If the number of iterations remain stalled, it means that the mesh is sensitive to
gradients, so you should use non-orthogonal correction.
• In this case we have a good mesh.
End
220
Flow past a cylinder – From laminar to turbulent flow
Let us map a solution from a coarse mesh to a finer mesh
• It is also possible to map the solution from a coarse mesh to a finer mesh (and all the
way around).
• For instance, you can compute a full Navier-Stokes solution in a coarse mesh (fast
solution), and then map it to a finer mesh.
• Let us map the solution from the potential solver to a finer mesh (if you want you can
map the solution obtained using pisoFoam or icoFoam). To do this we will use the
utility mapFields.
• This case is already setup in the directory
$PTOFC/101OF/vortex_shedding/c6
221
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us map a solution from a coarse mesh to a finer mesh
1. $> foamCleanTutorials
2. $> blockMesh
3. $> rm –rf 0
4. $> cp –r 0_org 0
5. $> mapfields ../c4 –consistent –noFunctionObjects –mapMethod cellPointInterpolate -sourceTime 0
6. $> paraFoam
222
Flow past a cylinder – From laminar to turbulent flow
Running the case – Let us map a solution from a coarse mesh to a finer mesh
• In step 2 we generate a finer mesh using blockMesh. The name and type of the
patches are already set in the dictionary blockMeshDict so there is no need to
modify the boundary file.
• In step 4 we copy the original files to the directory 0. We do this to keep a backup of
the original files as they will be overwritten by the utility mapFields.
• In step 5 we use the utility mapFields with the following options:
• We copy the solution from the directory ../c4
• The options –consistent is used when the domains and BCs are the same.
• The option –noFunctionObjects is used to avoid conflicts with the
functionObjects.
• The option –mapMethod cellPointInterpolate defines the interpolation
method.
• The option -sourceTime 0 defines the time from which we want to interpolate
the solution.
223
Flow past a cylinder – From laminar to turbulent flow
The meshes and the mapped fields
mapFields
224
Flow past a cylinder – From laminar to turbulent flow
The output screen
• This is the output screen of the mapFields utility.
• The utility mapFields, will try to interpolate all fields in the source directory.
• You can control the target time via the startFrom and startTime keywords in the
controlDict dictionary file.
Source: "/home/joegi/my_cases_course/6x/101OF/vortex_shedding" "c5" Source case
Target: "/home/joegi/my_cases_course/6x/101OF/vortex_shedding" "c6" Target case
Mapping method: cellPointInterpolate Interpolation method
Source mesh size: 9200 Target mesh size: 36800 Source and target mesh cell count
interpolating Phi
interpolating p Interpolated fields
interpolating U
End
• Finally, after mapping the solution, you can run the solver in the usual way. The solver
will use the mapped solution as initial conditions. 225
Flow past a cylinder – From laminar to turbulent flow
Setting a turbulent case
• So far we have used laminar incompressible solvers.
• Let us do a turbulent simulation.
• When doing turbulent simulations, we need to choose the turbulence model, define
the boundary and initial conditions for the turbulent quantities, and modify the
fvSchemes and fvSolution dictionaries to take account for the new variables we
are solving (the transported turbulent quantities).
• This case is already setup in the directory
$PTOFC/101OF/vortex_shedding/c14
226
Flow past a cylinder – From laminar to turbulent flow
• The following dictionaries remain unchanged
• system/blockMeshDict
• constant/polyMesh/boundary
• 0/p
• 0/U
16 transportModel Newtonian;
17
19 nu nu [ 0 2 -1 0 0 0 0 ] 0.0002;
• Reminder:
• The diameter of the cylinder is 2.0 m.
• And we are targeting for a Re = 10000.
228
Flow past a cylinder – From laminar to turbulent flow
The turbulenceProperties dictionary file
• This dictionary file is located in the directory constant.
• In this dictionary file we select what model we would like to use (laminar or turbulent).
• In this case we are interested in modeling turbulence, therefore the dictionary is as follows
• If you want to know the models available use the banana method.
229
Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary
17 application pimpleFoam;
• This case will start from the last saved solution (startFrom). If there is
18 no solution, the case will start from time 0 (startTime).
20 startFrom latestTime;
21 • It will run up to 500 seconds (endTime).
22 startTime 0;
23 • The initial time step of the simulation is 0.001 seconds (deltaT).
24 stopAt endTime;
25
26 endTime 500;
• It will write the solution every 1 second (writeInterval) of simulation time
27 (runTime).
28 deltaT 0.001;
32 • It will keep all the solution directories (purgeWrite).
33 writeControl runTime;
41 • It will save the solution in ascii format (writeFormat).
42 writeInterval 1;
43
50 purgeWrite 0;
• The write precision is 8 digits (writePrecision).
51
52 writeFormat ascii; • And as the option runTimeModifiable is on, we can modify all these
53 entries while we are running the simulation.
54 writePrecision 8;
55 • In line 64 we turn on the option adjustTimeStep. This option will
56 writeCompression off;
57 automatically adjust the time step to achieve the maximum desired
58 timeFormat general; courant number maxCo (line 66).
59
60 timePrecision 6; • We also set a maximum time step maxDeltaT in line 67.
61
62 runTimeModifiable yes; • Remember, the first time step of the simulation is done using the value
63
64 adjustTimeStep yes; set in line 28 and then it is automatically scaled to achieve the desired
65 maximum values (lines 66-67).
66 maxCo 0.9;
67 maxDeltaT 0.1; • The feature adjustTimeStep is only present in the PIMPLE family
solvers, but it can be added to any solver by modifying the source code.
230
Flow past a cylinder – From laminar to turbulent flow
The fvSchemes dictionary
231
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary
17 solvers
• To solve the pressure (p) we are using the GAMG method, with an
18 { absolute tolerance of 1e-6 and a relative tolerance relTol of 0.001.
31 p Notice that we are fixing the number of minimum iterations (minIter).
32 {
33 solver GAMG;
34 tolerance 1e-6;
• To solve the final pressure correction (pFinal) we are using the PCG
35 relTol 0.001; method with the DIC preconditioner, with an absolute tolerance of 1e-6
36 smoother GaussSeidel; and a relative tolerance relTol of 0.
37 nPreSweeps 0;
38 nPostSweeps 2;
39 cacheAgglomeration on;
• Notice that we can use different methods between p and pFinal. In this
40 agglomerator faceAreaPair; case we are using a tighter tolerance for the last iteration.
41 nCellsInCoarsestLevel 100;
42 mergeLevels 1; • We are also fixing the number of minimum iterations (minIter). This
44 minIter 2;
45 }
entry is optional.
46
47 pFinal • To solve U we are using the solver PBiCGStab with the DILU
48 { preconditioner, an absolute tolerance of 1e-8 and a relative tolerance
49 solver PCG;
50 preconditioner DIC;
relTol of 0. Notice that we are fixing the number of minimum iterations
51 tolerance 1e-06; (minIter).
52 relTol 0;
54 minIter 3;
55 }
56
57 U
58 {
59 solver PBiCGStab;
60 preconditioner DILU;
61 tolerance 1e-08;
62 relTol 0;
63 minIter 3;
64 }
232
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary
17 solvers
• To solve UFinal we are using the solver PBiCGStab with an absolute
18 { tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
77 UFinal fixing the number of minimum iterations (minIter).
78 {
79 solver PBiCGStab;
80 preconditioner DILU;
• To solve omega and omegaFinal we are using the solver PBiCGStab
81 tolerance 1e-08; with an absolute tolerance of 1e-8 and a relative tolerance relTol of 0.
82 relTol 0; Notice that we are fixing the number of minimum iterations (minIter).
83 minIter 3;
84 }
85
• To solve k we are using the solver PBiCGStab with an absolute
86 omega tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
87 { fixing the number of minimum iterations (minIter).
88 solver PBiCGStab;
89 preconditioner DILU;
90 tolerance 1e-08;
91 relTol 0;
92 minIter 3;
93 }
94
95 omegaFinal
96 {
97 solver PBiCGStab;
98 preconditioner DILU;
99 tolerance 1e-08;
100 relTol 0;
101 minIter 3;
102 }
103
104 k
105 {
106 solver PBiCGStab;
107 preconditioner DILU;
108 tolerance 1e-08;
109 relTol 0;
110 minIter 3;
111 }
233
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary
113 kFinal
• To solve kFinal we are using the solver PBiCGStab with an absolute
114 { tolerance of 1e-8 and a relative tolerance relTol of 0. Notice that we are
115 solver PBiCGStab; fixing the number of minimum iterations (minIter).
116 preconditioner DILU;
117 tolerance 1e-08;
118 relTol 0;
• In lines 123-133 we setup the entries related to the pressure-velocity
119 minIter 3; coupling method used (PIMPLE in this case). Setting the keyword
120 } nOuterCorrectors to 1 is equivalent to running using the PISO method.
121 }
122
123 PIMPLE
• To gain more stability we are using 1 outer correctors
124 { (nOuterCorrectors), 3 inner correctors or PISO correctors
126 nOuterCorrectors 1; (nCorrectors), and 1 correction due to non-orthogonality
127 //nOuterCorrectors 2;
128 (nNonOrthogonalCorrectors).
129 nCorrectors 3;
130 nNonOrthogonalCorrectors 1; • Remember, adding corrections increase the computational cost.
133 }
134 • In lines 135-147 we setup the under relaxation factors used during the
135 relaxationFactors
136 {
outer corrections (pseudo transient iterations). If you are working in
137 fields PISO mode (only one outer correction or nOuterCorrectors), these
138 { values are ignored.
139 p 0.3;
140 }
141 equations
142 {
143 U 0.7;
144 k 0.7;
145 omega 0.7;
146 }
147 }
234
Flow past a cylinder – From laminar to turbulent flow
• The following dictionaries are new
• 0/k
• 0/omega
• 0/nut
These are the field variables related to the closure equations of the turbulent
model.
235
Flow past a cylinder – From laminar to turbulent flow
Turbulence model free-stream boundary conditions
• The initial value for the turbulent kinetic energy can be found as follows
• The initial value for the specific kinetic energy can be found as follows
• If you are working with external aerodynamics or virtual wind tunnels, you can use the following
reference values for the turbulence intensity and the viscosity ratio. They work most of the
times, but it is a good idea to have some experimental data or a better initial estimate.
1 10 100
236
Flow past a cylinder – From laminar to turbulent flow
The file 0/k
19 internalField uniform 0.00015;
20 • We are using uniform initial conditions (line 19).
21 boundaryField
22 { • For the in patch we are using a fixedValue boundary
23 out
24 { condition.
25 type inletOutlet;
26 inletValue uniform 0.00015; • For the out patch we are using an inletOutlet boundary
27 value uniform 0.00015;
28 } condition (this boundary condition avoids backflow).
29 sym1
30
31
{
type symmetryPlane;
• For the cylinder patch (which is base type wall), we
32 } are using the kqRWallFunction boundary condition.
33 sym2
34 {
This is a wall function, we are going to talk about this
35 type symmetryPlane; when we deal with turbulence modeling. Remember,
36 }
37 in we can use wall functions only if the patch is of base
38 {
39 type fixedValue;
type wall.
40 value uniform 0.00015;
41 } • The rest of the patches are constrained.
42 cylinder
43
44
{
type kqRWallFunction;
• FYI, the inlet velocity is 1 and the turbulence intensity is
45 value uniform 0.00015; equal to 1%.
46 }
47
48
back
{
• We will study with more details how to setup the
49 type empty; boundary conditions when we deal with turbulence
50 }
51 front modeling in the advanced modules.
52 {
53 type empty;
54 }
55 }
237
Flow past a cylinder – From laminar to turbulent flow
The file 0/omega
19 internalField uniform 0.075;
20
21 boundaryField • We are using uniform initial conditions (line 19).
22 {
23 out • For the in patch we are using a fixedValue boundary
24 {
25 type inletOutlet; condition.
26 inletValue uniform 0.075;
27
28 }
value uniform 0.075; • For the out patch we are using an inletOutlet boundary
29 sym1 condition (this boundary condition avoids backflow).
30 {
31
32 }
type symmetryPlane;
• For the cylinder patch (which is base type wall), we
33 sym2 are using the omegaWallFunction boundary condition.
34 {
35 type symmetryPlane; This is a wall function, we are going to talk about this
36
37
}
in
when we deal with turbulence modeling. Remember, we
38 { can use wall functions only if the patch is of base type
39 type fixedValue;
40 value uniform 0.075;
wall.
41 }
42 cylinder • The rest of the patches are constrained.
43 {
44
45
type
Cmu
omegaWallFunction;
0.09;
• FYI, the inlet velocity is 1 and the eddy viscosity ratio is
46 kappa 0.41; equal to 10.
47 E 9.8;
48
49
beta1
value
0.075;
uniform 0.075;
• We will study with more details how to setup the
50 } boundary conditions when we deal with turbulence
51 back
52 { modeling in the advanced modules.
53 type empty;
54 }
55 front
56 {
57 type empty;
58 }
59 }
238
Flow past a cylinder – From laminar to turbulent flow
The file 0/nut
19 internalField uniform 0;
20 • We are using uniform initial conditions (line 19).
21 boundaryField
22
23
{
out
• For the in patch we are using the calculated boundary
24 { condition (nut is computed from kappa and omega)
25 type calculated;
26
27 }
value uniform 0; • For the out patch we are using the calculated
28 sym1 boundary condition (nut is computed from kappa and
29 {
30 type symmetryPlane; omega)
31 }
32 sym2 • For the cylinder patch (which is base type wall), we
33 {
34 type symmetryPlane; are using the nutkWallFunction boundary condition.
35
36
}
in
This is a wall function, we are going to talk about this
37 { when we deal with turbulence modeling. Remember, we
38 type calculated;
39 value uniform 0;
can use wall functions only if the patch is of base type
40 } wall.
41 cylinder
42 {
43 type nutkWallFunction; • The rest of the patches are constrained.
44 Cmu 0.09;
45 kappa 0.41; • Remember, the turbulent viscosity (nut) is equal to
46 E 9.8;
47 value uniform 0;
48 }
49 back
50 {
51 type empty;
52 } • We will study with more details how to setup the
53 front
54 { boundary conditions when we deal with turbulence
55 type empty;
56 }
modeling in the advanced modules.
57 }
239
Flow past a cylinder – From laminar to turbulent flow
Running the case – Setting a turbulent case
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c14
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this case we will use
blockMesh.
• To run this case, in the terminal window type:
1. $> foamCleanTutorials
2. $> blockMesh
3. $> renumberMesh -overwrite
$> pimpleFoam | tee log.solver
4.
You will need to launch this script in a different terminal
8. $> paraFoam
240
Flow past a cylinder – From laminar to turbulent flow
Running the case – Setting a turbulent case
• In step 3 we use the utility renumberMesh to make the linear system more diagonal
dominant, this will speed-up the linear solvers.
• In step 4 we run the simulation and save the log file. Notice that we are sending the
job to background.
• In step 5 we use pyFoamPlotWatcher.py to plot the residuals on-the-fly. As the
job is running in background, we can launch this utility in the same terminal tab.
• In step 6 we use the gnuplot script scripts0/plot_coeffs to plot the force
coefficients on-the-fly. Besides monitoring the residuals, is always a good idea to
monitor a quantity of interest. Feel free to take a look at the script and to reuse it.
• In step 7 we use the utility postProcess to compute the value of each saved
solution (we are going to talk about when we deal with turbulence modeling).
241
Flow past a cylinder – From laminar to turbulent flow
pimpleFoam output screen
Courant Number mean: 0.088931706 max: 0.90251464 Courant number
deltaT = 0.040145538 Time step
Time = 499.97 Simulation time
PIMPLE: iteration 1 Outer iteration 1 (nOuterCorrectors)
DILUPBiCG: Solving for Ux, Initial residual = 0.0028528538, Final residual = 9.5497298e-11, No Iterations 3
DILUPBiCG: Solving for Uy, Initial residual = 0.0068876991, Final residual = 7.000938e-10, No Iterations 3
GAMG: Solving for p, Initial residual = 0.25644342, Final residual = 0.00022585963, No Iterations 7
GAMG: Solving for p, Initial residual = 0.0073871161, Final residual = 5.2798526e-06, No Iterations 8
time step continuity errors : sum local = 3.2664019e-10, global = -1.3568363e-12, cumulative = -9.8446438e-08
GAMG: Solving for p, Initial residual = 0.16889316, Final residual = 0.00014947209, No Iterations 7
GAMG: Solving for p, Initial residual = 0.0051876466, Final residual = 3.7123156e-06, No Iterations 8
time step continuity errors : sum local = 2.2950163e-10, global = -8.0710768e-13, cumulative = -9.8447245e-08
PIMPLE: iteration 2 Outer iteration 2 (nOuterCorrectors)
DILUPBiCG: Solving for Ux, Initial residual = 0.0013482181, Final residual = 4.1395468e-10, No Iterations 3
DILUPBiCG: Solving for Uy, Initial residual = 0.0032433196, Final residual = 3.3969121e-09, No Iterations 3
GAMG: Solving for p, Initial residual = 0.10067317, Final residual = 8.9325549e-05, No Iterations 7
GAMG: Solving for p, Initial residual = 0.0042844521, Final residual = 3.0190597e-06, No Iterations 8
time step continuity errors : sum local = 1.735023e-10, global = -2.0653335e-13, cumulative = -9.8447452e-08
GAMG: Solving for p, Initial residual = 0.0050231165, Final residual = 3.2656397e-06, No Iterations 8
DICPCG: Solving for p, Initial residual = 0.00031459519, Final residual = 9.4260163e-07, No Iterations 36 pFinal
time step continuity errors : sum local = 5.4344408e-11, global = 4.0060595e-12, cumulative = -9.8443445e-08
DILUPBiCG: Solving for omega, Initial residual = 0.00060510266, Final residual = 1.5946601e-10, No Iterations 3
DILUPBiCG: Solving for k, Initial residual = 0.0032163247, Final residual = 6.9350899e-10, No Iterations 3
bounding k, min: -3.6865398e-05 max: 0.055400108 average: 0.0015914926
ExecutionTime = 1689.51 s ClockTime = 1704 s
Time = 500.01
Reading field U
Writing yPlus to field yPlus Writing the field to the solution directory
243
Flow past a cylinder – From laminar to turbulent flow
Using a compressible solver
• So far we have only used incompressible solvers.
• Let us use the compressible solver rhoPimpleFoam, which is a,
Transient solver for laminar or turbulent flow of compressible fluids for HVAC and
similar applications. Uses the flexible PIMPLE (PISO-SIMPLE) solution for time-
resolved and pseudo-transient simulations.
$PTOFC/101OF/vortex_shedding/c24
244
Flow past a cylinder – From laminar to turbulent flow
• The following dictionaries remain unchanged
• system/blockMeshDict
• constant/polyMesh/boundary
• Reminder:
• The diameter of the cylinder is 0.002 m.
• The working fluid is air at 20° Celsius and at a sea level.
• Isothermal flow.
• And we are targeting for a Re = 200.
245
Flow past a cylinder – From laminar to turbulent flow
The constant directory
• thermophysicalProperties
• turbulenceProperties
246
Flow past a cylinder – From laminar to turbulent flow
The thermophysicalProperties dictionary file
247
Flow past a cylinder – From laminar to turbulent flow
The thermophysicalProperties dictionary file
248
Flow past a cylinder – From laminar to turbulent flow
The turbulenceProperties dictionary file
• In this dictionary file we select what model we would like to use (laminar or
turbulent).
• This dictionary is compulsory.
• As we do not want to model turbulence, the dictionary is defined as follows,
17 simulationType laminar;
249
Flow past a cylinder – From laminar to turbulent flow
The 0 directory
• In this directory, we will find the dictionary files that contain the boundary and
initial conditions for all the primitive variables.
• As we are solving the compressible laminar Navier-Stokes equations, we will
find the following field files:
• p (pressure)
• T (temperature)
• U (velocity field)
250
Flow past a cylinder – From laminar to turbulent flow
The file 0/p
• This file contains the boundary and initial conditions
17 dimensions [1 -1 -2 0 0 0 0];
18
for the scalar field pressure (p). We are working
19 internalField uniform 101325; with absolute pressure.
20
21
22
boundaryField
{
• Contrary to incompressible flows where we defined
23 in relative pressure, this is the absolute pressure.
24 {
25
26 }
type zeroGradient;
• Also, pay attention to the units (line 17). The
28 out pressure is defined in Pascal.
29 {
30
31
type
value
fixedValue;
uniform 101325;
• We are using uniform initial conditions (line 19).
32 }
34 cylinder • For the in patch we are using a zeroGradient
35 {
36 type zeroGradient; boundary condition.
37 }
39 sym1 • For the outlet patch we are using a fixedValue
40 {
41 type symmetryPlane; boundary condition.
42 }
44 sym2 • For the cylinder patch we are using a zeroGradient
45 {
46 type symmetryPlane; boundary condition.
47 }
49 back • The rest of the patches are constrained.
50 {
51 type empty;
52 }
54 front
55 {
56 type empty;
57 }
58 }
251
Flow past a cylinder – From laminar to turbulent flow
The file 0/T
17 dimensions [0 0 0 -1 0 0 0];
• This file contains the boundary and initial conditions
18 for the scalar field temperature (T).
19 internalField uniform 293.15;
20
21 boundaryField • Also, pay attention to the units (line 17). The
22 { temperature is defined in Kelvin.
23 in
24 {
25 type fixedValue; • We are using uniform initial conditions (line 19).
26 value $internalField;
27 } • For the in patch we are using a fixedValue boundary
29 out
30 { condition.
31 type inletOutlet;
32 value $internalField; • For the out patch we are using a inletOutlet
33 inletValue $internalField;
34 } boundary condition (in case of backflow).
36 cylinder
37 { • For the cylinder patch we are using a zeroGradient
38 type zeroGradient;
39 } boundary condition.
41 sym1
42 { • The rest of the patches are constrained.
43 type symmetryPlane;
44 }
46 sym2
47 {
48 type symmetryPlane;
49 }
51 back
52 {
53 type empty;
54 }
56 front
57 {
58 type empty;
59 }
60 }
252
Flow past a cylinder – From laminar to turbulent flow
The file 0/U
17 dimensions [0 1 -1 0 0 0 0];
18 • This file contains the boundary and initial conditions
19 internalField uniform (1.5 0 0); for the dimensional vector field U.
20
21 boundaryField
22 { • We are using uniform initial conditions and the
23 in
24 {
numerical value is (1.5 0 0) (keyword internalField in
25 type fixedValue; line 19).
26 value uniform (1.5 0 0);
27
29
}
out
• For the in patch we are using a fixedValue boundary
30 { condition.
31 type inletOutlet;
32
33
phi
inletValue
phi;
uniform (0 0 0);
• For the out patch we are using a inletOutlet
34 value uniform (0 0 0); boundary condition (in case of backflow).
35 }
37 cylinder
38 {
• For the cylinder patch we are using a zeroGradient
39 type fixedValue; boundary condition.
40 value uniform (0 0 0);
41 }
43 sym1 • The rest of the patches are constrained.
44 {
45 type symmetryPlane;
46 }
48 sym2
49 {
50 type symmetryPlane;
51 }
53 back
54 {
55 type empty;
56 }
58 front
59 {
60 type empty;
61 }
62 }
253
Flow past a cylinder – From laminar to turbulent flow
The system directory
254
Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary
17 application rhoPimpleFoam;
• This case will start from the last saved solution (startFrom). If there is
18 no solution, the case will start from time 0 (startTime).
19 startFrom startTime;
20 //startFrom latestTime; • It will run up to 0.3 seconds (endTime).
21
22 startTime 0; • The initial time step of the simulation is 0.00001 seconds (deltaT).
23
24 stopAt endTime;
25 //stopAt writeNow;
• It will write the solution every 0.0025 seconds (writeInterval) of
26 simulation time (adjustableRunTime). The option adjustableRunTime
27 endTime 0.3; will adjust the time-step to save the solution at the precise intervals. This
28
29 deltaT 0.00001; may add some oscillations in the solution as the CFL is changing.
30
31 writeControl adjustableRunTime; • It will keep all the solution directories (purgeWrite).
32
33 writeInterval 0.0025; • It will save the solution in ascii format (writeFormat).
34
35 purgeWrite 0; • And as the option runTimeModifiable is on, we can modify all these
36
37 writeFormat ascii; entries while we are running the simulation.
38
39 writePrecision 10; • In line 49 we turn on the option adjustTimeStep. This option will
40 automatically adjust the time step to achieve the maximum desired
41 writeCompression off;
42 courant number (line 50).
43 timeFormat general;
44 • We also set a maximum time step in line 51.
45 timePrecision 6;
46 • Remember, the first time step of the simulation is done using the value
47 runTimeModifiable true;
set in line 28 and then it is automatically scaled to achieve the desired
48
49 adjustTimeStep yes; maximum values (lines 66-67).
50 maxCo 1;
51 maxDeltaT 1; • The feature adjustTimeStep is only present in the PIMPLE family
solvers, but it can be added to any solver by modifying the source code.
255
Flow past a cylinder – From laminar to turbulent flow
The controlDict dictionary
235
236 };
256
Flow past a cylinder – From laminar to turbulent flow
The fvSchemes dictionary
257
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary
17 solvers • To solve the pressure (p) we are using the PCG method with
18 { an absolute tolerance of 1e-6 and a relative tolerance relTol
20 p
21 { of 0.01.
22 solver PCG;
23
24
preconditioner
tolerance
DIC;
1e-06;
• The entry pFinal refers to the final correction of the PISO
25 relTol 0.01; loop. Notice that we are using macro expansion ($p) to copy
26 minIter 2;
27 } the entries from the sub-dictionary p.
46 pFinal
47 { • To solve U and UFinal (U.*) we are using the solver
48 $p;
49 relTol 0; PBiCGStab with an absolute tolerance of 1e-8 and a relative
50 minIter 2;
51 }
tolerance relTol of 0.
53 "U.*"
54 { • To solve hFinal (enthalpy) we are using the solver
55 solver PBiCGStab;
56 preconditioner DILU;
PBiCGStab with an absolute tolerance of 1e-8 and a relative
57 tolerance 1e-08; tolerance relTol of 0.
58 relTol 0;
59
60 }
minIter 2;
• To solve rho and rhoFinal (rho.*) we are using the diagonal
74 hFinal solver (remember rho is found from the equation of state, so
75 {
76 solver PBiCGStab; this is a back-substitution).
77 preconditioner DILU;
78 tolerance 1e-08; • FYI, solving for the velocity is relative inexpensive, whereas
79 relTol 0;
80 minIter 2; solving for the pressure is expensive.
81 }
83 "rho.*" • Be careful with the enthalpy, it might cause oscillations.
84 {
85 solver diagonal;
86 }
87 }
258
Flow past a cylinder – From laminar to turbulent flow
The fvSolution dictionary
259
Flow past a cylinder – From laminar to turbulent flow
Running the case – Using a compressible solver
• You will find this tutorial in the directory $PTOFC/101OF/vortex_shedding/c24
• Feel free to use the Fluent mesh or the mesh generated with blockMesh. In this case we will use
blockMesh.
• To run this case, in the terminal window type:
1. $> foamCleanTutorials
2. $> blockMesh
3. $> transformPoints –scale ‘(0.001 0.001 0.001)’
4. $> renumberMesh -overwrite
5. $> rhoPimpleFoam | tee log
$> pyFoamPlotWatcher.py log
6.
You will need to launch this script in a different terminal
261
Flow past a cylinder – From laminar to turbulent flow
rhoPimpleFoam output screen
Courant Number mean: 0.1280224248 max: 0.9885863338 Courant number
deltaT = 3.816512052e-05 Time step
Time = 0.3
diagonal: Solving for rho, Initial residual = 0, Final residual = 0, No Iterations 0 Solving for density (rho)
PIMPLE: iteration 1
DILUPBiCG: Solving for Ux, Initial residual = 0.003594731129, Final residual = 3.026673755e-11, No Iterations 5
DILUPBiCG: Solving for Uy, Initial residual = 0.01296036298, Final residual = 1.223236662e-10, No Iterations 5
DILUPBiCG: Solving for h, Initial residual = 0.01228951539, Final residual = 2.583236461e-09, No Iterations 4 h residuals
DICPCG: Solving for p, Initial residual = 0.01967621449, Final residual = 8.797612158e-07, No Iterations 77
DICPCG: Solving for p, Initial residual = 0.003109422612, Final residual = 9.943030465e-07, No Iterations 69
diagonal: Solving for rho, Initial residual = 0, Final residual = 0, No Iterations 0
time step continuity errors : sum local = 6.835363016e-11, global = 4.328592697e-12, cumulative = 2.366774797e-09
rho max/min : 1.201420286 1.201382023 pFinal
DICPCG: Solving for p, Initial residual = 0.003160602108, Final residual = 9.794177338e-07, No Iterations 69
DICPCG: Solving for p, Initial residual = 0.0004558492254, Final residual = 9.278622052e-07, No Iterations 58
diagonal: Solving for rho, Initial residual = 0, Final residual = 0, No Iterations 0 Solving for density (rhoFinal)
time step continuity errors : sum local = 6.38639685e-11, global = 1.446434866e-12, cumulative = 2.368221232e-09
rho max/min : 1.201420288 1.201381976 Max/min density values
ExecutionTime = 480.88 s ClockTime = 490 s
263
Flow past a cylinder – From laminar to turbulent flow
• This is what you will find in each directory,
• 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.
• c19 = blockMesh – pimpleFoam – Re = 1000000 – Spalart Allmaras turbulent model with no wall
functions.
• c20 = blockMesh – sonicFoam – Mach = 2.0 – Compressible – Laminar.
• c21 = blockMesh – sonicFoam – Mach = 2.0 – Compressible – K-Omega SST turbulent model with wall
functions.
• c22 = blockMesh – pimpleFoam – Re = 200 – No turbulent model – Source terms (momentum)
• c23 = blockMesh – pimpleFoam – Re = 200 – No turbulent model – Source terms (scalar transport)
• c24 = blockMesh – rhoPimpleFoam – Re = 200 – Laminar, isothermal
• c25 = blockMesh – rhoPimpleFoam – Re = 20000 – Turbulent, compressible
• c26 = blockMesh – pimpleDyMFoam – Re = 200 – Laminar, moving cylinder (oscillating).
• c27 = blockMesh – pimpleDyMFoam/pimpleFoam – Re = 200 – Laminar, rotating cylinder using AMI
patches.
• c28 = blockMesh – interFoam – Laminar, multiphase, free surface.
• c29 = blockMesh – pimpleFoam laminar with source terms and AMR.
264
Module 2
Solid modeling
265
Roadmap
266
Solid modeling – Preliminaries
• There is no wrong or right way when doing solid modeling for CFD. The
only rule you should keep in mind is that by the end of the day you should
get a smooth, clean, and watertight geometry.
• A watertight geometry means a close body with no holes or overlapping
surfaces.
• Have in mind that the quality of the mesh and hence of the solution, greatly
depends on the geometry. So always do your best when creating the
geometry.
• During this solid modeling session we are going to show you how to get
started with the geometry generation tools. The rest is on you.
• The best way to learn how to use these tools is by doing.
267
Solid modeling – Preliminaries
• There are always many ways to accomplish a task when creating a
geometry, this give you the freedom to work in a way that is comfortable to
you. Hereafter we are going to show you our way.
• Before starting to create your geometry, think about a strategy to employ to
create your design, this is what we call design intent.
• Choose one feature over other.
• Dimensioning strategy.
• Order of the operations.
• Parametrization.
• Single or multiple parts.
• Do I need to parametrize my design or should I use direct modeling?
• We are going to work with design intent during the hands-on sessions.
268
Solid modeling – Preliminaries
Geometry defeaturing
• Many times, it is not necessary to model all the details of the geometry. In these cases you
should consider simplifying the geometry (geometry defeaturing).
• Geometry defeaturing can save you a lot of time when generating the mesh. So be smart,
and use it whenever is possible.
Do we really need to
capture the fillet details?
Do we need to
model the flange?
269
Solid modeling – Preliminaries
Geometry defeaturing
• Would you use all these geometry details for a CFD simulations?
270
Solid modeling using Onshape
• Onshape is a professional CAD/solid modeling application.
• It provides powerful parametric and direct modeling capabilities.
• It is cloud based therefore you do not need to install any software.
• Documents are shareable.
• Multiple users can work in the same document at the same time
(simultaneous editing).
• It runs in any device with a working web browser.
• Users can implement their own features using Onshape scripting language
(featureScript).
• Users can access and modify documents in a programmatic way using
python or nodejs.
• It is freely available for educational use.
• To start using onshape register at: https://cad.onshape.com/
271
Solid modeling using Onshape
• Even if you have not used a CAD software before, you will find the GUI easy to use.
• You will notice that there is no save button because everything you do is
automatically saved.
Help
Versioning, branching, and history menu Toolbar
Feature list
Parts list
3D area
Document tabs 272
Solid modeling using Onshape
• Mouse interaction in the 3D area (it can be configure in the preference area).
Selection
Rotate
Pan
Zoom
Feature toolbar:
Sketch toolbar:
274
Solid modeling using Onshape
• Let us create this solid using the dimensions illustrated.
276
Solid modeling using Onshape
• In the part studio page, select the top plane and start a new sketch.
277
Solid modeling using Onshape
• In the part studio page, select the top plane and start a new sketch.
278
Solid modeling using Onshape
• Using the sketching features, draw the following line.
When you are done sketching
press the checkmark
Origin
280
Solid modeling using Onshape
• Use the sweep feature to create a new solid.
Select the circle as the Select new solid Select the lines as the
face to sweep sweep patch
Sweep feature
281
Solid modeling using Onshape
• At this point, you should have this solid.
Solid name.
Right click to rename
or view the properties
282
Solid modeling using Onshape
• Let us add the new inlet to the pipe.
• Create a new sketch in the top plane or edit the initial sketch.
• Hereafter we will edit the initial sketch.
283
Solid modeling using Onshape
• Create a plane normal to a line and passing through a point
284
Solid modeling using Onshape
• Sketch a circle in the newly created plane.
New plane
285
Solid modeling using Onshape
• Using the feature extrude to create a new solid using the previous sketch.
• Extrude the circle until in intercept the solid.
Add the new solid to the previous part (boolean operation)
Feature extrusion
287
Solid modeling using Onshape
• If you want to know the mass properties of the solid, select it, and then click on the
mass properties icon.
• To get the inertia, you will need to assign a material.
288
Solid modeling using Onshape
• To export the solid model, right click on the part name and select the option export.
• Choose the desired format. In this case choose STL.
289
Solid modeling using Onshape
• Parametric modeling and feature-based modeling are two of the most powerful tools
available in any CAD/solid modeling applications.
• They are crucial components in the design experience, especially when dealing with
design intent.
• Experimenting with dimension schemes is one of the best ways to improve your
understanding of design intent.
• To learn more about Onshape, you can visit their learning center:
https://learn.onshape.com/
• Finally, feel free to visit our youtube channel where you will find a few solid modeling
videos in the context of CFD and OpenFOAM® :
https://www.youtube.com/channel/UCNNBm3KxVS1rGeCVUU1p61g
290
Module 3
Meshing preliminaries – Mesh quality
assessment – Meshing in OpenFOAM®
291
Before we begin
• OpenFOAM® comes with the following meshing applications:
• blockMesh
• snappyHexMesh
• foamyHexMesh
• foamyQuadMesh
• We are going to work with blockMesh and snappyHexMesh.
• blockMesh is a multi-block mesh generator.
• snappyHexMesh is an automatic split hex mesher, refines and snaps to surface.
• If you are not comfortable using OpenFOAM® meshing applications, you can use an
external mesher.
• OpenFOAM® comes with many mesh conversion utilities. Many popular meshing
formats are supported. To name a few: gambit, cfx, fluent, gmsh, ideas, netgen,
plot3d, starccm, VTK.
• In this module, we are going to address how to mesh using OpenFOAM®
technology, how to convert meshes to OpenFOAM® format, and how to assess
mesh quality in OpenFOAM®.
292
Before we begin
By the end of this module, you will realize that
You will use snappyHexMesh to mesh the sphinx
293
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
294
Meshing preliminaries
• Mesh generation or domain discretization consist in dividing the physical
domain into a finite number of discrete regions, called control volumes or
cells in which the solution is sought
www.wolfdynamics.com/wiki/moving/ani1.gif www.wolfdynamics.com/wiki/moving/ani2.gif
295
Meshing preliminaries
Mesh generation process
• Generally speaking, when generating the mesh we follow these three
simple steps:
• Geometry generation: we first generate the geometry that we are going
to feed into the meshing tool.
• Mesh generation: the mesh can be internal or external. We also define
surface and volume refinement regions. We can also add inflation layers
to better resolve the boundary layer. During the mesh generation
process we also check the mesh quality.
• Definition of boundary surfaces: in this step we define physical
surfaces where we are going to apply the boundary conditions. If you do
not define these individual surfaces, you will have one single surface
and it will not be possible to apply different boundary conditions.
• Remember this: Geometry is to mesh generation as turbulence modeling is
to CFD.
296
Meshing preliminaries
Geometry generation - Input geometry
• The geometry must be watertight.
• Remember, the quality of the mesh and hence the quality of the solution greatly depends on the geometry. So
always do your best when creating the geometry.
297
Meshing preliminaries
Mesh generation
• If we are interested in external aerodynamics, we define a physical domain and we mesh the region around
the body.
• If we are interested in internal aerodynamics, we simply mesh the internal volume of the geometry.
• To resolve better the flow features, we can add surface and volume refinement.
• Remember to always check the mesh quality.
298
Meshing preliminaries
Definition of boundary surfaces (patches)
• In order to assign boundary conditions, we need to create boundary surfaces (patches) where we are going to
apply the boundary values.
• The boundary surfaces (patches) are created at meshing time.
• In OpenFOAM®, you will find this information in the boundary dictionary file which is located in the directory
constant/polyMesh. This dictionary is created automatically at meshing time.
inlet outlet
top
left right
airplane
bottom 299
Meshing preliminaries
What cell type should I use?
• In the meshing world, there are many cell types. Just to name a few: tetrahedrons,
pyramids, hexahedrons, prisms, polyhedral.
• Each cell type has its very own properties when it comes to approximate the gradients
and fluxes, we are going to talk about this later on when we deal with the FVM.
• Generally speaking, hexahedral cells will give more accurate solutions under certain
conditions.
• However, this does not mean that tetra/poly cells are not good.
• What cell type do I use? It is up to you, at the end of the day the overall quality of the
final mesh should be acceptable and your mesh should resolve the physics
300
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
301
What is a good mesh?
• There is no written theory when it comes to mesh generation.
• Basically, the whole process depends on user experience and good standard
practices.
• A standard rule of thumb is that the elements shape and distribution should be
pleasing to the eye.
302
What is a good mesh?
• The user can rely on grid dependency studies, but they are time consuming and
expensive.
Cells ≈ 3 500 000 ≈ 11 000 000 ≈ 36 000 000 ≈ 105 000 000
303
What is a good mesh?
• Finally, we can rely in mesh metrics. However, no single standard
benchmark or metric exists that can effectively assess the quality of a
mesh, but the user can rely on suggested best practices.
• Hereafter, we will present the most common mesh quality metrics:
• Orthogonality.
• Skewness.
• Aspect Ratio.
• Smoothness.
• After generating the mesh, we measure these quality metrics and we use
them to assess mesh quality.
• Have in mind that there are many more mesh quality metrics out there, and
some of them are not very easy to interpret (e.g., jacobian matrix,
determinant, flatness, equivalence, condition number, and so on).
• It seems that it is much easier diagnosing bad meshes than good meshes.
304
What is a good mesh?
Mesh quality metrics. Mesh orthogonality
• Mesh orthogonality is the angular deviation of the vector S (located at the face center
f ) from the vector d connecting the two cell centers P and N. In this case is .
• Affects the gradient of the face center f.
• It adds numerical diffusion to the solution.
• It mainly affects the diffusive terms.
305
What is a good mesh?
Mesh quality metrics. Mesh skewness
• Skewness (also known as non-conjunctionality) is the deviation of the vector d that
connects the two cells P and N, from the face center f.
• The deviation vector is represented with and is the point where the vector d
intersects the face f .
• 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.
306
What is a good mesh?
Mesh quality metrics. Mesh aspect ratio AR
• Mesh aspect ratio AR is the ratio between the longest side and the shortest
side .
• Large AR are ok if gradients in the largest direction are small.
• High AR smear gradients.
307
What is a good mesh?
Mesh quality metrics. Smoothness
• Smoothness, also known as expansion rate, growth factor or uniformity, defines the
transition in size between contiguous cells.
• Large transition ratios between cells add diffusion to the solution.
• Ideally, the maximum change in mesh spacing should be less than 20%:
• Hexes, prisms, and quadrilaterals can be stretched easily to resolve boundary layers
without losing quality.
• Triangular and tetrahedral meshes have inherently larger truncation error.
• Less truncation error when faces aligned with flow direction and gradients.
Flow direction
309
What is a good mesh?
Striving for quality
• For the same cell count, hexahedral meshes will give more accurate solutions,
especially if the grid lines are aligned with the flow.
• But this does not mean that tetrahedral meshes are not good, by carefully choosing
the numerical scheme you can get the same level of accuracy as in hexahedral
meshes.
• The problem with tetrahedral meshes is mainly related to the way gradients are
computed.
Hexa
Year 310
What is a good mesh?
Striving for quality
• The mesh density should be high enough to capture all relevant flow features.
• In areas where the solution change slowly, you can use larger elements.
• A good mesh does not rely in the fact that the more cells we use the better the
solution.
A good mesh might not lead to the ideal solution, but a bad
mesh will always lead to a bad solution.
P. Baker – Pointwise
313
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
314
Mesh quality assessment in OpenFOAM®
Mesh quality metrics in OpenFOAM®
• In the file primitiveMeshCheck.C located in the directory
$WM_PROJECT_DIR/src/OpenFOAM/meshes/primitiveMesh/primitiveMeshCheck/ you will find the
quality metrics hardwired in OpenFOAM®. Their maximum (or minimum) values are defined as follows:
• You will be able to run simulations with mesh quality errors such as high skewness, high aspect ratio, and high
non-orthogonality. But remember, they will affect the solution accuracy, might give you strange results, and
eventually can made the solver blow-up.
• Have in mind that if you have bad quality meshes, you will need to adapt the numerics to deal with this kind of
meshes. We will give you our recipe later when we deal with the numerics.
• You should avoid as much as possible non-orthogonality values close to 90. This is an indication that you have
zero-volume cells.
• In overall, large aspect ratios do not represent a problem. It is just an indication that you have very fine
meshes (which is the case when you are resolving the boundary layer).
• The default quality metrics in OpenFOAM® seems to be a little bit conservative. In our experience, we have
found that you can run simulations with a non-orthogonality up to 80 and skewness up to 8.
315
Mesh quality assessment in OpenFOAM®
Checking the mesh quality in OpenFOAM®
• To check the mesh quality and validity, OpenFOAM® comes with the utility checkMesh.
• To use this utility, just type in the terminal checkMesh, and read the screen output.
• checkMesh will look for/check for:
• Mesh stats and overall number of cells of each type.
• Check topology (boundary conditions definitions).
• Check geometry and mesh quality (bounding box, cell volumes, skewness, orthogonality, aspect
ratio, and so on).
• If for any reason checkMesh finds errors, it will give you a message and it will tell you what check failed.
• It will also write a set with the faulty cells, faces, and/or points.
• These sets are saved in the directory constant/polyMesh/sets/
• Mesh topology and patch topology errors must be repaired.
• You will be able to run with mesh quality errors such as skewness, aspect ratio, minimum face area, and non-
orthogonality.
• But remember, they will severely tamper the solution accuracy, might give you strange results, and eventually
can made the solver blow-up.
• Unfortunately, checkMesh does not repair these errors.
• You will need to check the geometry for possible errors and generate a new mesh.
• You can visualize the failed sets directly in paraFoam .
• Alternatively, you can use the utility foamToVTK to convert the failed sets to VTK format.
316
Mesh quality assessment in OpenFOAM®
Visualizing the failed sets in OpenFOAM®
• You can load the failed sets directly within
paraFoam.
• Remember, you will need to create the sets. To
do so just run the checkMesh utility.
• If there are problems in the mesh, checkMesh
will automatically save the sets in the directory
constant/polyMesh/sets
• In paraFoam, simply select the option Include
Sets and then select the sets you want to
visualize.
• This method only works with paraFoam.
• When working with large meshes we prefer to
convert the faulty sets to VTK format using
foamToVTK. Failed sets
317
Mesh quality assessment in OpenFOAM®
Visualizing the failed sets in OpenFOAM®
• To convert the failed faces/cells/points to VTK format, you can proceed as follows:
where set_type is the type of sets (faceSet, cellSet, pointSet, surfaceFields) and
name_of_sets is the name of the set in the directory constant/polyMesh/sets
(highAspectRatioCells, nonOrthoFaces, wrongOrientedFaces, skewFaces,
unusedPoints, and so on).
• At the end, foamToVTK will create a directory named VTK, where you will find the
failed faces/cells/points in VTK format.
• At this point you can use paraview/paraFoam to open the VTK files and visualize
the failed sets.
318
Mesh quality assessment in OpenFOAM®
Checking mesh quality in OpenFOAM®
• Sample checkMesh output,
Mesh stats
points: 81812
faces: 902132
internal faces: 871012
cells: 443286
faces per cell: 4 Mesh stats
boundary patches: 9
point zones: 0
face zones: 1
cell zones: 1
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
319
Mesh quality assessment in OpenFOAM®
Checking mesh quality in OpenFOAM®
• Sample checkMesh output,
Checking patch topology for multiply connected surfaces...
Patch Faces Points Surface topology
FAIRING 1267 727 ok (non-closed singly connected)
FUSELAGE 3243 1774 ok (non-closed singly connected)
WING 15313 7706 ok (non-closed singly connected)
INLET 272 160 ok (non-closed singly connected)
OUTLET 272 160 ok (non-closed singly connected) Boundary patches
SYMM 6280 3324 ok (non-closed singly connected)
FARFIELD 3136 1645 ok (non-closed singly connected)
NOSE 76 49 ok (non-closed singly connected)
COCKPIT 1261 670 ok (non-closed singly connected)
Checking geometry...
Overall domain bounding box (-15000 -7621.0713 -7396.4536) (30048.969 0 7446.8442)
Mesh has 3 geometric (non-empty/wedge) directions (1 1 1)
Mesh has 3 solution (non-empty) directions (1 1 1)
Mesh bounding box
Boundary openness (-4.2298633e-18 8.0240802e-16 4.013988e-16) OK.
Max cell openness = 4.8098963e-16 OK.
Max aspect ratio = 29.575835 OK. Aspect ratio
Minimum face area = 0.0066721253. Maximum face area = 1037224.8. Face area magnitudes OK.
Min volume = 0.00050536842. Max volume = 3.2500889e+08. Total volume = 5.0960139e+12. Cell volumes OK.
Mesh non-orthogonality Max: 86.939754 average: 17.939523 High non-orthogonality
*Number of severely non-orthogonal (> 70 degrees) faces: 3168. But we still can run the simulation
Non-orthogonality check OK.
<<Writing 3168 non-orthogonal faces to set nonOrthoFaces
Face pyramids OK.
Max skewness = 2.5719979 OK. Skewness
Coupled point location match (average 0) OK.
Failed 1 mesh checks. The fact that one check failed does not mean that you can not run the simulation
End 320
Mesh quality assessment in OpenFOAM®
Visualization of faulty sets in paraFoam
• You will find this case ready to use in the directory,
$PTOFC/mesh_quality_manipulation/M1_wingbody
• To run the case, just follow the instructions in the README.FIRST files.
Non orthogonal faces (green spheres) and unused points (yellow spheres) 321
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
322
Mesh generation using blockMesh
blockMesh
• “blockMesh is a multi-block mesh generator.”
• For simple geometries, the mesh generation utility blockMesh can be used.
• The mesh is generated from a dictionary file named blockMeshDict
located in the system directory.
• The meshing tool generates high quality meshes, it is the tool to use for very
simple geometries. As the complexity of the geometry increases, the effort
and time required to setup the dictionary increases a lot.
• Usually the background mesh used with snappyHexMesh consist of a single
rectangular block, therefore blockMesh can be used with no problem.
• It is highly recommended to create a template of the dictionary
blockMeshDict that you can change according to the dimensions of your
domain.
• You can also use m4 or Python scripting to automate the whole process.
323
Mesh generation using blockMesh
blockMesh
324
Mesh generation using blockMesh
blockMesh workflow
• To generate a mesh with blockMesh, you will need to define the vertices, block
connectivity and number of cells in each direction.
• To assign boundary patches, you will need to define the faces connectivity
325
blockMesh guided tutorials
$PTOFC/101BLOCKMESH/C1
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
326
blockMesh guided tutorials
What are we going to do?
• We will use this simple case to take a close look at a blockMeshDict dictionary.
• We will study all sections in the blockMeshDict dictionary.
• We will introduce two features useful for parameterization, namely, macro syntax and
inline calculations.
• You can use this dictionary as a blockMeshDict template that you can change
automatically according to the dimensions of your domain and the desired cell
spacing.
327
blockMesh guided tutorials
The blockMeshDict dictionary.
• The keyword convertToMeters (line 17), is a scaling
17 convertToMeters 1; factor. In this case we do not scale the dimensions.
18
19 xmin 0;
20 xmax 1; • In lines 19-24 we declare some variables using macro
21 ymin 0; syntax notation. With macro syntax, we first declare the
22 ymax 1;
23 zmin 0; variables and their values (lines 19-24), and then we can
24 zmax 1;
25
use the variables by adding the symbol $ to the variable
30 deltax 0.05; name (lines 47-54).
31 deltay 0.05;
32 deltaz 0.05;
33 • In lines 30-32 we use macro syntax to declare another
34 lx #calc "$xmax - $xmin"; set of variables that will be used later.
35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin";
37 • Macro syntax is a very convenient way to parameterize
38 xcells #calc "round($lx/$deltax)"; dictionaries.
39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );
328
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 34-40 we are doing inline calculations using the
17 convertToMeters 1; directive #calc.
18
19 xmin 0;
20 xmax 1; • Basically we are programming directly in the dictionary.
21 ymin 0; OpenFOAM® will compile this function as it reads it.
22 ymax 1;
23 zmin 0;
24 zmax 1; • With inline calculations and codeStream you can access
25 many OpenFOAM® functions from the dictionaries.
30 deltax 0.05;
31 deltay 0.05;
32 deltaz 0.05; • Inline calculations and codeStream are very convenient
33
34 lx #calc "$xmax - $xmin";
ways to parameterize dictionaries and program directly
35 ly #calc "$ymax - $ymin"; on the dictionaries.
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round($lx/$deltax)";
39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );
329
blockMesh guided tutorials
The blockMeshDict dictionary.
• To do inline calculations using the directive #calc, we
17 convertToMeters 1; proceed as follows (we will use line 35 as example):
18
19 xmin 0;
20 xmax 1;
21 ymin 0;
22 ymax 1; ly #calc "$ymax - $ymin";
23 zmin 0;
24 zmax 1;
25
30 deltax 0.05;
31 deltay 0.05; • We first give a name to the new variable (ly), we then tell
32 deltaz 0.05;
33
OpenFOAM® that we want to do an inline calculation
34 lx #calc "$xmax - $xmin"; (#calc), and then we do the inline calculation ("$ymax-
35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin"; $ymin";). Notice that the operation must be between
37
38 xcells #calc "round($lx/$deltax)";
double quotation marks.
39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );
330
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines lines 34-36, we use inline calculations to
17 convertToMeters 1; compute the length in each direction.
18
19 xmin 0;
20 xmax 1; • Then we compute the number of cells to be used in each
21 ymin 0; direction (lines 38-40).
22 ymax 1;
23 zmin 0;
24 zmax 1; • To compute the number of cells we use as cell spacing
25 the values declared in lines 30-32.
30 deltax 0.05;
31 deltay 0.05;
32 deltaz 0.05; • By proceeding in this way, we can compute automatically
33
34 lx #calc "$xmax - $xmin";
the number of cells needed in each direction according to
35 ly #calc "$ymax - $ymin"; the desired cell spacing.
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round($lx/$deltax)";
39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );
331
blockMesh guided tutorials
The blockMeshDict dictionary.
• By the way, as this dictionary is designed for blocks with
17 convertToMeters 1; positive vertices coordinates, there is a small catch in the
18
19 xmin 0; way we compute the length (lines 34-36) and the number
20 xmax 1;
21 ymin 0;
of cells (lines 38-40).
22 ymax 1;
23 zmin 0; • What will happen if xmin is negative?
24 zmax 1;
25
30 deltax 0.05;
• What will happen if xcells is negative?
31 deltay 0.05;
32 deltaz 0.05; • What will happen if xcells is a float with decimals?
33
34 lx #calc "$xmax - $xmin"; • Can you find a solution to these small problems?
35 ly #calc "$ymax - $ymin";
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round($lx/$deltax)";
39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );
332
blockMesh guided tutorials
The blockMeshDict dictionary.
• In the vertices section (lines 44-66), we define the vertex
17 convertToMeters 1; coordinates of the geometry.
18
19 xmin 0;
20 xmax 1; • In this case, there are eight vertices defining a 3D block.
21 ymin 0;
22 ymax 1; • Remember, OpenFOAM® always uses 3D meshes, even
23 zmin 0;
24 zmax 1; if the simulation is 2D. For 2D meshes, you only add one
25 cell in the third dimension.
30 deltax 0.05;
31 deltay 0.05;
32 deltaz 0.05; • Notice that the vertex numbering starts from 0 (as the
33
34 lx #calc "$xmax - $xmin";
counters in c++). This numbering applies for blocks as
35 ly #calc "$ymax - $ymin"; well.
36 lz #calc "$zmax – $zmin";
37
38 xcells #calc "round($lx/$deltax)";
39 ycells #calc "round($ly/$deltay)";
40 zcells #calc "round($lz/$deltaz)";
41
44 vertices
45 (
46 //BLOCK 0
47 ($xmin $ymin $zmin) //0
48 ($xmax $ymin $zmin) //1
49 ($xmax $ymax $zmin) //2
50 ($xmin $ymax $zmin) //3
51 ($xmin $ymin $zmax) //4
52 ($xmax $ymin $zmax) //5
53 ($xmax $ymax $zmax) //6
54 ($xmin $ymax $zmax) //7
66 );
333
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 68-71, we define the block topology, hex means that it is a structured hexahedral block. In this case,
we are generating a rectangular mesh.
• In line 70, (0 1 2 3 4 5 6 7) are the vertices used to define the block (and yes, the order is important). Each
hex block is defined by eight vertices, in sequential order. Where the first vertex in the list represents the
origin of the coordinate system (vertex 0 in this case).
• ($xcells $ycells $zcells) is the number of mesh cells in each direction (X Y Z). Notice that we are using
macro syntax, and we compute the values using inline calculations.
• simpleGrading (1 1 1) is the grading or mesh stretching in each direction (X Y Z), in this case the mesh is
uniform. We will deal with mesh grading/stretching in the next case.
68 blocks
69 (
70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
71 );
72
73 edges
74 (
75
76 );
334
blockMesh guided tutorials
The blockMeshDict dictionary.
• Let us talk about the block ordering hex (0 1 2 3 4 5 6 7), which is extremely important.
• hex blocks are defined by eight vertices in sequential order. Where the first vertex in the list represents the
origin of the coordinate system (vertex 0 in this case).
• Starting from this vertex, we construct the block topology. So in this case, the first part of the block is made up
by vertices 0 1 2 3 and the second part of the block is made up by vertices 4 5 6 7 (notice that we start from
vertex 4 which is the projection in the Z-direction of vertex 0).
• In this case, the vertices are ordered in such a way that if we look at the screen/paper (-z direction), the
vertices rotate counter-clockwise.
• If you add a second block, you must identify the first vertex and starting from it, you should construct the block
topology. In this case, you might need to merges faces, we will address this later.
68 blocks
69 (
70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
71 );
72
73 edges
74 (
75
76 );
335
blockMesh guided tutorials
The blockMeshDict dictionary.
• Edges, are constructed from the vertices definition.
• Each edge joining two vertices is assumed to be straight by default.
• The user can specified any edge to be curved by entries in the section edges.
• Possible options are: arc, spline, polyline, BSpline, line.
• For example, to define an arc we first define the vertices to be connected to form an edge and then we give an
interpolation point.
• To define a polyline we first define the vertices to be connected to form an edge and then we give a list of the
coordinates of the interpolation points.
• In this case and as we do not specified anything, all edges are assumed to be straight lines.
68 blocks
69 (
70 hex (0 1 2 3 4 5 6 7) ($xcells $ycells $zcells) simpleGrading (1 1 1)
71 );
72
73 edges
74 (
75
76 );
336
blockMesh guided tutorials
The blockMeshDict dictionary.
• In the section boundary, we define all the patches where
78 boundary we want to apply boundary conditions.
79 (
80 top
81 { • This step is of paramount importance, because if we do
82
83
type wall;
faces
not define the surface patches we will not be able to
84 ( apply the boundary conditions to individual surface
85 (3 7 6 2)
86 );
patches.
87 }
88 left
89 {
90 type wall;
91 faces
92 (
93 (0 4 7 3)
94 );
95 }
96 right
97 {
98 type wall;
99 faces
100 (
101 (2 6 5 1)
102 );
103 }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }
337
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 80-87 we define a boundary patch.
78 boundary
79 ( • In line 80 we define the patch name top (the name is
80 top
81 { given by the user).
82 type wall;
83 faces • In line 82 we give a base type to the surface patch. In
84 (
85 (3 7 6 2) this case wall (do not worry we are going to talk about
86 ); this later).
87 }
88 left
89 { • In line 85 we give the connectivity list of the vertices that
90 type wall;
91 faces
made up the surface patch or face, that is, (3 7 6 2).
92 (
93 (0 4 7 3) • Have in mind that the vertices need to be neighbors and
94 );
95 }
it does not matter if the ordering is clockwise or counter
96 right clockwise.
97 {
98 type wall;
99 faces
100 (
101 (2 6 5 1)
102 );
103 }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }
338
blockMesh guided tutorials
The blockMeshDict dictionary.
• Have in mind that the vertices need to be neighbors and
78 boundary it does not matter if the ordering is clockwise or counter
79 (
80 top clockwise.
81 {
82
83
type wall;
faces
• Remember, faces are defined by a list of 4 vertex
84 ( numbers, e.g., (3 7 6 2).
85 (3 7 6 2)
86
87 }
); • In lines 88-95 we define the patch left.
88 left
89 { • In lines 96-103 we define the patch right.
90 type wall;
91 faces • In lines 104-11 we define the patch bottom.
92 (
93 (0 4 7 3)
94 );
95 }
96 right
97 {
98 type wall;
99 faces
100 (
101 (2 6 5 1)
102 );
103 }
104 bottom
105 {
106 type wall;
107 faces
108 (
109 (0 1 5 4)
110 );
111 }
339
blockMesh guided tutorials
The blockMeshDict dictionary.
• In lines 112-119 we define the patch front.
112 front
113 { • In lines 120-127 we define the patch back.
114 type wall;
115
116
faces
(
• You can also group many faces into one patch, for
117 (4 5 6 7) example, instead of creating the patches front and back,
118 );
119 } you can group them into a single patch named
120 back backAndFront, as follows,
121 {
122 type wall;
123 faces
124 (
125 (0 3 2 1) backAndFront
126 ); {
127 }
128 ); type wall;
129 faces
130 mergePatchPairs
131 ( (
132 (4 5 6 7)
133 );
(0 3 2 1)
);
}
340
blockMesh guided tutorials
The blockMeshDict dictionary.
• We can merge blocks in the section mergePatchPairs
112 front (lines 130-133).
113 {
114 type wall;
115 faces • The block patches to be merged must be first defined in
116 ( the boundary list, blockMesh then connect the two
117 (4 5 6 7)
118 ); blocks.
119 }
120
121
back
{
• In this case, as we have one single block there is no
122 type wall; need to merge patches.
123 faces
124 (
125 (0 3 2 1)
126 );
127 }
128 );
129
130 mergePatchPairs
131 (
132
133 );
341
blockMesh guided tutorials
The blockMeshDict dictionary.
342
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18
19
6
(
• First at all, this file is automatically generated after you
20 top create the mesh or you convert it from a third party format.
21 {
22 type wall;
23 inGroups 1(wall); • In this file, the geometrical information related to the base
24 nFaces 400;
25 startFace 22800; type patch of each boundary of the domain is specified.
26 }
27 left
28 { • The base type boundary condition is the actual surface
29 type wall;
30 inGroups 1(wall); patch where we are going to apply a primitive type
31 nFaces 400; boundary condition (or numerical boundary condition).
32 startFace 23200;
33 }
34
35
right
{
• The primitive type boundary condition assign a field value
36 type empty; to the surface patch.
37 inGroups 1(wall);
38 nFaces 400;
39 startFace 23600; • You define the numerical type patch (or the value of the
40 }
41 bottom boundary condition), in the directory 0 or time directories.
42 {
43 type wall;
44 inGroups 1(wall); • The name and base type of the patches was defined in the
45 nFaces 400;
46 startFace 24000;
dictionary blockMeshDict in the section boundary.
47 }
48 front
49 { • You can change the name if you do not like it. Do not use
50 type wall; strange symbols or white spaces.
51 inGroups 1(wall);
52 nFaces 400;
53
54 }
startFace 24400; • You can also change the base type. For instance, you can
55 back change the type of the patch top from wall to patch.
56 {
57 type empty;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 343
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18
19
6
(
• If you do not define the boundary patches in the dictionary
20 top blockMeshDict, they are grouped automatically in a default
21 {
22 type wall; group named defaultFaces of type empty.
23 inGroups 1(wall);
24
25
nFaces
startFace
400;
22800;
• For instance, if you do not assign a base type to the patch
26 } front, it will be grouped as follows:
27 left
28 {
29 type wall;
30 inGroups 1(wall);
31 nFaces 400;
defaultFaces
32 startFace 23200; {
33 } type empty;
34 right inGroups 1(empty);
35 {
36 type empty;
nFaces 400;
37 inGroups 1(wall); startFace 24800;
38 nFaces 400; }
39 startFace 23600;
40 }
41 bottom
42 {
43 type wall; • Remember, you can manually change the name and type.
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 24400;
54 }
55 back
56 {
57 type empty;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 344
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
Number of surface patches
20 top
21 {
22 type wall; In the list bellow there must be 6 patches
23 inGroups 1(wall);
24 nFaces 400; definition.
25 startFace 22800;
26 }
27 left
28 {
29 type wall;
30 inGroups 1(wall); top
31 nFaces 400;
32 startFace 23200;
33 }
34 right
35 {
36 type empty;
37 inGroups 1(wall); back
38 nFaces 400;
39 startFace 23600;
40 }
41 bottom
42 {
43 type wall;
44 inGroups 1(wall);
45 nFaces 400; left right
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400; front
53 startFace 24400;
54 }
55 back
56 {
57 type empty;
58 inGroups 1(wall);
59 nFaces 400; bottom
60 startFace 24800;
61 }
62 ) 345
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
20 top
21 {
22 type wall; Name and type of the surface patches
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 22800;
26 } • The name and base type of the patch is given
27 left
28 { by the user.
29 type wall;
30
31
inGroups
nFaces
1(wall);
400;
• In this case the name and base type was
32 startFace 23200; assigned in the dictionary blockMeshDict.
33 }
34 right
35 { • You can change the name if you do not like it.
36 type wall;
37 inGroups 1(wall);
Do not use strange symbols or white spaces.
38 nFaces 400;
39 startFace 23600; • You can also change the base type. For
40 }
41 bottom instance, you can change the type of the
42 {
43 type wall;
patch top from wall to patch.
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 24400;
54 }
55 back
56 {
57 type wall;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 346
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
20 top
21 {
22 type wall; inGroups keyword
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 22800;
26 } • This is optional.
27 left
28
29
{
type wall; • You can erase this information safely.
30 inGroups 1(wall);
31 nFaces 400; • It is used to group patches during visualization
32 startFace 23200;
33 } in ParaView/paraFoam. If you open this mesh
34 right
35 { in paraFoam you will see that there are two
36 type wall;
37 inGroups 1(wall);
groups, namely: wall and empty.
38 nFaces 400;
39 startFace 23600; • As usual, you can change the name.
40 }
41
42
bottom
{ • If you want to put a surface patch in two
43
44
type
inGroups
wall;
1(wall);
groups, you can proceed as follows:
45 nFaces 400;
46 startFace 24000; 2(wall wall1)
47 }
48 front
49 {
In this case the surface patch belongs to the
50
51
type
inGroups
wall;
1(wall);
group wall (which can have another patch)
52 nFaces 400; and the group wall1
53 startFace 24400;
54 }
55 back
56 {
57 type wall;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 347
blockMesh guided tutorials
The constant/polyMesh/boundary dictionary
18 6
19 (
20 top
21 {
22 type wall; nFaces and startFace keywords
23 inGroups 1(wall);
24 nFaces 400;
25 startFace 22800;
26 } • Unless you know what you are doing, you do
27 left
28 { not need to change this information.
29 type wall;
30
31
inGroups
nFaces
1(wall);
400;
• Basically, this is telling you the starting face
32 startFace 23200; and ending face of the patch.
33 }
34 right
35 { • This information is created automatically when
36 type wall;
37 inGroups 1(wall);
generating the mesh or converting the mesh.
38 nFaces 400;
39 startFace 23600;
40 }
41 bottom
42 {
43 type wall;
44 inGroups 1(wall);
45 nFaces 400;
46 startFace 24000;
47 }
48 front
49 {
50 type wall;
51 inGroups 1(wall);
52 nFaces 400;
53 startFace 24400;
54 }
55 back
56 {
57 type wall;
58 inGroups 1(wall);
59 nFaces 400;
60 startFace 24800;
61 }
62 ) 348
blockMesh guided tutorials
Running the case
1. $> foamCleanTutorials
2. $> blockMesh
3. $> checkMesh
4. $> paraFoam
• You can run the rest of the cases following the same steps.
349
blockMesh guided tutorials
Final remarks on blockMesh
• For the moment, we will limit the use of blockMesh to single-block mesh topologies, which are
used to run some simple cases and are the starting point for snappyHexMesh.
• But have in mind that you can do more elaborated meshes, however, it requires careful setup of
the input dictionary.
• Have in mind that it can be really tricky to generate multi-block meshes with curve edges.
• With the training material, you will find a set of supplement slides where we explain how to
create multi-block meshes, add stretching, and how to define curve edges.
Single-block mesh with multi-stretching Multi-block mesh with curved edges and Multi-block mesh with face merging
multi-stretching
350
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
351
Mesh generation using snappyHexMesh
snappyHexMesh
• “Automatic split hex mesher. Refines and snaps to surface.”
• For complex geometries, the mesh generation utility snappyHexMesh can be used.
• The snappyHexMesh utility generates 3D meshes containing hexahedra and split-
hexahedra from a triangulated surface geometry in Stereolithography (STL) format.
• The mesh is generated from a dictionary file named snappyHexMeshDict located in
the system directory and a triangulated surface geometry file located in the directory
constant/triSurface.
352
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• To generate a mesh with snappyHexMesh we proceed as follows:
• Generation of a background or base mesh.
• Geometry definition.
• Generation of a castellated mesh or cartesian mesh.
• Generation of a snapped mesh or body fitted mesh.
• Addition of layers close to the surfaces or boundary layer meshing.
• Check/enforce mesh quality.
snappyHexMesh
OpenFOAM mesh
353
Mesh generation using snappyHexMesh
snappyHexMesh workflow – Background mesh
• The background or base mesh can be generated using blockMesh or an
external mesher.
• The following criteria must be observed when creating the background
mesh:
• The mesh must consist purely of hexes.
• The cell aspect ratio should be approximately 1, at least near the
STL surface.
• There must be at least one intersection of a cell edge with the
STL surface.
blockMesh or external mesher
snappyHexMesh
OpenFOAM mesh
354
Mesh generation using snappyHexMesh
snappyHexMesh workflow – Geometry (STL file)
• The STL geometry can be obtained from any geometry modeling tool.
• The STL file can be made up of a single surface describing the geometry, or
multiple surfaces that describe the geometry.
• In the case of a STL file with multiple surfaces, we can use local refinement
in each individual surface. This gives us more control when generating the
mesh.
• The STL geometry is always located in the directory
constant/triSurface
snappyHexMesh
OpenFOAM mesh
355
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• The meshing utility snappyHexMesh reads the dictionary
snappyHexMeshDict located in the directory system.
• The castellation, snapping, and boundary layer meshing steps are controlled
by the dictionary snappyHexMeshDict.
• The final mesh is always located in the directory
constant/polyMesh
snappyHexMesh
OpenFOAM mesh
356
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• All the volume and surface refinement is done in reference to the
background or base mesh.
and so on …
Base cell – RL 0 RL 1 RL 2
* RL = refinement level
Note:
• In 2D each quad is subdivided in 4
quads.
• In 3D each hex is subdivided in 8
hexes.
357
Mesh generation using snappyHexMesh
snappyHexMesh workflow
• The process of generating a mesh using snappyHexMesh will be described using this figure.
• The objective is to mesh a rectangular shaped region (shaded grey in the figure) surrounding an object
described by a STL surface (shaded green in the figure).
• This is an external mesh (e.g. for external aerodynamics). You can also generate an internal mesh (e.g. flow in
a pipe).
358
Mesh generation using snappyHexMesh
snappyHexMesh workflow
360
Mesh generation using snappyHexMesh
snappyHexMesh workflow
361
Mesh generation using snappyHexMesh
snappyHexMesh workflow
362
Mesh generation using snappyHexMesh
snappyHexMesh workflow
363
Mesh generation using snappyHexMesh
snappyHexMesh workflow
366
Mesh generation using snappyHexMesh
$PTOFC/101SHM/M101_WD
367
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
castellatedMesh true; //or false • Have in mind that there are more than 70
snap true; //or false
addLayers true; //or false parameters to control in
snappyHexMeshDict dictionary.
geometry
{
... • Adding the fact that there is no native GUI, it
... can be quite tricky to control the mesh
}
generation process.
castellatedMeshControls
{
... • Nevertheless, snappyHexMesh generates
...
} really good hexa dominant meshes.
snapControls
{ • Hereafter, we will only comment on the most
...
...
important parameters.
}
regions Use this option if you have a STL with multiple patches defined
{
wolflocal This is the name of the region or surface patch in the STL
{
name wolf_wall; User-defined patch name. This is the final name of the patch
}
}
}
• In this section we read in the STL geometry. Remember, the input
box Name of geometrical entity
geometry is always located in the directory constant/triSurface
{
type searchableBox; • We can also define geometrical entities that can be used to refine the
min (-100.0 -120.0 -50.0 ); mesh, create regions, or generate baffles.
max (100.0 120.0 150.0 );
} • You can add multiple STL files.
sphere Name of geometrical entity • If you do not give a name to the surface, it will take the name of the
{ STL file.
type searchableSphere; Note 1
centre (120.0 -100.0 50.0 ); • The geometrical entities are created inside snappyHexMesh.
radius 40.0;
} Note 1:
If you want to know what geometrical entities are available, just
} misspelled something in the type keyword.
370
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{
//Refinement parameters
maxLocalCells 100000;
maxGlobalCells 2000000; Note 1
nCellsBetweenLevels 3;
...
...
// Refinement parameters
maxLocalCells 100000;
maxGlobalCells 2000000;
minRefinementCells 0;
maxLoadUnbalance 0.10;
nCellsBetweenLevels 3; Note 1
planarAngle 30;
allowFreeStandingZoneFaces true;
...
...
...
regions Note 2
{
wolflocal Note 3
Note 1:
{
The surface wolf was defined in the geometry section.
level (2 4); Local refinement
Note 2:
patchInfo
The region wolflocal was defined in the geometry section.
{
type wall; Note 4
Note 3:
}
Named region in the STL file. This refinement is local.
}
To use the surface refinement in the regions, the local
}
regions must exist in STL file. We created a pointer to this
}
region in the geometry section.
...
...
Note 4:
} 373
You can only define patches of type wall or patch.
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{
...
...
...
//This surface or geometrical entity
//was defined in geometry section
sphere Note 1
{
level (1 1);
Name of faceZone
faceZone face_inner;
cellZone cell_inner; Name of cellZone
...
...
...
//Region-wise refinement
refinementRegions Dictionary block
{
box Note 1
{
mode inside;
levels (( 1 1 ));
}
375
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Castellated mesh controls section
castellatedMeshControls
{
...
...
...
//Region-wise refinement
refinementRegions Dictionary block
{
box
{
mode inside;
levels (( 1 1 ));
}
}
This point defines where do you want the mesh.
Can be internal mesh or external mesh.
//Mesh selection
locationInMesh (-100.0 0.0 50.0 ); • If the point is inside the STL it is an internal mesh.
• If the point is inside the background mesh and outside the
} STL it is an external mesh.
tolerance 2.0;
// Feature snapping
layers Note 1
{
wolf_wall Note 2
{
nSurfaceLayers 3;
//Local parameters
//expansionRatio 1.3;
//finalLayerThickness 0.3;
//minThickness 0.1;
}
}
// Advanced settings
nGrow 0;
featureAngle 130; Note 3 Note 1:
maxFaceThicknessRatio 0.5; In this section we select the patches where we want to add the
nSmoothSurfaceNormals 1; layers. We can add multiple patches (if they exist).
nSmoothThickness 10;
minMedianAxisAngle 90; Note 2:
maxThicknessToMedialRatio 0.3; This patch was created in the geometry section.
nSmoothNormals 3;
slipFeatureAngle 30; Note 3:
nRelaxIter 5; Specification of feature angle above which layers are collapsed
nBufferCellsNoExtrude 0; automatically.
nLayerIter 50;
nRelaxedIter 20; • In this step, we are generating the boundary layer mesh.
} 378
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Mesh quality controls section
meshQualityControls
{
maxNonOrtho 75; Note 1
maxBoundarySkewness 20;
maxInternalSkewness 4; Note 2
maxConcave 80;
minVol 1E-13;
//minTetQuality 1e-15;
minTetQuality -1e+30;
minArea -1;
minTwist 0.02;
minDeterminant 0.001;
Note 1:
Maximum non-orthogonality angle.
minFaceWeight 0.05;
Note 2:
minVolRatio 0.01;
Maximum skewness angle.
minTriangleTwist -1;
• During the mesh generation process, the mesh quality is continuously
monitored.
minFlatness 0.5; • The mesher snappyHexMesh will try to generate a mesh using the
mesh quality parameters defined by the user.
nSmoothScale 4;
• If a mesh motion or topology change introduces a poor quality cell or
face the motion or topology change is undone to revert the mesh back
errorReduction 0.75;
to a previously valid error free state.
}
379
Mesh generation using snappyHexMesh
Let us explore the snappyHexMeshDict dictionary.
Mesh debug and write controls sections
debugFlags
(
// write intermediate meshes
mesh
writeFlags
(
// write volScalarField with cellLevel for • At the end of the dictionary you will find the sections: debugFlags
// postprocessing and writeFlags
scalarLevels
• By default they are commented. If you uncomment them you will
// write cellSets, faceSets of faces in layer enable debug information.
layerSets
• debugFlags and writeFlags will produce a lot of outputs that you
// write volScalarField for layer coverage can use to post process and troubleshoot the different steps of
layerFields the meshing process.
);
380
Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo.
• This tutorial is located in the directory:
• $PTOFC/101SHM/M101_WD
• In this case we are going to generate a body fitted mesh with boundary layer. This is an
external mesh.
• Before generating the mesh take a look at the dictionaries and files that will be used.
• These are the dictionaries and files that will be used.
• system/snappyHexMeshDict
• system/surfaceFeatureExtractDict
• system/meshQualityDict
• system/blockMeshDict
• constant/triSurface/wolfExtruded.stl
• constant/triSurface/wolfExtruded.eMesh
1. $> foamCleanTutorials
2. $> blockMesh
3. $> surfaceFeatureExtract
4. $> snappyHexMesh
5. $> checkMesh –latestTime
• In the case directory you will find the time folders 1, 2, and 3, which contain
the castellated mesh, snapped mesh and boundary layer mesh respectively.
In this case, snappyHexMesh automatically saved the intermediate steps.
• Before running the simulation, remember to transfer the solution from the
latest mesh to the directory constant/polyMesh, in the terminal type:
383
Mesh generation using snappyHexMesh
Let us generate the mesh of the wolf dynamics logo.
• If you want to avoid the additional steps of transferring the final mesh to the
directory constant/polyMesh by not saving the intermediate steps, you
can proceed as follows:
18 9 Name
19 ( Name and type of the surface patches
20 minX
21 { • The name and base type of the patch is given by the user.
22 type wall; Type
23 inGroups 1(wall);
24 nFaces 400; • In this case the name and base type was assigned in the
25
26 }
startFace 466399;
dictionaries blockMeshDict and snappyHexMeshDict.
27 maxX
28 {
nFaces • You can change the name if you do not like it. Do not use
29 type wall;
30 inGroups 1(wall); startFace strange symbols or white spaces.
31 nFaces 400;
32
33 }
startFace 466799;
• You can also change the base type. For instance, you can
34 minY change the type of the patch maxY from wall to patch.
35 {
36 type empty;
37 inGroups 1(wall);
38 nFaces 400;
39 startFace 467199; nFaces and startFace keywords
40 }
41 maxY • Unless you know what you are doing, you do not
42 {
43 type wall; need to change this information.
44 inGroups 1(wall);
45
46
nFaces
startFace
400;
467599;
• Basically, this is telling you the starting face and ending face
47 } of the patch.
48 minZ
49 {
50 type wall; • This information is created automatically when generating
51 inGroups 1(wall);
52 nFaces 400;
the mesh or converting the mesh.
53 startFace 467999;
54 }
387
Mesh generation using snappyHexMesh
The constant/polyMesh/boundary file
55 maxZ
56 { Name and type of the surface patches
57 type wall;
58 inGroups 1(wall); • The name and base type of the patch is given by the user.
59 nFaces 400;
60 startFace 466399;
61 } Name • In this case the name and base type was assigned in the
62
63
wolf_wall
{
dictionaries blockMeshDict and snappyHexMeshDict.
64 type wall; Type
65 inGroups 1(wall); • You can change the name if you do not like it. Do not use
66 nFaces 400;
67 startFace 466799; strange symbols or white spaces.
68 }
69
70
sphere
{ nFaces • You can also change the base type. For instance, you can
71 type empty; startFace change the type of the patch maxY from wall to patch.
72 inGroups 1(wall);
73 nFaces 400;
74 startFace 467199;
75 }
76 sphere_slave nFaces and startFace keywords
77 {
78 type wall; • Unless you know what you are doing, you do not
79 inGroups 1(wall);
80 nFaces 400; need to change this information.
81 startFace 467599;
82
83 )
}
• Basically, this is telling you the starting face and ending face
of the patch.
• This information is created automatically when generating
the mesh or converting the mesh.
388
Mesh generation using snappyHexMesh
• $> foamCleanTutorials
• $> foamCleanPolyMesh
• If you are planning to start the meshing from a previous saved state, you do
not need to clean the case directory.
389
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
390
snappyHexMesh guided tutorials
• Our first case will be a mesh around a cylinder.
• This is a simple geometry, but we will use it to study all the meshing steps
and introduce a few advanced features.
• This case is located in the directory $PTOFC/101SHM/M1cyl
391
snappyHexMesh guided tutorials
$PTOFC/101SHM/M1_cyl/C1
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
392
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
Sphere with no edge refinement Cylinder with edge refinement Cylinder with no edge refinement
• If the geometry has sharp angles and you want to resolve those edges, you should use edge
refinement.
• In the left figure there is no need to use edge refinement as there are no sharp angles.
• In the mid figure we used edge refinement to resolve the sharp angles.
• In the right figure we did not use edge refinement, therefore we did not resolve well the sharp
angles.
393
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we control curvature refinement and enable edge refinement?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
...
...
...
...
...
...
} 394
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
resolveFeatureAngle
STL
395
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
angle
resolveFeatureAngle
STL
396
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we control surface refinement?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
...
...
...
397
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we create refinement regions?
• In the file snappyHexMeshDict, look for the following entry:
geometry
{
...
...
...
...
Dimensions of geometrical entity
...
...
};
398
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• How do we create refinement regions?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
refinementRegions
{ Name of the region
refinementBox created in the geometry section
{
mode inside; Type of refinement (inside,
levels ((1e15 1)); outside, or distance mode)
}
}
Refinement level
...
... Distance from the surface
... A large value covers the whole region
}
399
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
Explicit feature edge refinement level 0 Explicit feature edge refinement level 0
resolveFeatureAngle 110 resolveFeatureAngle 60
Surface based refinement level (2 2) Surface based refinement level (2 2)
Explicit feature edge refinement level 0 Explicit feature edge refinement level 4
resolveFeatureAngle 60 resolveFeatureAngle 60
Surface based refinement level (2 2) Surface based refinement level (2 2)
• To control edges refinement level, you can change the value of the explicit feature
edge refinement level.
401
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
Explicit feature edge refinement level 6 Explicit feature edge refinement level 0
resolveFeatureAngle 5 resolveFeatureAngle 5
Surface based refinement level (2 4) Surface based refinement level (2 4)
• To control edges refinement level, you can change the value of the explicit feature
edge refinement level.
402
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
Explicit feature edge refinement level 0 Explicit feature edge refinement level 4
resolveFeatureAngle 60 resolveFeatureAngle 60
Surface based refinement level (2 4) Surface based refinement level (2 2)
• To control surface refinement level, you can change the value of the surface based
refinement level.
• The first digit controls the global surface refinement level and the second digit
controls the curvature refinement level. 403
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
Explicit feature edge refinement level 0 Explicit feature edge refinement level 0
resolveFeatureAngle 60 resolveFeatureAngle 5
Surface based refinement level (2 4) Surface based refinement level (2 4)
• To control surface refinement due to curvature together with control based surface
refinement level, you can change the value of resolveFeatureAngle, and surface
based refinement level
404
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• Let us explore the dictionary surfaceFeatureExtractDict used by the
utility surfaceFeatureExtract.
• This utility will extract surface features (sharp angles) according to an angle
criterion (includedAngle).
extractionMethod extractFromSurface;
extractFromSurfaceCoeffs
{
Angle criterion
includedAngle 150;
to extract features
}
subsetFeatures
{
nonManifoldEdges yes;
openEdges yes;
}
405
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• Let us explore the dictionary surfaceFeatureExtractDict used by the
utility surfaceFeatureExtract.
• This utility will extract surface features (sharp angles) according to an angle
criterion (includedAngle).
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
406
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• If you want to have a visual representation of the feature edges, you can use
paraview/paraFoam.
• Just look for the filter Feature Edges.
• Have in mind that the angle you need to define in paraview/paraFoam is the complement of the
angle you define in the dictionary surfaceFeatureExtractDict
407
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
• In this case we are going to generate a body fitted mesh with edge refinement. This is an
external mesh.
• These are the dictionaries and files that will be used.
• system/snappyHexMeshDict
• system/surfaceFeatureExtractDict
• system/meshQualityDict
• system/blockMeshDict
• constant/triSurface/surfacemesh.stl
• constant/triSurface/surfacemesh.eMesh
408
snappyHexMesh guided tutorials
3D Cylinder with edge refinement.
1. $> foamCleanTutorials
2. $> surfaceFeatureExtract
3. $> blockMesh
4. $> snappyHexMesh –overwrite
5. $> checkMesh –latestTime
6. $> paraFoam
$PTOFC/101SHM/M1_cyl/C2
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
410
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
411
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• How do we enable boundary layer?
• In the file snappyHexMeshDict, look for the following entry:
...
...
...
412
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• How do we enable boundary layer?
• In the file snappyHexMeshDict, look for the section addLayersControls:
addLayersControls
{
//Global parameters
relativeSizes true;
expansionRatio 1.2;
finalLayerThickness 0.5;
minThickness 0.1;
layers
{ Name of the surface or user-defined
banana_stlSurface patch where you want to add the
{ boundary layer mesh.
nSurfaceLayers 3;
}
}
// Advanced settings
...
...
...
413
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• How do we control boundary layer collapsing?
• In the file snappyHexMeshDict, look for the section addLayersControls:
addLayersControls
{
...
...
...
// Advanced settings
nGrow 0;
Increase this value to avoid BL
featureAngle 130; collapsing
...
...
...
414
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
415
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• When the option relativeSizes is true, the boundary layer meshing is done relative to the size
of the cells next to the surface.
• This option requires less user intervention but can not guarantee a uniform boundary layer.
• Also, it is quite difficult to set a desired thickness of the first layer.
416
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• When the option relativeSizes is false, we give the actual thickness of the layers.
• This option requires a lot user intervention but it guarantees a uniform boundary layer and the
desired layer thickness. 417
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• When the option relativeSizes is true and in order to have a uniform boundary layer, we need
to have a uniform surface refinement.
• Nevertheless, we still do not have control on the desired thickness of the first layer. 418
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• To avoid boundary layer collapsing close to the corners, we can increase the value of the
boundary layer parameter featureAngle. 419
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• 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.
420
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
1. $> foamCleanTutorials
2. $> surfaceFeatureExtract
3. $> blockMesh
4. $> snappyHexMesh -overwrite
5. $> checkMesh –latestTime
6. $> paraFoam
421
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• At the end of the meshing process you will get the following information
regarding the boundary layer meshing:
[m] [%]
• If you want to visualize the boundary layer thickness, you can enable
writeFlags in the snappyhexMeshDict dictionary,
...
...
...
writeFlags
(
scalarLevels; // write volScalarField with cellLevel for postprocessing
layerSets; // write cellSets, faceSets of faces in layer
layerFields; // write volScalarField for layer coverage
);
...
...
...
423
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• After creating the mesh and if you do not like the inflation layer or you want to
try different layer parameters, you do not need to start the meshing process
from scratch.
• To restart the meshing process from a saved state you need to save the
intermediate steps (castellation and snapping), and then create the inflation
layers starting from the snapped mesh.
• That is, do not use the option snappyHeshMesh -overwrite.
• Also, in the dictionary controlDict remember to set the entry startFrom
to latestTime or the time directory where the snapped mesh is saved (in
this case 2).
• Before restarting the meshing, you will need to turn off the castellation and
snapping options and turn on the boundary layer options in the
snappyHexMeshDict dictionary.
425
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer.
• Remember, before restarting the meshing you will need to modify the
snappyHexMeshDict dictionary as follows:
castellatedMesh false;
snap false;
addLayers true;
• At this point, you can restart the meshing process by typing in the terminal,
• $> snappyHexMesh
• By the way, you can restart the boundary layer mesh from a previous mesh
with a boundary layer.
• So in theory, you an add one layer at a time, this will give you more control
but it will require more manual work and some scripting.
426
snappyHexMesh guided tutorials
• Meshing with snappyHexMesh – Case 3.
• 3D cylinder with feature edge refinement and boundary layer using a STL
with multiple surfaces (external mesh).
• You will find this case in the directory:
$PTOFC/101SHM/M1_cyl/C3
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
427
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
STL visualization with a single surface using paraview (the STL visualization with multiple surfaces using paraview (each
single surface in represented with a single color) color corresponds to a different surface)
• When you use a STL with multiple surfaces, you have more control over the meshing process.
• By default, STL files are made up of one single surface.
• If you want to create the multiple surfaces you will need to do it in the solid modeler.
• Alternatively, you can split the STL manually or using the utility surfaceAutoPatch.
• Loading multiple STLs is equivalent to using a STL with multiple surfaces.
428
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• When you use a STL with multiple surfaces, you have more control over the meshing process.
• In this case, we were able to use different refinement parameters in the lateral and central
surface patches of the cylinder. 429
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we assign different names to different surface patches?
• In the file snappyHexMeshDict, look for the following entry:
geometry
{
surfacemesh.stl
{
type triSurfaceMesh;
name stlSurface;
regions
{
patch0 Named region in the STL file
{
name surface0; User-defined patch name
} This is the name you need to use when
setting the boundary layer meshing
patch1
{
name surface1;
}
patch2
{
name surface2;
}
}
}
...
...
...
} 430
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we refine user defined surface patches?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
refinementSurfaces
{
level (2 2); Global refinement level
regions
{
patch0 Local surface patch
{
level (2 2); Local refinement level
patchInfo
{
type wall; Type of the patch.
} This information is optional
}
...
...
...
}
}
...
...
...
}
431
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we control curvature refinement on surface patches?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
refinementSurfaces
{
level (2 2); Global refinement level
regions
{
patch0 Local surface patch
{
level (2 4); Local curvature refinement (in red)
patchInfo
{
type wall;
}
}
...
...
...
}
}
...
...
...
}
432
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we control curvature refinement on surface patches?
• In the file snappyHexMeshDict, look for the following entry:
castellatedMeshControls
{
...
...
...
...
...
...
433
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• How do we control boundary layer meshing on the surface patches?
• In the file snappyHexMeshDict, look for the following entry:
addLayersControls
{
//Global parameters
relativeSizes true;
expansionRatio 1.2;
Global BL parameters
finalLayerThickness 0.5;
minThickness 0.1;
layers
{
“surface.*” POSIX wildcards are permitted
{
nSurfaceLayers 5;
}
surface0 Local surface patch
{
nSurfaceLayers 3;
expansionRatio 1.0;
finalLayerThickness 0.25; Local BL parameters
minThickness 0.1;
}
}
//Advanced settings
...
...
...
} 434
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
1. $> cd geo
4. $> cd ..
5. $> paraview
• The utility surfaceAutoPatch will read the original STL file (geo.stl), and it will find the
patches using an angle criterion of 130 (similar to the angle criterion used with the utility
surfaceFeatureExtract). It writes the new STL geometry in the file output.stl.
• By the way, it is better to create the STL file with multiple surfaces directly in the solid modeler.
• FYI, there is an equivalent utility for meshes, autoPatch. So if you forgot to define the
patches, this utility will automatically find the patches according to an angle criterion. 435
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• If you open the file output.stl, you will notice that there are three
surfaces defined in the STL file. The different surfaces are defined in by the
following sections:
solid patch0
… Surface patch 1 • The name of the solid sections are
automatically given by the utility
endsolid patch0
surfaceAutoPatch.
solid patch1
• The convention is as follows: patch0,
… Surface patch 2
patch1, pathc2, … patchN.
endsolid patch1
endsolid patch2
436
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
1. $> foamCleanTutorials
2. $> surfaceFeatureExtract
3. $> blockMesh
4. $> snappyHexMesh -overwrite
5. $> checkMesh –latestTime
437
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
• This case is ready to run using the solver simpleFoam. But before running,
you will need to set the boundary and initial conditions.
• You will need to manually modify the file constant/polyMesh/boundary
• Remember:
• Base type boundary conditions are defined in the file boundary located
in the directory constant/polyMesh.
• Numerical type boundary conditions are defined in the field variables
files located in the directory 0 or the time directory from which you want
to start the simulation (e.g. U, p).
• The name of the base type boundary conditions and numerical type
boundary conditions needs to be the same.
• Also, the base type boundary condition needs to be compatible with the
numerical type boundary condition.
438
snappyHexMesh guided tutorials
3D Cylinder with edge refinement and boundary layer, using a STL file
with multiple surfaces.
1. $> cp 0_org/* 0
2. $> cp system/boundary_org constant/polyMesh/boundary
3. $> renumberMesh –overwrite
4. $> simpleFoam > log | tail –f log
439
snappyHexMesh guided tutorials
$PTOFC/101SHM/M1_cyl/C4
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
440
snappyHexMesh guided tutorials
2D Cylinder
From 3D To 2D
• To generate a 2D mesh using snappyHexMesh, we need to start from a 3D. After all,
snappyHexMesh is a 3D mesher.
• To generate a 2D mesh (and after generating the 3D mesh), we use the utility
extrudeMesh.
• The utility extrudeMesh works by projecting a face into a mirror face. Therefore,
the faces need to parallel. 441
snappyHexMesh guided tutorials
2D Cylinder
Geometry width
FACE 1
• At most, the input geometry and the background mesh need to have the same width.
• If the input geometry is larger than the background mesh, it will be automatically cut by the faces
of the background mesh.
• In this case, the input geometry will be cut by the two lateral patches of the background mesh.
• If you want to take advantage of symmetry in 3D, you can cut the geometry in half using one of
the faces of the background mesh.
• When dealing with 2D
• Extracting the features edges is optional for the 2D geometry extremes, but it is recommended if
there are internal edges that you want to resolve.
442
snappyHexMesh guided tutorials
2D Cylinder
• How do we create the 2D mesh?
• After generating the 3D mesh, we use the utility extrudeMesh.
• This utility reads the extrudeMeshDict,
constructFrom patch;
sourceCase “.”
sourcePatches (minZ); Name of source patch
extrudeModel linearNormal
Number of layers to use in the linear extrusion.
nLayers 1;
As this is a 2D case we must use 1 layer
linearNormalCoeffs
{
Thickness of the extrusion.
thickness 1;
It is highly recommended to use a value of 1
}
mergeFaces false;
443
snappyHexMesh guided tutorials
2D Cylinder
1. $> foamCleanTutorials
2. $> blockMesh
3. $> snappyHexMesh –overwrite
4. $> extrudeMesh
5. $> checkMesh –latestTime
6. $> paraFoam
445
snappyHexMesh guided tutorials
$PTOFC/101SHM/M2_mixing_elbow
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
446
snappyHexMesh guided tutorials
Mixing elbow.
castellatedMeshControls
{
...
...
...
refinementRegions
{
mixing_elbow Name of surface
{
mode distance; Refinement using distance mode
levels ((1e-4 1));
}
}
• At this point, we are going to work in parallel (but you can work in serial as
well).
• To generate the mesh, in the terminal window type:
1. $> foamCleanTutorials
2. $> surfaceFeatureExtract
3. $> blockMesh
4. $> decomposePar
5. $> mpirun -np 4 snappyHexMesh –parallel –overwrite
6. $> mpirun -np 4 checkMesh –parallel –latestTime
7. $> reconstructParMesh -constant
8. $> paraFoam
450
snappyHexMesh guided tutorials
Mixing elbow.
• So what did we do?
• Step 4: we distribute the mesh among the processors we want to use.
• Step 5 and 6: we run in parallel.
• Step 7: we put back together the decomposed mesh.
• Step 8: we visualize the reconstructed mesh.
452
snappyHexMesh guided tutorials
Mixing elbow.
• Empty patches are no problem, they remain from the background mesh.
• To erase the empty patches, you can do it manually (you will need to modify the file
boundary), or you can use the utility createPatch as follows (the utility runs in
parallel):
• $> createPatch -overwrite
• The surface patch pipe was created in the geometry section of the dictionary
snappyHexMeshDict.
• The patches mixing_elbow_outlet, mixing_elbow_inlet1 and
mixing_elbow_inlet2 were created automatically by snappyHexMesh.
• You have the choice of giving the names of the patches yourself or letting
snappyHexMesh assign the names automatically.
• Remember, when creating the boundary layer mesh, these are the names you need
to use to assign the layers.
453
snappyHexMesh guided tutorials
Mixing elbow.
• The mesh used in the previous case was a STL with multiple surfaces.
• In you do not create the regions in the geometry section of the dictionary
snappyHexMeshDict, snappyHexMesh will automatically assign the names of the
surface patches as follows:
system/surfaceFeatureExtractDict
…
• mixing_elbow_outlet …
• mixing_elbow_inlet1 geometry
{
surfacemesh.stl
• mixing_elbow_inlet2 {
type triSurfaceMesh;
name mixing_elbow;
regions
{
pipe NOTE 1
{
NOTE 2 name pipe;
}
}
}
NOTE 1:
};
This is the name of the region or surface patch in the STL file
…
NOTE 2:
…
User-defined patch name. This is the final name of the patch.
454
snappyHexMesh guided tutorials
Mixing elbow.
• The mesh used in the previous case was a STL with multiple surfaces.
• In you do not create the regions in the geometry section of the dictionary
snappyHexMeshDict, snappyHexMesh will automatically assign the names of the
surface patches as follows:
constant/triSurfaceSurfacemesh.stl
• mixing_elbow_outlet
solid outlet
• mixing_elbow_inlet1 …
…
…
• mixing_elbow_inlet2 solid outlet
solid inlet1
…
…
…
solid inlet1
solid inlet2
…
…
…
solid inlet2
455
snappyHexMesh guided tutorials
Mixing elbow.
• The mesh used in the previous case was a STL with multiple surfaces.
• In the directory geometry, you fill find the file
mixing_pipe_onesurface.stl, this STL has one single surface.
• Try to use this STL file to generate the mesh.
• You will notice that the final mesh has only one patch, namely
mixing_elbow (or whatever name you chose).
• Also, it is not possible to have local control on the mesh refinement and
boundary layer meshing.
• You will also face the conundrum that as there is only one surface patch, it is
not possible to assign boundary conditions.
456
snappyHexMesh guided tutorials
Mixing elbow.
• To solve the problem of the single surface patch, you can use the utility autoPatch.
To do so, you can proceed as follows:
• $> autoPatch 60 -overwrite
• The option -overwrite, will copy the new mesh in the directory
constant/polyMesh.
• The utility autoPatch will use an angle criterion to find the patches, and will assign
the name auto0, auto1, auto2 and auto3 to the new patches.
• The angle criterion is similar to that of the utility 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.
• Remember, autoPatch will manipulate the mesh located in the directory
constant/polyMesh.
• FYI, autoPatch does not un in parallel.
457
snappyHexMesh guided tutorials
Exercises
• To get a feeling of the includedAngle value, try to change the value in the dictionary
surfaceFeatureExtractDict.
• Remember the higher the includedAngle value, the more features you will capture.
• In the dictionary snappyHexMeshDict, change the value of resolveFeatureAngle
(try to use a lower value), and check the mesh quality in the intersection between
both pipes.
• In the castellatedMeshControls section, try to disable or modify the distance
refinement of the mixing_elbow region (refinementRegions).
• What difference do you see in the output?
458
snappyHexMesh guided tutorials
• Meshing with snappyHexMesh – Case 6.
• Parallel meshing of a continuous stirring tank reactor mesh with moving
regions (internal mesh)
• You will find this case in the directory:
$PTOFC/101SHM/M3_CSTR
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
459
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• In this case we are going to use multiple STL and eMesh files.
• Each color in the figure above represents a different STL.
• Working with multiple STL is no different from working with a single STL, we just need
to read all the STLs.
• When working with multiple STL we have more control on the local refinement.
460
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
Inner region (rotating mesh)
Impeller
http://www.wolfdynamics.com/training/meshing/image5.gif
• We are going to work with sliding grids (the impeller will be rotating), therefore we
need to divide the mesh in two regions, one fix region and one rotating region.
• To split the mesh in two regions we are going to use another STL file (the green
surface), plus a few utilities to manipulate the mesh.
• We will show how to setup conforming patches between regions.
461
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• In this case we are going to generate a body fitted mesh with two regions and using multiple
STL files.
• 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.
• system/snappyHexMeshDict
• system/meshQualityDict
• system/surfaceFeatureExtractDict
• system/decomposeParDict
• system/blockMeshDict
• constant/triSurface/impeller.stl
• constant/triSurface/impeller.eMesh
• constant/triSurface/inner_volume.stl
• constant/triSurface/inner_volume.eMesh
• constant/triSurface/shaft.stl
• constant/triSurface/shaft.eMesh
• constant/triSurface/sparger.stl
• constant/triSurface/sparger.eMesh
• constant/triSurface/vesel.stl
• constant/triSurface/vesel.eMesh
462
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
1. $> foamCleanTutorials
2. $> surfaceFeatureExtract
3. $> blockMesh
4. $> decomposePar
5. $> mpirun -np 4 snappyHexMesh –parallel –overwrite
6. $> mpirun -np 4 checkMesh –parallel –latestTime
7. $> reconstructParMesh -constant
8. $> paraFoam
463
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
464
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• Let us take a look at the geometry section of the dictionary snappyHexMeshDict.
• Notice that we are reading multiple STL files.
geometry
{
vessel.stl STL file to read.
{
type triSurfaceMesh;
name vessel; Name of the surface inside snappyHexMesh.
Use regions if you have a STL
regions
with multiple patches defined.
{
This is the name of the region or surface
inlet
patch in the STL file .
User-defined patch name. {
This is the final name of the name inlet;
patch. }
outlet
{
name outlet;
}
}
}
inner_volume.stl Define every single STL that
{ you want to use.
type triSurfaceMesh;
name inner_volume;
}
…
…
…
}
465
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• Let us take a look at the castellatedMeshControls section of the dictionary
snappyHexMeshDict.
• Notice that we are reading multiple eMesh files.
castellatedMeshControls
{
...
...
...
);
}
466
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• Let us take a look at the castellatedMeshControls section of the dictionary
snappyHexMeshDict.
• In this block we define the cellZone and faceZone, as follows,
castellatedMeshControls
{
...
...
...
467
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
face_inner_volume cell_inner_volume
468
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• 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.
1. 2.
469
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• At this point and if you run checkMesh, you will get the following
information:
• $> checkMesh
…
…
…
Checking topology…
Boundary definition OK.
Cell to face addressing OK.
Point usage OK.
UPPER triangular ordering OK.
Face vertices OK.
Number of regions: 1 (OK).
…
…
…
• As you can see we only have one region, but we are interested in having
two regions.
470
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• system/createBafflesDict
• system/createPatchDict
• system/topoSetDict
471
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
baffles
{
rotating Name of the baffle group
{
type faceZone; Use faceZone
zoneName face_inner_volume; Face to use to construct the AMI patches.
The nanme 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;
}
}
}
} The master and slave patches
share a common face 472
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• To create the two regions we proceed as follows (notice that we are going to
work in serial from now on)
473
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• So what did we do?
• Step 1:
• Splits the mesh in regions using the baffles (faceZone), created during the meshing
stage.
• We also create the cyclicAMI patches AMI1 and AMI2.
• At this point we have two regions and one zone. However, the two regions are stich
together via the patches AMI1 and AMI2.
• Step 2: topologically split the patches AMI1 and AMI2. As we removed the link between
AMI1 and AMI2, the regions are free to move.
• Step 3 (optional): gets rid of zero faced patches if hey exist. These are the patches
remaining from the base mesh, as they are empty, we do not need them.
• 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.
• Step 6 (optional): scales the mesh.
474
snappyHexMesh guided tutorials
CSTR – Continuous stirring tank reactor mesh
• At this point and if you run checkMesh, you will get the following information:
• $> checkMesh
…
…
…
Checking topology…
Boundary definition OK.
Cell to face addressing OK.
Point usage OK.
UPPER triangular ordering OK.
Face vertices OK.
*Number of regions: 2
The mesh has multiple regions which are not connected by any face.
<<Writing region information to ”0/cellToRegion”
<<Writing region 0 with 136187 cells to cellSet region0
<<Writing region 1 with 67682 cells to cellSet region1
…
…
…
Calculating AMI weights between owner patch: AMI1 and neighbour patch: AMI2
Number of faces in
AMI: Creating addressing and weights between 2476 source faces and 2476 target faces the AMI patches
AMI: Patch source sum(weights) min/max/average = 0.94746705, 1.0067199, 0.99994232 AMI1 patch weights
AMI: Patch target sum(weights) min/max/average = 0.94746692, 1.0004497, 0.99980782 AMI2 patch weights
…
476
snappyHexMesh guided tutorials
$PTOFC/101SHM/M4_ahmed
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
477
snappyHexMesh guided tutorials
Ahmed body
479
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
480
Mesh conversion
• OpenFOAM® gives users a lot of flexibility when it comes to meshing.
• You are not constrained to use OpenFOAM® meshing tools.
• To convert a mesh generated with a third-party software to OpenFOAM® polyMesh format, you
can use the OpenFOAM® mesh conversion utilities.
• If your format is not supported, you can write your own conversion tool.
• By the way, many of the commercially available meshers can save the mesh in OpenFOAM®
polyMesh format or in a compatible format.
• In the directory $PTOFC/mesh_conversion_sandbox you will find a few meshes generated
using the most popular third-party mesh generation applications.
• Feel free to play with these meshes.
• In the README.FIRST file of each case, you will find the instructions of how to convert the
mesh.
• Remember to always check the file boundary after converting the mesh. You
will need to change the name and type of the surface patches according to what
you would intent to do.
• Also, to convert the mesh you need to be in the top level of the case directory,
and you need to give to the conversion utility the path (absolute or relative) of
the mesh to be converted.
481
Mesh conversion
• In the directory $FOAM_UTILITIES/mesh/conversion you will find the source
code for the mesh conversion utilities:
• ansysToFoam • kivaToFoam
• cfx4ToFoam • mshToFoam
• datToFoam • netgenNeutralToFoam
• fluent3DMeshToFoam • Optional/ccm26ToFoam
• fluentMeshToFoam • plot3dToFoam
• foamMeshToFluent • sammToFoam
• foamToStarMesh • star3ToFoam
• foamToSurface • star4ToFoam
• gambitToFoam • tetgenToFoam
• gmshToFoam • vtkUnstructuredToFoam
• ideasUnvToFoam • writeMeshObj
• Take your time and read the instructions/comments contained in the source code of
the mesh conversion utilities so you can understand how to use these powerful tools.
482
Mesh conversion
$PTOFC/mesh_conversion_sandbox/M1_mixing_elbow_salome
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
483
Mesh conversion
Case 1. Mixing elbow (internal mesh).
1. $> foamCleanTutorials
2. $> foamCleanPolyMesh
3. $> ideasUnvToFoam ../../meshes_and_geometries/salome_elbow3d/Mesh_1.unv
4. $> checkMesh
5. $> paraFoam
• Remember to always check the file boundary after converting the mesh.
• To convert the mesh, you need to be in the top level of the case directory and you
need to give the path (absolute or relative) of the mesh to be converted.
484
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• ideasUnvToFoam output.
Create time
Processing tag:2411
Starting reading points at line 3.
Read 31136 points.
Processing tag:2412
Starting reading cells at line 62278.
First occurrence of element type 11 for cell 1 at line 62279
First occurrence of element type 41 for cell 361 at line 63359
First occurrence of element type 111 for cell 20933 at line 104503
Read 151064 cells and 20572 boundary faces. Internal cells and boundary faces read
Processing tag:2467
Starting reading patches at line 406633.
For group 1 named pipe trying to read 19778 patch face indices.
For group 2 named inlet1 trying to read 358 patch face indices.
For group 3 named inlet2 trying to read 78 patch face indices.
For group 4 named outlet trying to read 358 patch face indices.
End
485
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• checkMesh output.
Mesh stats
points: 31136
faces: 312414
internal faces: 291842
cells: 151064
faces per cell: 4
boundary patches: 4
point zones: 0
face zones: 0
cell zones: 0
Checking topology...
Boundary definition OK.
Cell to face addressing OK.
Point usage OK.
Upper triangular ordering OK.
Face vertices OK.
Number of regions: 1 (OK).
486
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• checkMesh output.
Checking geometry...
Overall domain bounding box (0 -0.414214 -0.5) (5 5 0.5)
Mesh has 3 geometric (non-empty/wedge) directions (1 1 1)
Mesh has 3 solution (non-empty) directions (1 1 1)
Boundary openness (-1.0302e-17 -6.17232e-17 -1.77089e-16) OK.
Max cell openness = 2.32045e-16 OK.
Max aspect ratio = 4.67245 OK.
Minimum face area = 0.000286852. Maximum face area = 0.010949. Face area magnitudes OK.
Min volume = 2.74496e-06. Max volume = 0.00035228. Total volume = 6.75221. Cell volumes OK.
Mesh non-orthogonality Max: 54.2178 average: 15.1295
Non-orthogonality check OK.
Face pyramids OK.
Max skewness = 0.649359 OK.
Coupled point location match (average 0) OK.
End
487
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• The boundary file.
488
Mesh conversion
Case 1. Mixing elbow (internal mesh).
• The boundary file.
4
(
pipe
{
type patch;
nFaces 19778;
Base type of the boundary patches
startFace 291842;
}
inlet1
{
• In this case, the utility automatically
type patch; assigned the base type patch to all
nFaces 358;
startFace 311620; boundary patches.
}
inlet2
{
• Feel free to change the base type
type
nFaces
patch;
78;
according to your needs.
startFace 311978;
} • In this case, it will be wise to change
outlet
{
the base type of patch pipe to wall.
type patch;
nFaces 358;
startFace 312056;
}
)
489
Roadmap
1. Meshing preliminaries
2. What is a good mesh?
3. Mesh quality assessment in OpenFOAM®
4. Mesh generation using blockMesh.
5. Mesh generation using snappyHexMesh.
6. snappyHexMesh guided tutorials.
7. Mesh conversion
8. Geometry and mesh manipulation utilities
490
Geometry and mesh manipulation utilities
• First of all, by mesh manipulation we mean modifying a valid OpenFOAM®
mesh.
• These modifications can be scaling, rotation, translation, mirroring,
topological changes, mesh refinement and so on.
• In the directory $FOAM_UTILITIES/mesh/manipulation you will find the
mesh manipulation utilities. Just to name a few:
• autoPatch • rotateMesh
• checkMesh • setSet
• createBaffles • splitMesh
• mergeMeshes • splitMeshRegions
• mergerOrSplitBaffles • stitchMesh
• mirrorMesh • subsetMesh
• polyDualMesh • topoSet
• refineMesh • transformPoints
• renumberMesh
491
Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES/mesh/manipulation you will find the
following mesh manipulation utilities.
• Inside each utility directory you will find a *.C file with the same name as the
directory. This is the main file, where you will find the top-level source code and a
short description of the utility.
• For instance, in the directory checkMesh, you will find the file checkMesh.C, which
is the source code of the utility checkMesh. In the source code you will find the
following description:
Usage
- checkMesh [OPTION]
\param -allGeometry \n
Checks all (including non finite-volume specific) geometry
\param -allTopology \n
Checks all (including non finite-volume specific) addressing
\param -meshQuality \n
Checks against user defined (in \a system/meshQualityDict) quality settings
• surfaceAdd • surfaceMeshConvert
• surfaceAutoPatch • surfaceMeshExport
• surfaceBooleanFeatures • surfaceMeshTriangulate
• surfaceCheck • surfaceOrient
• surfaceConvert • surfaceSplitByPatch
• surfaceFeatureConvert • surfaceSubset
• surfaceFeatureExtract • surfaceToPatch
• surfaceInertia • surfaceTransformPoints
493
Geometry and mesh manipulation utilities
• In the directory $FOAM_UTILITIES/surface you will find the following surface
manipulation utilities.
• Inside each utility directory you will find a *.C file with the same name as the
directory. This is the main file, where you will find the top-level source code and a
short description of the utility.
• For instance, in the directory surfaceTransformPoints, you will find the file
surfaceTransformPoints.C, which is the source code of the utility
surfaceTransformPoints. In the source code you will find the following
description:
494
Geometry and mesh manipulation utilities
$PTOFC/mesh_quality_manipulation/M5_ahmed_body_transform
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
495
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• We will now manipulate a STL geometry. In the terminal type:
1. $> foamCleanTutorials
2. $> surfaceMeshInfo ./constant/triSurface/ahmed_body.stl
3. $> surfaceCheck ./constant/triSurface/ahmed_body.stl
$> surfaceTransformPoints -rollPitchYaw '(0 0 15)’
4. ./constant/triSurface/ahmed_body.stl rotated.stl
$> surfaceTransformPoints -translate '(0 0.12 0)'
5. ./constant/triSurface/ahmed_body.stl translated.stl
$> surfaceTransformPoints -scale '(0.9 1.1 1.3)'
6. ./constant/triSurface/ahmed_body.stl scaled.stl
$> surfaceInertia -density 2700 –noFunctionObjects
7. ./constant/triSurface/ahmed_body.stl
$> surfaceOrient ./constant/triSurface/ahmed_body_wrong_normals.stl
8. out.stl ‘(1e10 1e10)’
496
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• In step 2 we use the utility surfaceMeshInfo to get general information about the STL (such
as number of faces and so on).
• In step 3 we use the utility surfaceCheck to check the STL file.
• In step 4 we use the utility surfaceTransformPoints to rotate the STL. We read in the STL
./constant/triSurface/ahmed_body.stl and we write out the STL rotated.stl
• In step 5 we use the utility surfaceTransformPoints to translate the STL. We read in the
STL ./constant/triSurface/ahmed_body.stl and we write out the STL
translated.stl
• In step 6 we use the utility surfaceTransformPoints to scale the STL. We read in the STL
./constant/triSurface/ahmed_body.stl and we write out the STL scaled.stl
• In step 7 we use the utility surfaceInertia to compute the inertia of the STL. We read in the
STL ./constant/triSurface/ahmed_body.stl. Notice that we need to give a reference
density value.
• In step 8 we use the utility surfaceOrient to orient the normals of the STL in the same way.
We read in the STL ./constant/triSurface/ahmed_body_wrong_normals.stl and we
write out the STL out.stl. Notice that we give an outside point or ‘(1e10 1e10 1e10)’, if
this point is outside the STL all normals will be oriented outwards, if the point is inside the STL
all normals will be oriented inwards.
497
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• Pay particular attention to step 8.
• We already have seen that snappyHexMesh computes surface angles using the surface
normals as a reference, so it is extremely important to have the normals oriented in the same
way and preferably outwards.
498
Geometry and mesh manipulation utilities
Geometry manipulation in OpenFOAM®
• To plot the normals in paraview/paraFoam you can use the filter Normal Glyphs
Select the Normal Glyphs from the filter menu
499
Geometry and mesh manipulation utilities
$PTOFC/mesh_quality_manipulation/M7_cylinder_transform
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
500
Geometry and mesh manipulation utilities
Mesh manipulation in OpenFOAM®
• We will now manipulate a mesh. In the terminal type:
1. $> foamCleanTutorials
2. $> blockMesh
3. $> transformPoints -rollPitchYaw '(0 0 90)'
4. $> transformPoints -scale '(0.01 0.01 0.01)'
5. $> transformPoints -translate '(0 0 1)'
6. $> createPatch -noFunctionObjects –overwrite
7. $> checkMesh
8. $> paraFoam
• In step 3 we use the utility transformPoints to rotate the mesh. We rotate the mesh by 90° about the Z
axis.
• In step 4 we use the utility transformPoints to scale the mesh. We scale the mesh by a factor of '(0.01
0.01 0.01)'.
• In step 5 we use the utility transformPoints to translate the mesh. We translate the mesh by the vector
'(0 0 1)'.
• In step 6 we use the utility createPatch to rename the patches of the mesh. This utility reads the dictionary
system/createPatchDict. Instead of using the utility createPatch we could have modified the
boundary file directly.
• This case is ready to run using the solver buoyantBoussinesqPimpleFoam. 501
Geometry and mesh manipulation utilities
Mesh manipulation in OpenFOAM®
Original mesh
503
Roadmap
1. Running in parallel
504
Running in parallel
• First of all, to know how many processors/cores you have available in your computer,
type in the terminal:
• $> lscpu
• The output for this particular workstation is the following:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Total number of cores available after
CPU(s): 24
hyper threading (virtual cores)
On-line CPU(s) list: 0-23
Thread(s) per core: 2
Core(s) per socket: 6 Number of threads per core (hyper threading)
Socket(s): 2
NUMA node(s): 2
Vendor ID: GenuineIntel Number of cores per socket or physical
CPU family: 6 processor
Model: 44
Model name: Intel(R) Xeon(R) CPU X5670 @ 2.93GHz
Stepping: 2 Number of sockets (physical processors)
CPU MHz: 1600.000
CPU max MHz: 2934.0000
CPU min MHz: 1600.0000
BogoMIPS: 5851.91
Total number of physical cores
Virtualization: VT-x
=
L1d cache: 32K
Number of cores per socket X Number of sockets
L1i cache: 32K
L2 cache: 256K
L3 cache: 12288K Total number of physical cores = 6 X 2 = 12 cores
NUMA node0 CPU(s): 0-5,12-17
NUMA node1 CPU(s): 6-11,18-23
• To take full advantage of the hardware, we use the maximum number of physical
cores (12 physical cores in this case) when running in parallel.
• If you use the maximum number of virtual cores, OpenFOAM® will run but it will be
slower in comparison to running with the maximum number of physical cores (or even
less cores).
• Same rule applies when running in clusters/super computers, so always read the
hardware specifications to know the limitations.
506
Running in parallel
Why use parallel computing?
• Solve larger and more complex problems (scale-up):
Thanks to parallel computing we can solve bigger problems (scalability). A single computer has limited
physical memory, many computers interconnected have access to more memory (distributed memory).
• Save money:
In theory, throwing more resources at a task will shorten its time to completion, with potential cost
savings. Parallel computers can be built from cheap, commodity components.
507
Running in parallel
Speed-up and scalability example
• In the context of high performance computing (HPC), there are two common metrics that measure the scalability
of the application:
• Strong scaling (Amdahl’s law): which is defined as how the solution time varies with the number of
processors for a fixed problem size (number of cells in CFD)
• Weak scaling (Gustafson’s law): which is defined as how the solution time varies with the number of
processors for a fixed problem size per processor (or increasing the problem size with a fix number of
processors).
• In this example, when we reach 12 cores inter-processor communication slow-downs the computation. But if we
increase the problem size for a fix number of processors, we will increase the speed-up.
• The parallel case with 1 processor runs slower than the serial case due to the extra overhead when calling the
MPI library. 508
Running in parallel
• The method of parallel computing used by OpenFOAM® is known as domain
decomposition, in which the geometry and associated fields are broken into pieces
and distributed among different processors.
• structured
• If you want more information about each decomposition method, just read
the source code:
• $WM_PROJECT_DIR/src/parallel/decompose/
513
Running in parallel
Running in parallel – Gathering all together
decomposePar
• Inside each processorN directory you will have the mesh information, boundary conditions,
initial conditions, and the solution for that processor.
514
Running in parallel
Running in parallel – Gathering all together
• After decomposing the mesh, we can run in parallel using MPI.
reconstructPar
1. $> decomposePar
2. $> mpirun –np <NPROCS> <application/utility> –parallel
3. $> reconstructPar
• If you are doing remeshing or using AMR you will need to use
reconstructParMesh before reconstrucPar.
517
Running in parallel
Kelvin Helmholtz instability in a coarse mesh
Mesh size
Processors Clock time (seconds)
in x, y, and z directions
Volume fraction
www.wolfdynamics.com/wiki/kelvin_helmholtz/ani1.gif
• The traditional way is to first reconstruct the case and then do the post-
processing and visualization on the reconstructed case.
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.
519
Running in parallel
Visualization of a parallel case
520
Running in parallel
Visualization of a parallel case
521
Running in parallel
Decomposing big meshes
• One final word, the utility decomposePar does not run in parallel. So, it is
not possible to distribute the mesh among different computing nodes to do
the partitioning in parallel.
• If you need to partition big meshes, you will need a computing node with
enough memory to handle the mesh. We have been able to decompose
meshes with up to 500.000.000 elements, but we used a computing node
with 512 gigs of memory.
522
Running in parallel
Do all utilities run in parallel?
• At this point, you might be wondering if all solvers/utilities run in parallel.
• To know what solvers/utilities do not run in parallel, in the terminal type:
• $> find $WM_PROJECT_DIR -type f | xargs grep –sl ‘noParallel’
• Paradoxically, the utilities used to decompose the domain and reconstruct the
domain do not run in parallel.
• Another important utility that does not run in parallel is blockMesh. So to generate
big meshes with blockMesh you need to use a big fat computing node.
• Another important utility that does not run in parallel by default is paraFoam.
• To compile paraFoam with MPI support, in the file makeParaView4 (located in the
directory $WM_THIRD_PARTY_DIR), set the option withMPI to true,
• withMPI = true
• While you are working with the file makeParaView4, you might consider enabling
Python support,
• withPYTHON = true
523
Running in parallel
Exercises
• Choose any tutorial or design your own case and do an scalability test. Scale your case with two different
meshes (a coarse and a fine mesh).
• Run the same case using different partitioning methods. Which method scales better? Do you get the same
results?
• Do you think that the best partitioning method is problem dependent?
• Compare the wall time of a test case using the maximum number of cores and the maximum number of virtual
cores. Which scenario is faster and why?
• Run a parallel case without using the –parallel option. Does it run? Is it faster of slower? How many
outputs do you see on the screen?
• Do you get any speed-up by using renumberMesh?
• What applications do not run in parallel?
524
Module 5
The postprocess utility – Sampling – Probing
– On-the-fly postprocessing – Field
manipulation – Data conversion
525
Roadmap
526
On-the-fly postprocessing – functionObjects
527
On-the-fly postprocessing – functionObjects
• In the directory $FOAM_SRC/functionObjects you will find the source code for the
functionObjects.
• There are many functionObjects, and according to what they do, they are located in different
sub-directories, namely, field, forces, lagrangian, solvers, and utilities. Just to
name a few functionObjects:
• corantNo • forceCoeffs
• div • forces
• fieldAverage • icoUncoupledKinematicCloud
• fieldMinMax • scalarTransport
• grad • codedFunctionObject
• MachNo • residuals
• Q • systemCall
• vorticity • timeActivatedFileUpdate
• yPlus • writeObjects
// ...
// functionObject Keywords and sub-dictionaries
// keywords and sub-dictionaries specific to the functionObject
// ...
529
On-the-fly postprocessing – functionObjects
• There are many functionObjects implemented in OpenFOAM®, and sometimes is
not very straightforward how to use a specific functionObject.
• Also, functionObjects can have many options and some limitations.
• Our best advice is to read the doxygen documentation or the source code to learn
how to use functionObjects.
• Remember, the source code of the functionObjects is located in the directory:
$WM_PROJECT_DIR/src/postProcessing/functionObjects
• The source code of the sampling and co-processing utilities is located in the directory:
$WM_PROJECT_DIR/src /sampling
• The source code of the database entries required for the functionObjects is located
in the directory:
$FOAM_SRC/OpenFOAM/db/functionObjects
$PTOFC/postprocessing/MDA_30P30N
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
531
On-the-fly postprocessing – functionObjects
At the end of the day, you should get something like this
cd cl
• Let us run this case using the automatic scripts distributed with the tutorial. In the
terminal type:
1. $> sh run_all.sh
• After the simulation is finish, you will find the decomposed directories (processor0,
processor1, processor2 and processor3), the postProcessing directory,
and the 2000 directory. The solution, and output of the functionObjects, is saved in
these directories.
• Remember, to visualize the decomposed solution you will need to launch paraFoam
as follows,
• Do not erase the solution as we are going to use it in the next section.
535
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us take a look at the bottom of the controlDict
51 functions dictionary file. In this dictionary is where we define all
52 {
functionObjects.
name_of_the_functionObject_dictionary
{ • Within this dictionary, functionObjects are defined in
Sub-dictionary with functionObject entries
}
the sub-dictionary functions, i.e.,
200 }
• $WM_PROJECT_DIR/src/postProcessing/f
unctionObjects
537
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us study all entries of the forces functionObject
51 functions
74 //only for incompressible flows Reference density value. It only needs to be defined for
75 rho rhoInf;
76 rhoInf 1.0; incompressible flows. For compressible flows, the
computed density is used instead (you will need to define
a dummy value, though)
78 //// Centre of rotation
79 CofR (0 0 0);
80 } Reference center of rotation to compute moments
200 } Note:
• The source code of this functionObject is located in the directory
$FOAM_SRC/functionObjects/forces/forces
• Use the banana method to know all the options available for each entry. 538
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us study now the functionObject used to
51 functions functionObject
compute the force coefficients.
86 forceCoeffs_object
identifier (user given)
87 {
88 type forceCoeffs;
89 functionObjectLibs ("libforces.so");
90
91 enabled true;
92 • This functionObject computes the force coefficients.
93 patches ("wall_slat" "wall_airfoil" "wall_flap");
94
• These entries are similar to those of the force
95 pName p; functionObject
96 Uname U;
97
99 rho rhoInf;
100 rhoInf 1.0;
101
This option will output the values to a text file located in the
103 log true; directory postProcessing/forceCoeffs_object
104
105 CofR (0.0 0 0);
106 Reference center of rotation to compute moments
107 pitchAxis (0 0 1);
108 magUInf 1.0;
109 lRef 1; Reference values used to compute coefficients
110 Aref 1;
111
115 writeControl timeStep;
116 writeInterval 1;
Controls for saving frequency
117
119 liftDir (0 1 0);
120 dragDir (1 0 0); Reference axes to compute the lift and drag coefficients.
121
125 }
196 }
539
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• Let us study now the functionObject used to
51 functions functionObject
compute the force coefficients.
86 forceCoeffs_object
identifier (user given)
87 {
88 type forceCoeffs;
89 functionObjectLibs ("libforces.so");
90
91 enabled true;
92
93 patches ("wall_slat" "wall_airfoil" "wall_flap");
94
95 pName p;
96 Uname U;
97
99 rho rhoInf;
100 rhoInf 1.0;
101
103 log true;
104
105 CofR (0.0 0 0);
106
107 pitchAxis (0 0 1);
108 magUInf 1.0;
109 lRef 1;
110 Aref 1;
111
115 writeControl timeStep;
116 writeInterval 1;
117
119 liftDir (0 1 0); • Reference axes to compute the lift and drag coefficients.
120 dragDir (1 0 0);
121 • Remember, lift and drag are perpendicular and parallel
125 }
to the incoming flow, respectively.
196 }
• So if the inlet velocity is entering at a given angle, you
should adjust the vectors liftDir and dragDir so they are
aligned with the incoming flow (rotation matrix).
540
On-the-fly postprocessing – functionObjects
The controlDict dictionary
• fieldMinMax functionObject
51 functions
• This functionObject is used to compute the minimum
131 minmaxdomain
132 {
and maximum values of the field variables.
133 type fieldMinMax;
134
• The output of this functionObject is saved in ascii format
135 functionObjectLibs ("libfieldFunctionObjects.so"); in the file fieldMinMax.dat located in the directory
136
137 enabled true; postProcessing/minmaxdomain/0
138
139 mode component; • Remember, the name of the directory where the output
140
141 writeControl timeStep; data is saved is the same as the name of the
142 writeInterval 1; functionObject (line 131).
143
144 log true;
145
146 fields (p U nuTilda nut k omega);
147 }
• yPlus functionObject
148
149 • This functionObject is used to compute the yPlus field.
150
151 • This functionObject has two outputs, one output saved
152 in the solution directories (1, 2, 3, and so on). You can
153 yplus
154 { visualize this output using paraview/paraFoam.
155 type yPlus;
156 functionObjectLibs ("libfieldFunctionObjects.so"); • The second output is located in the directory
157 enabled true;
158 log true; postProcessing/yplus/0.
159 writeControl outputTime;
160 } • In this file you will find the minimum, maximum and
196 } average values of yPlus in all patches defined as walls.
• Remember, the name of the directory where the output
data is saved is the same as the name of the
functionObject (line 153).
541
On-the-fly postprocessing – functionObjects
The controlDict dictionary
196 }
542
On-the-fly postprocessing – functionObjects
The externalFunctionObject dictionary
19 probes_online
• probes functionObject
20 {
21 type probes; • This functionObject is used to probe field data at the
22 functionObjectLibs ("libfieldFunctionObjects.so"); given locations.
23 enabled true;
24 writeControl timeStep; • In this case, we are sampling the fields U and p (lines 35-
25 writeInterval 1;
26 39)
27 probeLocations
28 ( • The output of this functionObject is saved in ascii format
29 (1 0 0) in the files p and U located in the directory
30 (2 0 0)
31 (2 0.25 0)
postProcessing/probes_online/0
32 (2 -0.25 0)
33 );
34 • Remember, the name of the directory where the output
35 fields data is saved is the same as the name of the
36 (
37 U
functionObject (line 19).
38 p
39 );
40
41 } • vorticity functionObject
47 vorticity • This functionObject is used to compute the vorticity field.
48 {
49 type vorticity; • The output of this functionObject is saved in the solution
50 functionObjectLibs ("libfieldFunctionObjects.so");
51 enabled true;
directories (1, 2, 3, and so on). You can visualize this
52 log true; output using paraview/paraFoam.
53 writeControl outputTime;
54 }
543
On-the-fly postprocessing – functionObjects
Final remarks on functionObjects
• A functionObject that is very useful, but we did not use in this case:
inlet_massflow
{
type surfaceRegion;
functionObjectLibs ("libfieldFunctionObjects.so");
writeControl timeStep;
writesInterval 1;
log true;
Compute functionObject in a boundary patch
writeFields false;
regionType patch;
name inlet;
operation sum;
Compute functionObject in this boundary patch
fields (phi);
}
• This functionObject is used to computed the mass flow across a boundary patch.
• Remember, the method is conservative so what is going in, is going out (unless you have
source terms).
• So if you want to measure the mass imbalance, setup this function object for each boundary
patch where you have flow entering or going out.
544
On-the-fly postprocessing – functionObjects
Final remarks on functionObjects
545
On-the-fly postprocessing – functionObjects
Running functionObjects a-posteriori
• Sometimes it can happen that you forget to use a functionObject or you want to execute a
functionObject a-posteriori (when the simulation is over).
• The solution to this problem is to use the solver with the option -postProcess. This will only
compute the new functionObject, it will not rerun the simulation.
• For instance, let us say that you forgot to use a given functionObject. Open the dictionary
controlDict, add the new functionObject, and type in the terminal,
• $> name_of_the_solver -postProcess –dict dictionary_location
• You also have the option of adding the new functionObject in an external file. If you chose this
option, do not forget to add the functionOption within the function sub-dictionary block:
function
{
//functionObject definitions here
};
• By proceeding in this way you do not need to rerun the simulation, you just compute the new
functionObject.
546
On-the-fly postprocessing – functionObjects
Running functionObjects a-posteriori
• In the directory system, you will find the following functionObjects external
dictionaries: functionObject1, functionObject2 and functionObject3
• Try to figure out what we are doing in every functionObject external dictionary.
• At this point, let us run each the functionObject a-posteriori. In the terminal type:
• In step 1, we are reading the dictionary functionObject1 and we are doing the
computation for all the saved solutions, except time zero.
• In step 2, we are reading the dictionary functionObject2 and we are doing the
computation for the time range 500 to 2000
• In step 3, we are reading the dictionary functionObject3 and we are doing the
computation only for he latest save solution.
547
On-the-fly postprocessing – functionObjects
Exercises
• Where is located the source code of the functionObjects?
• Try to run in parallel? Do all functionObjects work properly?
• Compute the Courant number using functionObjects.
• Compute the total pressure and velocity gradient using functionObjects (on-the-fly and a-posteriori).
• Sample data (points, lines and surfaces) using functionObjects (a-posteriori).
• Is it possible to do system calls using functionObjects? If so what functionObject will you use and how do
you use it? Setup a sample case.
• Is it possible to update dictionaries using functionObjects? If so what functionObjects will you use and how
do you use it? Setup a sample case.
• What are the compulsory entries of the functionObjects?
548
Roadmap
549
Sampling with the postProcess utility
• OpenFOAM® provides the postProcess utility to sample field data for plotting.
• The sampling parameters are specified in a dictionary located in the case system
directory.
• You can give any name to the input dictionary, hereafter we are going to name them
sampleDict (to sample along a line) and probesDict (to sample in a set of
probes).
• During the sampling, and inside the case directory, a new directory named
postProcessing will be created. In this directory, the sampled values are stored in
a sub-directory with the name of the input dictionary, in this case, sampleDict and
probesDict.
• This utility can sample points, lines, and surfaces.
• Data can be written in a range of formats including well-known plotting packages
such as: grace/xmgr, gnuplot and jPlot.
• The sampling can be executed by running the utility postProcess in the case
directory and according to the application syntax.
• A final word, this utility does not do the sampling while the solver is running. It does
the sampling after you finish the simulation.
550
Sampling with the postProcess utility
• To do sampling, we will use the solution from the previous case.
• If you do not have the solution, follow the instructions given in the previous slides.
• Hereafter, we will sample along a line and in a few probe locations, as illustrated in
the figure below.
551
Sampling with the postProcess utility
Running the case
552
Sampling with the postProcess utility
The sampleDict and probesDict dictionaries
• These dictionaries are located in the directory system.
• In this case, the sampleDict dictionary is used to sample along a line. This file
contains several entries to be set according to the user needs. The following entries
can be set,
• The choice of the interpolationScheme.
• The format of the line data output.
• The format of the surface data output.
• The fields to be sample.
• The sub-dictionaries that controls each sampling operation.
• In these sub-dictionaries you can set the name, type and geometrical
information of the sampling operation.
• In this case, the probesDict is used to sample in a set of points. This file contains
several entries to be set according to the user needs. The following entries,
• The fields to be sample.
• Location of the probes.
• The following functionObjects type can be used to do sampling: patchProbes,
probes, sets, or surfaces.
553
Sampling with the postProcess utility
The sampleDict dictionary
Note:
66 );
Use the banana method to know all the options available. 554
Sampling with the postProcess utility
The sampleDict dictionary
48 }
66 );
555
Sampling with the postProcess utility
The probesDict dictionary
20 (
21 p
22 U Fields to sample. No need to mention that they must exist.
23 );
27 probeLocations
28 (
29 (1.0 0 0)
30 (1.25 0 0)
31 (1.5 0 0)
32 (1.75 0 0)
33 (2.0 0 0) Location of the points.
34 (2.0 -.25 0)
35 (2.0 -.5 0)
36 (2.0 .25 0)
37 (2.0 .5 0)
38 );
Note:
Use the banana method to know all the options available. 556
Sampling with the postProcess utility
The probesDict dictionary
557
Sampling with the postProcess utility
The output files – functionObject type sets or surfaces
Scalars
#POINT_COORDINATES (X Y Z) SCALAR_VALUE
0 0 0.05 13.310995
0 0 0.1 19.293817
…
Vectors
#POINT_COORDINATES (X Y Z) VECTOR_COMPONENTS (X Y Z)
0 0 0.05 0 0 2.807395
0 0 0.1 0 0 2.826176
…
558
Sampling with the postProcess utility
The output files – functionObject type sets or surfaces
Scalars
#AXIS_COORDINATE SCALAR_VALUE
0 18.594038
0.0015 18.249091
…
Vectors
#AXIS_COORDINATE VECTOR_COMPONENTS (X Y Z)
0 0 0 1.6152966
0.0015 0 0 1.8067536
…
559
Sampling with the postProcess utility
The output files – functionObject type sets or surfaces
Scalars
#POINT_COORDINATES (X Y Z) SCALAR_VALUE
0 0 0.05 13.310995
0 0 0.1 19.293817
…
Vectors
#POINT_COORDINATES (X Y Z) VECTOR_COMPONENTS (X Y Z)
0 0 0.05 0 0 2.807395
0 0 0.1 0 0 2.826176
…
560
Sampling with the postProcess utility
The output files – functionObject type probes
Scalars
# Probe 0 (0 0 0.025)
# Probe 1 (0 0 0.05)
# Probe 2 (0 0 0.075)
# Probe 3 (0 0 0.1)
# Probe 0 1 2 3
# Time
0 0 0 0 0
0.005 19.1928 16.9497 14.2011 11.7580
0.01 16.6152 14.5294 12.1733 10.0789
…
…
…
561
Sampling with the postProcess utility
The output files – functionObject type probes
Vectors
# Probe 0 (0 0 0.025)
# Probe 1 (0 0 0.05)
# Probe 2 (0 0 0.075)
# Probe 3 (0 0 0.1)
# Probe 0 1 2 3
# Time
0 (0 0 0) (0 0 0) (0 0 0) (0 0 0)
0.005 (0 0 2.1927) (0 0 2.1927) (0 0 2.1927) (0 0 2.1927)
0.01 (0 0 2.5334) (0 0 2.5334) (0 0 2.5334) (0 0 2.5334)
…
…
…
562
Sampling with the postProcess utility
Exercises
• Where is located the source code of the utility postProcess?
• Try to do the sampling in parallel? Does it run? What about the output file?
• How many options are there available to do sampling in a line?
• Do point, line, and surface sampling using paraFoam/ParaView and compare with the output of the
postProcess utility. Do you get the same results?
• Compute the descriptive statistics of each column of the output files using gnuplot. Be careful with the
parentheses of the vector files.
(Hint: you can use sed within gnuplot)
563
Roadmap
564
Field manipulation
• Hereafter we are going to deal with field manipulation
• Field manipulation means modifying a field variable or deriving a new field
variable using the primitive variables computed during the solution stage.
• We will do the post-processing using the command line interface (CLI), or
non-GUI mode.
• The utility postProcess can be used as a single application, e.g.,
• $> postprocess –func vorticity
• Running the solver with the option –postprocess will only execute the
post-processing and it will let you access data available on the database for
the particular solver (such as physical properties or turbulence model).
565
Field manipulation
• To get a list of what can be computed using the postProcess utility, type in
the terminal:
• $> postProcess –list
• The utility postProcess can take many options. To get more information
on how to use the utility, type in the terminal:
• $> postProcess –help
• $> simpleFoam -postProcess –help
• The options of the solver using the –postProcess flag are the same as the
options of the utility postProcess.
• In the sub-directory $FOAM_UTILITIES/postProcessing/postProcess
you will find the utility postProcess.
• In the directory $FOAM_SRC/functionObjects, you will find the source
code of the objects that can be used to compute a new field.
566
Field manipulation
$PTOFC/postprocessing/supersonic_wedge/
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
567
Field manipulation
After computing the solution, we can compute derived fields (e.g., Mach number, density,
Courant number, vorticity, and so on), using the primitive fields (U, p, T)
Mach number Total pressure
568
Field manipulation
What are we going to do?
• We will use this case to introduce the postProcess utility for field manipulation.
• We will also show how to run the solver with the option -postProcess. This will let us do only
the post-processing after the solution has been computed, and it will let us access the database
of the solver.
• To find the numerical solution we will use the solver rhoPimpleFoam.
• rhoPimpleFoam is a transient solver for laminar or turbulent flow of compressible gas.
1. $> sh run_solver.sh
2. $> paraFoam
• Fell free to open the file run_solver.sh to know all the steps.
569
Field manipulation
• After finding the solution, we can compute the new field variables using the
primitive variables computed during the solution stage. In the terminal type:
571
Field manipulation
• After finding the solution, we can compute new field variables using the primitive
variables computed during the solution stage. In the terminal type:
• We can also use the utility postProcess to compute the average and integral of a
specified field over a patch. In the terminal type:
573
Roadmap
574
Data conversion
• OpenFOAM® gives users a lot of flexibility when it comes to scientific visualization.
• You are not obliged to use OpenFOAM® visualization tools (paraFoam or paraview).
• You can convert the solution obtained with OpenFOAM® to many third-party formats
by using OpenFOAM® data conversion utilities.
• If you are looking for a specific format and it is not supported, you can write your own
conversion tool.
• In the directory $FOAM_UTILITIES/postprocessing/dataConversion, you will
find the source code of the following data conversion utilities:
• foamDataToFluent • foamToTecplot360
• foamToEnsight • foamToTetDualMesh
• foamToEnsightParts • foamToVTK
• foamToGMV • smapToFoam
• To get more information on how to use a data conversion utility, you can read the
source code or type in the terminal:
• $> name_of_data_conversion_utility -help
575
Data conversion
ASCII ↔ Binary conversion
• Another utility that might come in handy, specially when dealing with
large meshes is foamFormatConvert.
17
18
application icoFoam; • This utility converts the mesh and field variables into ascii or binary
19 startFrom startTime; format.
20
21 startTime 0; • In order to manually edit the boundary file and the field variables
22
23 stopAt endTime; dictionaries (initial and boundary conditions), they must be in ascii
24
25 endTime 50; format.
26
27 deltaT 0.01; • After editing these files, we can convert them into binary format.
28
29
30
writeControl runTime;
• Working in binary format can significantly reduce data parsing and
31 writeInterval 1; dimension of the files (specially for large meshes).
32
33
34
purgeWrite 0;
• The drawback is that the files are not human readable anymore.
35 writeFormat binary;
36 • To convert ascii files into binary files, just type in the terminal:
37 writePrecision 8;
38 • $> foamFormatConvert
39 writeCompression off;
40
41 timeFormat general; • Remember you will need to set the keyword writeFormat to binary
42
43 timePrecision 6;
in the controlDict dictionary.
44
45 runTimeModifiable true; • In the same way, if you want to convert from binary to ascii, set the
keyword writeFormat to ascii in the controlDict dictionary and
type in the terminal:
• $> foamFormatConvert
576
Module 6
Finite volume method overview
577
Roadmap
578
Finite Volume Method: A Crash introduction
• Before continuing, we want to remind you that this a brief introduction to the FVM.
• There is much more under the hood.
• Let us use the general transport equation as the starting point to explain the FVM,
• We want to solve the general transport equation for the transported quantity in a
given domain, with given boundary conditions BC and initial conditions IC.
• 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 (in space and time).
• 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.
579
Finite Volume Method: A Crash introduction
• Let us use the general transport equation as the starting point to explain the FVM,
• Hereafter we are going to assume that the discretization practice is at least second
order accurate in space and time.
• As consequence of the previous requirement, all dependent variables are assumed
to vary linearly around a point P in space and instant t in time,
Profile assumptions using Taylor expansions around point P (in space) and point t (in time)
580
Finite Volume Method: A Crash introduction
• Let us divide the solution domain into a finite number of arbitrary control volumes or cells, such as the one
illustrated below.
• Inside each control volume the solution is sought.
• The control volumes can be of any shape (e.g., tetrahedrons, hexes, prisms, pyramids, dodecahedrons, and
so on). The only requirement is that the faces that made up the control volume need to be planar.
• We also know which control volumes are internal and which control volumes lie on the boundaries.
• In the control volume illustrated, the centroid P and face center f are known.
• We also assume that the values of all variables are computed and stored in the centroid of the control volume
Vp and that they are represented by a piecewise constant profile (the mean value). This is known as the
collocated arrangement.
• All the previous approximations are at least second order accurate (the ones in the shaded rectangle).
581
Finite Volume Method: A Crash introduction
• In the FVM, a lot of overhead goes into the data book-keeping of the domain information.
• We know the following information of every control volume in the domain:
• The control volume has a volume V and is constructed around point P, which is the
centroid of the control volume. Therefore the notation .
• The vector from the centroid P of to the centroid N of is named d.
• We also know all neighbors of the control volume .
• The control volume faces are labeled f, which also denotes the face center.
• The location where the vector d intersects a face is .
• The face area vector point outwards from the control volume, is located at the face
centroid, is normal to the face and has a magnitude equal to the area of the face.
• The vector from the centroid P to the face center f is named Pf.
582
Finite Volume Method: A Crash introduction
• Let us recall the Gauss or Divergence theorem,
583
Finite Volume Method: A Crash introduction
• Let us use the Gauss theorem to convert the volume integrals into surface integrals,
• At this point the problem reduces to interpolating somehow the cell centered values
(known quantities) to the face centers.
584
Finite Volume Method: A Crash introduction
• 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:
Gauss theorem:
585
Finite Volume Method: A Crash introduction
• Integrating in space each term of the general transport equation and by using Gauss
theorem, yields to the following discrete equations for each term
Diffusive term:
Gauss theorem:
586
Finite Volume Method: A Crash introduction
• Integrating in space each term of the general transport equation and by using Gauss
theorem, yields to the following discrete equations for each term
Gradient term:
where we have approximated the centroid gradients by using the Gauss theorem.
This method is second order accurate
Gauss theorem:
587
Finite Volume Method: A Crash introduction
• Integrating in space each term of the general transport equation and by using Gauss
theorem, yields to the following discrete equations for each term
Source term:
This approximation is exact if is either constant or varies linearly within the control
volume; otherwise is second order accurate.
Sc is the constant part of the source term and Sp is the non-linear part
Gauss theorem:
588
Finite Volume Method: A Crash introduction
• Using the previous equations to evaluate the general transport equation over all the
control volumes, we obtain the following semi-discrete equation
• 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.
589
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be
computed as follows,
• This type of interpolation scheme is known as upwind differencing and it is first order
accurate.
• This scheme is bounded (non-oscillatory) and diffusive.
591
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes
• By looking the figure below, the face values appearing in the convective flux can be
computed as follows,
• 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.,
594
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes
• Qualitative comparison of the upwind, linear upwind, linear, and Minmod TVD
schemes
595
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – TVD schemes
• Quantitative comparison of the upwind, linear upwind, linear, and Minmod TVD
schemes
596
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Unstructured meshes
• In the previous explanation, we assumed a line structure (figure A). That is, the cell centers PP,
P, and N are all aligned.
• In unstructured meshes (or meshes used in industrial cases), most of the times the cell center
PP is not aligned with the vector connecting cells P and N (figure B). Therefore, extending the
previous formulations to these meshes is not very straightforward.
• Higher-order schemes for unstructured meshes are an area of active research and new ideas
continue to emerge.
597
Finite Volume Method: A Crash introduction
Interpolation of the convective fluxes – Unstructured meshes
• A simple way around this problem is to redefine
higher-order schemes in terms of gradients at the
control volume P.
• For example, using the gradient of the cells, we can
compute the face values as follows,
Upwind →
Central difference →
• Notice that in this new formulation the cell PP does not appear any more.
• The problem now turns in the accurate and bounded evaluation of the gradients at the cell and
face centers.
• This can be done using the Gauss method, as previously explained.
598
Finite Volume Method: A Crash introduction
Interpolation of convective fluxes in a skew mesh
• In the case of a skew mesh (as the one in the figure), we should introduce a correction in order to maintain
second order accuracy and avoid unboundedness when computing gradients.
• One way of doing this is by using an iterative approach for computing successively better approximations to
the gradients.
• We can do a linear reconstruction of the cell and face gradients using compact stencils as follows.
1.
2.
Correction for
3. + interpolated
face gradient
Initial approximations
599
Finite Volume Method: A Crash introduction
Interpolation of diffusive fluxes in an orthogonal mesh
• By looking the figure below, the face values • By looking the figure below, the face values
appearing in the diffusive flux in an orthogonal appearing in the diffusive flux in a non-orthogonal
mesh can be computed as follows, mesh (20°) can be computed as follows,
• This is a central difference approximation of the • This type of approximation is second order accurate
first order derivative. This type of but involves a larger truncation error. It also uses a
approximation is second order accurate. larger numerical stencil, which make it less stable.
• Remember, the non-orthogonal angle is the angle between the vector S and the vector d
600
Finite Volume Method: A Crash introduction
Correction of diffusive fluxes in a non-orthogonal mesh
• By looking the figures below, the face values appearing in the diffusive flux in a non-
orthogonal mesh ( ) can be computed as follows.
• Using the over-relaxed approach, the diffusive fluxes can be corrected as follow,
Over-relaxed approach
601
Finite Volume Method: A Crash introduction
Mesh induced errors
• In order to maintain second order accuracy, and to avoid unboundedness, we need to correct
non-orthogonality and skewness errors.
• The ideal case is to have an orthogonal and non skew mesh, but this is the exception rather
than the rule.
Orthogonal and non skew mesh Non-orthogonal and non skew mesh
• The main advantage of the MOL method, is that it allows us to select numerical
approximations of different accuracy for the spatial and temporal terms. Each
term can be treated differently to yield to different accuracies.
603
Finite Volume Method: A Crash introduction
Temporal discretization
• Now, we evaluate in time the semi-discrete general transport equation
• At this stage, we can use any time discretization scheme, e.g., Crank-Nicolson, euler
implicit, forward euler, backward differencing, adams-bashforth, adams-moulton.
• It should be noted that the order of the temporal discretization of the transient term
does not need to be the same as the order of the discretization of the spatial terms.
Each term can be treated differently to yield different accuracies. As long as the
individual terms are at least second order accurate, the overall accuracy will also be
second order.
604
Finite Volume Method: A Crash introduction
Linear system solution
• After spatial and temporal discretization and by using equation
in every control volume of the domain, a system of linear algebraic equations for
the transported quantity is assembled,
gradSchemes
• The discretization schemes can be chosen in a term-by-term
{ basis.
default Gauss linear;
grad(p) Gauss linear; • The keyword ddtSchemes refers to the time discretization.
}
• The keyword gradSchemes refers to the gradient term
divSchemes discretization.
{
default none; • The keyword divSchemes refers to the convective terms
div(phi,U) Gauss linear; discretization.
}
• The keyword laplacianSchemes refers to the Laplacian terms
laplacianSchemes
{
discretization.
default Gauss linear orthogonal; • The keyword interpolationSchemes refers to the method used
}
to interpolate values from cell centers to face centers. It is
interpolationSchemes unlikely that you will need to use something different from
{ linear.
default linear;
} • The keyword snGradSchemes refers to the discretization of
snGradSchemes
the surface normal gradients evaluated at the faces.
{
default orthogonal;
• Remember, if you want to know the options available for each
} keyword you can use the banana method.
607
Finite Volume Method: A Crash introduction
Time discretization schemes
• There are many time discretization schemes available in OpenFOAM®.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/ddtSchemes
• These are the time discretization schemes that you will use most of the times:
• steadyState: for steady state simulations (implicit/explicit).
• Euler: time dependent first order (implicit/explicit), bounded.
• backward: time dependent second order (implicit), bounded/unbounded.
• CrankNicolson: time dependent second order (implicit), bounded/unbounded.
608
Finite Volume Method: A Crash introduction
Time discretization schemes
• The Crank-Nicolson method as it is implemented in OpenFOAM®, uses a blending factor.
ddtSchemes
{
default CrankNicolson ;
}
• Setting to 0 is equivalent to running a pure Euler scheme (robust but first order accurate).
• By setting the blending factor equal to 1 you use a pure Crank-Nicolson (accurate but
oscillatory, formally second order accurate).
• If you set the blending factor to 0.5, you get something in between first order accuracy and
second order accuracy, or in other words, you get the best of both worlds.
• A blending factor of 0.9 is safe to use for most applications.
609
Finite Volume Method: A Crash introduction
Convective terms discretization schemes
• There are many convective terms discretization schemes available in OpenFOAM® (more than
50 last time we checked).
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/interpolation/surfaceInterpolation
• These are the convective discretization schemes that you will use most of the times:
• upwind: first order accurate.
• linearUpwind: second order accurate, bounded.
• linear: second order accurate, unbounded.
• A good TVD scheme (vanLeer or Minmod): TVD, second order accurate, bounded.
• limitedLinear: second order accurate, unbounded, but more stable than pure linear.
Recommended for LES simulations (kind of similar to the Fromm method).
gradSchemes
{
grad(U) cellMDLimited Gauss linear 1.0;
}
divSchemes
{
div(phi,U) Gauss linearUpwind grad(U);
}
611
Finite Volume Method: A Crash introduction
Gradient terms discretization schemes
• There are many gradient discretization schemes available in OpenFOAM®.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/gradSchemes
• These are the gradient discretization schemes that you will use most of the times:
• Gauss
• leastSquares
• To avoid overshoots or undershoots when computing the gradients, you can use gradient
limiters.
• Gradient limiters increase the stability of the method but add diffusion due to clipping.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/gradSchemes/limitedGradSchemes
• These are the most important gradient limiter schemes available in OpenFOAM®:
• cellLimited, cellMDLimited, faceLimited, faceMDLimited
• All of the gradient discretization schemes are at least second order accurate.
612
Finite Volume Method: A Crash introduction
Gradient terms discretization schemes
• These are the gradient limiter schemes available in OpenFOAM®:
gradSchemes
{
default cellMDLimited Gauss linear ;
}
• Setting to 0 is equivalent to turning off the gradient limiter. You gain accuracy but the solution
might become unbounded.
• By setting the blending factor equal to 1 the limiter is always on. You gain stability but you give
up accuracy (due to gradient clipping).
• If you set the blending factor to 0.5, you get the best of both worlds.
• You can use limiters with all gradient discretization schemes.
614
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• There are many Laplacian terms discretization schemes available in OpenFOAM®.
• You will find the source code in the following directory:
• $WM_PROJECT_DIR/src/finiteVolume/finiteVolume/snGradSchemes
• These are the Laplacian terms discretization schemes that you will use most of the times:
• orthogonal: mainly limited for hexahedral meshes with no grading (a perfect mesh).
Second order accurate, bounded on perfect meshes, without non-orthogonal
corrections.
• corrected: for meshes with grading and non-orthogonality. Second order accurate,
bounded depending on the quality of the mesh, with non-orthogonal corrections.
• limited: for meshes with grading and non-orthogonality. Second order accurate,
bounded depending on the quality of the mesh, with non-orthogonal corrections.
• uncorrected: usually used on bad quality meshes with grading and non-orthogonality.
Second order accurate, without non-orthogonal corrections. Stable but more diffusive
than the limited and corrected methods.
615
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• The limited method uses a blending factor .
Surface normal gradients discretization
Only option
laplacianSchemes
{
default Gauss linear limited ;
}
Interpolation method of the diffusion coefficient
• Setting to 1 is equivalent to using the corrected method. You gain accuracy, but the solution might
become unbounded.
• By setting the blending factor equal to 0 is equivalent to using the uncorrected method. You give up accuracy
but gain stability.
• If you set the blending factor to 0.5, you get the best of both worlds. In this case, the non-orthogonal
contribution does not exceed the orthogonal part. You give up accuracy but gain stability.
• For meshes with non-orthogonality less than 70, you can set the blending factor to 1.
• For meshes with non-orthogonality between 70 and 85, you can set the blending factor to 0.5
• For meshes with non-orthogonality more than 85, it is better to get a better mesh. But if you 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). 616
Finite Volume Method: A Crash introduction
Laplacian terms discretization schemes
• The surface normal gradients terms usually use the same method as the one chosen for the
Laplacian terms.
• For instance, if you are using the limited 1 method for the Laplacian terms, you can use the
same method for snGradSchemes:
laplacianSchemes
{
default Gauss linear limited 1;
}
snGradSchemes
{
default limited 1;
}
617
Finite Volume Method: A Crash introduction
What method should I use?
ddtSchemes • This setup is recommended for most of
{
default CrankNicolson 0;
the cases.
}
gradSchemes • It is equivalent to the default method you will find in
{ commercial solvers.
default cellLimited Gauss linear 0.5;
grad(U) cellLimited Gauss linear 1; • In overall, this setup is second order accurate and
}
divSchemes
fully bounded.
{
default none;
• According to the quality of your mesh, you will need
div(phi,U) Gauss linearUpwindV grad(U); to change the blending factor of the
div(phi,omega) Gauss linearUpwind default; laplacianSchemes and snGradSchemes
div(phi,k) Gauss linearUpwind default;
keywords.
div((nuEff*dev(T(grad(U))))) Gauss linear;
}
laplacianSchemes
• To keep temporal diffusion to a minimum, use a CFL
{ number less than 2.
default Gauss linear limited 1;
} • If during the simulation the turbulence quantities
interpolationSchemes
{
become unbounded, you can safely change the
default linear; discretization scheme to upwind. After all,
}
snGradSchemes
turbulence is diffusion.
{
default limited 1; • Sometimes using gradient limiters for the pressure
} gradient grad(p) is not a good idea as it adds
diffusion.
618
Finite Volume Method: A Crash introduction
A very accurate but oscillatory numerics
ddtSchemes • If you are looking for more accuracy, you can use
{
default backward;
this method.
}
gradSchemes • In overall, this setup is second order accurate but
{ oscillatory.
default Gauss linear;
} • Use this setup with LES simulations or laminar
divSchemes
{ flows with no complex physics, and meshes with
default none; overall good quality.
div(phi,U) Gauss linear;
div(phi,omega) Gauss limitedlinear 1;
div(phi,k) Gauss limitedLinear 1;
div((nuEff*dev(T(grad(U))))) Gauss linear;
}
laplacianSchemes
{
default Gauss linear limited 1;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default limited 1;
}
619
Finite Volume Method: A Crash introduction
A very stable but too diffusive numerics
ddtSchemes • If you are looking for extra stability, you can use this
{
default Euler;
method.
}
gradSchemes • This setup is very stable but too diffusive.
{
default cellLimited Gauss linear 1; • This setup is first order in space and time.
grad(U) cellLimited Gauss linear 1;
}
• You can use this setup to start the solution in the
divSchemes presence of bad quality meshes or strong
{
default none;
discontinuities.
div(phi,U) Gauss upwind;
• Remember, you can start using a first order method
div(phi,omega) Gauss upwind;
div(phi,k) Gauss upwind; and then switch to a second order method.
div((nuEff*dev(T(grad(U))))) Gauss linear;
} • Start robustly, end with accuracy.
laplacianSchemes
{ • If this setup fails, you better check boundary
default Gauss linear limited 0.5; conditions, physical properties, under-relaxation
}
interpolationSchemes factors, time-step, and so on.
{
default linear;
}
snGradSchemes
{
default limited 0.5;
}
620
Roadmap
621
On the CFL number
• First of all, what is the CFL or Courant number?
• In one dimension, the CFL number is defined as,
• By the way, and this is extremely important, the CFL condition is a necessary
condition for stability (and hence convergence).
• But it is not always sufficient to guarantee stability.
• Other properties of the discretization schemes that you should observe are:
conservationess, boundedness, transportiveness, and accuracy.
624
On the CFL number
How to control the CFL number
application pimpleFoam; • You can control the CFL number by changing the mesh cell
size or changing the time-step size.
startFrom latestTime;
maxCo 2.0;
maxDeltaT 0.001;
625
On the CFL number
How to control the CFL number
application pimpleFoam; • The option adjustTimeStep will automatically adjust the time
step to achieve the maximum desired courant number
startFrom latestTime;
(maxCo) or time-step size (maxDeltaT).
startTime 0;
stopAt endTime;
• When any of these conditions is reached, the solver will stop
scaling the time-step size.
endTime 10;
deltaT 0.0001;
• To use these features, you need to turn-on the option
adjustTimeStep.
writeControl runTime;
writeInterval 0.1;
• Remember, the first time-step of the simulation is done using
the value defined with the keyword deltaT and then it is
purgeWrite 0;
automatically scaled (up or down), to achieve the desired
writeFormat ascii; maximum values (maxCo and maxDeltaT).
writePrecision 8;
• It is recommended to start the simulation with a low time-step
writeCompression off;
in order to let the solver scale-up the time-step size.
timeFormat general;
• If you want to change the values on-the-fly, you need to turn-
timePrecision 6;
on the option runTimeModifiable.
runTimeModifiable yes;
• The feature adjustTimeStep is only present in the PIMPLE
adjustTimeStep yes;
family solvers, but it can be added to any solver by modifying
maxCo 2.0; the source code.
maxDeltaT 0.001;
626
On the CFL number
The output screen
• This is the output screen of a solver supporting the option adjustTimeStep.
• In this case maxCo is equal 2 and maxDeltaT is equal to 0.001.
• Notice that the solver reached the maximum allowable maxDeltaT.
Courant Number mean: 0.10863988 max: 0.73950028 Courant number (mean and maximum values)
deltaT = 0.001 Current time-step
Time = 30.000289542261612 Simulation time
PIMPLE: iteration 1 One PIMPLE iteration (outer loop), this is equivalent to PISO
DILUPBiCG: Solving for Ux, Initial residual = 0.003190933, Final residual = 1.0207483e-09, No Iterations 5
DILUPBiCG: Solving for Uy, Initial residual = 0.0049140114, Final residual = 8.5790109e-10, No Iterations 5
DILUPBiCG: Solving for Uz, Initial residual = 0.010705877, Final residual = 3.5464756e-09, No Iterations 4
GAMG: Solving for p, Initial residual = 0.024334674, Final residual = 0.0005180308, No Iterations 3
GAMG: Solving for p, Initial residual = 0.00051825089, Final residual = 1.6415538e-05, No Iterations 5
time step continuity errors : sum local = 8.768064e-10, global = 9.8389717e-11, cumulative = -2.6474162e-07
GAMG: Solving for p, Initial residual = 0.00087813032, Final residual = 1.6222017e-05, No Iterations 3
GAMG: Solving for p, Initial residual = 1.6217958e-05, Final residual = 6.4475277e-06, No Iterations 1
time step continuity errors : sum local = 3.4456296e-10, global = 2.6009599e-12, cumulative = -2.6473902e-07
ExecutionTime = 33091.06 s ClockTime = 33214 s
CPU time and wall clock
fieldMinMax domainminandmax output:
min(p) = -0.59404715 at location (-0.019 0.02082288 0.072) on processor 1
max(p) = 0.18373302 at location (-0.02083962 -0.003 -0.136) on processor 1
min(U) = (0.29583255 -0.4833922 -0.0048229716) at location (-0.02259661 -0.02082288 -0.072) on processor 0
max(U) = (0.59710937 0.32913292 0.020043679) at location (0.11338793 -0.03267608 0.12) on processor 3
min(nut) = 1.6594481e-10 at location (0.009 -0.02 0.024) on processor 0
max(nut) = 0.00014588174 at location (-0.02083962 0.019 0.072) on processor 1
628
Linear solvers in OpenFOAM®
• After spatial and temporal discretization and by using equation
in every control volume of the domain, a system of linear algebraic equations for
the transported quantity is assembled
630
Linear solvers in OpenFOAM®
Linear solvers
solvers • In this generic case, to solve the pressure (p) we are using the
{ PCG method with the DIC preconditioner, an absolute
p
{
tolerance equal to 1e-06 and a relative tolerance relTol equal
solver PCG; to 0.
preconditioner DIC;
tolerance 1e-06; • The entry pFinal refers to the final pressure correction (notice
relTol 0; that we are using macro syntax), and we are using a relative
}
tolerance relTol equal to 0.
pFinal
{ • To solve the velocity field (U) we are using the PBiCGStab
$p; method with the DILU preconditoner, an absolute tolerance
relTol 0;
}
equal to 1e-08 and a relative tolerance relTol equal to 0.
U
{
• The linear solvers will iterative until reaching any of the
solver PBiCGStab; tolerance values set by the user or reaching a maximum value
preconditioner DILU; of iterations (optional entry).
tolerance 1e-08;
relTol 0; • FYI, solving for the velocity is relatively inexpensive, whereas
} solving for the pressure is expensive.
}
• The pressure equation is particularly important as it governs
PISO mass conservation.
{
nCorrectors 2; • If you do not solve the equations accurately enough (tolerance),
nNonOrthogonalCorrectors 1;
the physics might be wrong.
}
• Selection of the tolerance is of paramount importance and it
might be problem dependent.
631
Linear solvers in OpenFOAM®
Linear solvers
solvers • The linear solvers are iterative, i.e., they are based on reducing
{ the equation residual over a succession of solutions.
p
{ • The residual is a measure of the error in the solution so that the
solver PCG;
preconditioner DIC;
smaller it is, the more accurate the solution.
tolerance 1e-06;
• More precisely, the residual is evaluated by substituting the
relTol 0;
} current solution into the equation and taking the magnitude of
pFinal the difference between the left- and right-hand sides (L2-norm).
{
$p;
relTol 0;
}
U
{
solver PBiCGStab;
preconditioner DILU;
• It is also normalized to make it independent of the scale of the
tolerance 1e-08; problem being analyzed.
relTol 0;
}
}
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
632
Linear solvers in OpenFOAM®
Linear solvers
solvers • Before solving an equation for a particular field, the initial
{ residual is evaluated based on the current values of the field.
p
{ • After each solver iteration the residual is re-evaluated. The
solver PCG;
preconditioner DIC;
solver stops if either of the following conditions are reached:
tolerance 1e-06;
• The residual falls below the solver tolerance, tolerance.
relTol 0;
} • The ratio of current to initial residuals falls below the solver
pFinal
{ relative tolerance, relTol.
$p; • The number of iterations exceeds a maximum number of
relTol 0;
}
iterations, maxIter.
U
{
• The solver tolerance should represent the level at which the
solver PBiCG; residual is small enough that the solution can be deemed
preconditioner DILU; sufficiently accurate.
tolerance 1e-08;
relTol 0; • The keyword maxIter is optional and the default value is 1000.
minIter 3;
maxIter 100; • The user can also define the minimum number of iterations
} using the keyword minIter. This keyword is optional, and the
}
default value is 0.
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
633
Linear solvers in OpenFOAM®
Linear solvers
• These are the linear solvers available in OpenFOAM®:
• You will find the source code of the linear solvers in the following directory:
• $WM_PROJECT_DIR/src/OpenFOAM/matrices/lduMatrix/solvers
Time = 50
636
Linear solvers in OpenFOAM®
Linear solvers
• So how do we set the tolerances?
• The pressure equation is particularly important, so we should resolve it accurately.
Solving the pressure equation is the expensive part of the whole iterative process.
• For the pressure equation (symmetric matrix), you can start the simulation with a
tolerance equal to 1e-6 and relTol equal to 0.01. After a while you change these
values to 1e-6 and 0.0, respectively.
• If the linear solver is taking too much time, you can change the convergence criterion
to 1e-4 and relTol equal to 0.05. You usually will do this during the first iterations.
p p
{ {
solver PCG; solver PCG;
preconditioner DIC; preconditioner DIC;
tolerance 1e-6; tolerance 1e-6;
relTol 0.01; relTol 0.0;
} }
637
Linear solvers in OpenFOAM®
Linear solvers
• For the velocity field (U) and the transported quantities (asymmetric matrices), you
can use the following criterion.
• Solving for these variables is relatively inexpensive, so you can start right away with a
tight tolerance
U U
{ {
solver PBiCGStab; solver PBiCGStab;
preconditioner DILU; preconditioner DILU;
tolerance 1e-8; tolerance 1e-8;
relTol 0.001; relTol 0.0;
} }
638
Linear solvers in OpenFOAM®
Linear solvers
• It is also a good idea to set the minimum number of iterations (minIter), we
recommend using a value of 3.
• If your solver is doing too many iterations, you can set the maximum number of
iterations (maxIter).
• But be careful, if the solver reach the maximum number of iterations it will stop, we
are talking about unconverged time-steps or outer-iterations.
• Setting the maximum number of iterations is especially useful during the first time-
steps where the linear solver takes longer to converge.
• You can set minIter and maxIter in all symmetric and asymmetric linear solvers.
p
{
solver PCG;
preconditioner DIC;
tolerance 1e-6;
relTol 0.01;
minIter 3;
maxIter 100;
}
639
Linear solvers in OpenFOAM®
Linear solvers
• When you use the PISO or PIMPLE method, you also have the option to set the
tolerance for the final pressure corrector step (pFinal).
• By proceeding in this way, you can put all the computational effort only in the last
corrector step (pFinal).
• For all the intermediate corrector steps, you can use a more relaxed convergence
criterion.
• For example, you can use the following solver and tolerance criterion for all the
intermediate corrector steps (p), then in the final corrector step (pFinal) you tight the
solver tolerance.
p pFinal
{ {
solver PCG; solver PCG;
preconditioner DIC; preconditioner DIC;
tolerance 1e-4; tolerance 1e-6;
relTol 0.05; relTol 0.0;
} }
640
Linear solvers in OpenFOAM®
Linear solvers
• When you use the PISO or PIMPLE method, you also have the option to set the
tolerance for the final pressure corrector step (pFinal).
• By proceeding in this way, you can put all the computational effort only in the last
corrector step (pFinal in this case).
• For all the intermediate corrector steps (p), you can use a more relaxed convergence
criterion.
• If you proceed in this way, it is recommended to do at least 2 corrector steps
(nCorrectors).
PIMPLE: iteration 1
DILUPBiCG: Solving for Ux, Initial residual = 0.0024649332, Final residual = 2.3403547e-09, No Iterations 4
DILUPBiCG: Solving for Uy, Initial residual = 0.0044355904, Final residual = 1.8966277e-09, No Iterations 4
DILUPBiCG: Solving for Uz, Initial residual = 0.010100894, Final residual = 1.4724403e-09, No Iterations 4
GAMG: Solving for p, Initial residual = 0.018497918, Final residual = 0.00058090899, No Iterations 3
1 p
GAMG: Solving for p, Initial residual = 0.00058090857, Final residual = 2.5748489e-05, No Iterations 5
time step continuity errors : sum local = 1.2367812e-09, global = 2.8865505e-11, cumulative = 1.057806e-08
GAMG: Solving for p, Initial residual = 0.00076032002, Final residual = 2.3965621e-05, No Iterations 3 p
2 GAMG: Solving for p, Initial residual = 2.3961044e-05, Final residual = 6.3151172e-06, No Iterations 2 pFinal
time step continuity errors : sum local = 3.0345314e-10, global = -3.0075104e-12, cumulative = 1.0575052e-08
DILUPBiCG: Solving for omega, Initial residual = 0.00073937735, Final residual = 1.2839908e-10, No Iterations 4
DILUPBiCG: Solving for k, Initial residual = 0.0018291502, Final residual = 8.5494234e-09, No Iterations 3
ExecutionTime = 29544.18 s ClockTime = 29600 s
nCorrectors 641
Linear solvers in OpenFOAM®
Linear solvers
• As we are solving a sparse matrix, the more diagonal the matrix is, the best the convergence rate will be.
• So it is highly advisable to use the utility renumberMesh before running the simulation.
• $> renumberMesh –overwrite
• The utility renumberMesh can dramatically increase the speed of the linear solvers, specially during the first
iterations.
• You will find the source code and the master dictionary in the following directory:
• $WM_PROJECT_DIR/applications/utilities/mesh/manipulation/renumberMesh
• The idea behind reordering is to make the matrix more diagonally dominant, therefore, speeding up the
iterative solver.
Matrix structure plot before reordering Matrix structure plot after reordering
Note: this is the actual pressure matrix from an OpenFOAM® model case 642
Linear solvers in OpenFOAM®
On the multigrid solvers
• The development of multigrid solvers (GAMG in OpenFOAM®), together with the
development of high resolution TVD schemes and parallel computing, are among the
most remarkable achievements of the history of CFD.
• Most of the time using the GAMG linear solver is fine. However, if you see that the
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.
643
Linear solvers in OpenFOAM®
On the multigrid solvers tolerances
• If you go for the GAMG linear solver for symmetric matrices (e.g., pressure), the
following tolerances are acceptable for most of the cases.
p pFinal
{ {
solver GAMG; solver GAMG;
tolerance 1e-6; tolerance 1e-6;
relTol 0.01; relTol 0;
smoother GaussSeidel; smoother GaussSeidel;
nPreSweeps 0; nPreSweeps 0;
nPostSweeps 2; nPostSweeps 2;
cacheAgglomeration on; cacheAgglomeration on;
agglomerator faceAreaPair; agglomerator faceAreaPair;
nCellsInCoarsestLevel 100; nCellsInCoarsestLevel 100;
mergeLevels 1; mergeLevels 1;
minIter 3; minIter 3;
} }
NOTE:
The GAMG parameters are not optimized, that is up to you.
Most of the times is safe to use the default parameters. 644
Linear solvers in OpenFOAM®
Linear solvers tolerances – Steady simulations
• The previous tolerances are fine for unsteady solver.
• For extremely coupled problems you might need to have tighter tolerances.
• You can use the same tolerances for steady solvers. However, it is acceptable to use
a looser criterion.
• You can also set the convergence controls based on residuals of fields. The controls
are specified in the residualControls sub-dictionary of the dictionary file
fvSolution.
SIMPLE
{
nNonOrthogonalCorrectors 2;
residualControl
{
p 1e-4; Residual control for every
U 1e-4; field variable you are solving
}
}
645
Linear solvers in OpenFOAM®
Linear solvers benchmarking of a model case
Case Linear solver for P Preconditioner or smoother MR Time QOI
647
Roadmap
648
Pressure-Velocity coupling in OpenFOAM®
• To solve the Navier-Stokes equations we need to use a solution
approach able to deal with the nonlinearities of the governing
equations and with the coupled set of equations.
649
Pressure-Velocity coupling in OpenFOAM®
• Many numerical methods exist to solve the Navier-Stokes equations, just to name a few:
• Pressure-correction methods (Predictor-Corrector type).
• SIMPLE, SIMPLEC, SIMPLER, PISO.
• Projection methods.
• Fractional step (operator splitting), MAC, SOLA.
• Density-based methods and preconditioned solvers.
• Riemann solvers, ROE, HLLC, AUSM+, ENO, WENO.
• Artificial compressibility methods.
• Artificial viscosity methods.
• The most widely used approaches for solving the NSE are:
• Pressure-based approach (predictor-corrector).
• Density-based approach.
• Historically speaking, the pressure-based approach was developed for low-speed
incompressible flows, while the density-based approach was mainly developed for high-speed
compressible flows.
• However, both methods have been extended and reformulated to solve and operate for a wide
range of flow conditions beyond their original intent.
• In OpenFOAM®, you will find segregated pressure-based solvers. 650
Pressure-Velocity coupling in OpenFOAM®
• In OpenFOAM®, you will find segregated pressure-based solvers.
• The following methods are available:
• SIMPLE (Semi-Implicit Method for Pressure-Linked Equations)
• SIMPLEC (SIMPLE Corrected/Consistent)
• PISO (Pressure Implicit with Splitting Operators)
• You will find the solvers in the following directory:
• $WM_PROJECT_DIR/applications/solvers
• Additionally, you will find something called PIMPLE, which is an hybrid between SIMPLE and
PISO. This method is formulated for very large time-steps and pseudo-transient simulations.
• In OpenFOAM®, the PISO and PIMPLE methods are formulated for unsteady simulations.
• Whereas, the SIMPLE and SIMPLEC methods are formulated for steady simulations.
• If conserving time is not a priority, you can use the PIMPLE method for pseudo transient
simulations.
• The pseudo transient PIMPLE method is more stable than the SIMPLE method, but it has a
higher computational cost.
• Depending on the method and solver you are using, you will need to define a specific sub-
dictionary in the dictionary file fvSolution.
• For instance, if you are using the PISO method, you will need to specify the PISO sub-
dictionary.
• And depending on the method, each sub-dictionary will have different entries.
651
Pressure-Velocity coupling in OpenFOAM®
On the origins of the methods
• SIMPLE
• S. V. Patankar and D. B. Spalding, “A calculation procedure for heat, mass and
momentum transfer in three-dimensional parabolic flows”, Int. J. Heat Mass Transfer,
15, 1787-1806 (1972).
• SIMPLE-C
• J. P. Van Doormaal and G. D. Raithby, “Enhancements of the SIMPLE method for
predicting incompressible fluid flows”, Numer. Heat Transfer, 7, 147-163 (1984).
• PISO
• R. I. Issa, “Solution of the implicitly discretized fluid flow equations by operator-
splitting”, J. Comput. Phys., 62, 40-65 (1985).
• PIMPLE
• Unknown origins.
• Useful reference:
• I. E. Barton, “Comparison of SIMPLE and PISO-type algorithms for transient flows, Int.
J. Numerical methods in fluids, 26,459-483 (1998).
652
Pressure-Velocity coupling in OpenFOAM®
Pressure-velocity coupling using Pressure-velocity coupling using
the SIMPLE method the PISO method
Initial guess p*, u*, v*, w*
No Yes
Check convergence STOP
653
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution.
• It controls the options related to the SIMPLE pressure-velocity coupling method.
• The SIMPLE method only makes 1 correction.
• An additional correction to account for mesh non-orthogonality is available when using the
SIMPLE method. The number of non-orthogonal correctors is specified by the
nNonOrthogonalCorrectors keyword.
• The number of non-orthogonal correctors is chosen according to the mesh quality. For orthogonal
meshes you can use 0, whereas, for non-orthogonal meshes it is recommended to do at least 1
correction.
• However, it is strongly recommended to do at least 1 non-orthogonal correction.
SIMPLE
{
nNonOrthogonalCorrectors 1;
}
654
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
• You can use the optional keyword consistent to enable or disable the SIMPLEC method.
• This option is disable by default.
• In the SIMPLEC method, the cost per iteration is marginally higher but the convergence rate is
better so the number of iterations can be reduced.
• The SIMPLEC method relaxes the pressure in a consistent manner and additional relaxation of
the pressure is not generally necessary.
• In addition, convergence of the p-U system is better and still is reliable with less aggressive
relaxation of the momentum equation.
SIMPLE
{
consistent yes;
nNonOrthogonalCorrectors 1;
}
655
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
• Typical under-relaxation factors for the SIMPLE and SIMPLEC methods.
• Remember the under-relaxation factors are problem dependent.
SIMPLE SIMPLEC
relaxationFactors relaxationFactors
{ {
fields equations
{ {
p 0.3; U 0.9;
} k 0.9;
equations omega 0.9;
{ }
U 0.7; }
k 0.7;
omega 0.7;
}
}
656
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE sub-dictionary
SIMPLEC
• If you are planning to use the SIMPLEC
method, we recommend you using under- relaxationFactors
relaxation factors a little bit more {
fields
conservative that the commonly
{
recommended values.
p 0.7;
• If during the simulation you still have some }
stability problems, try to reduce all the values equations
to 0.5. {
p 0.7;
• Remember the under-relaxation factors are
U 0.7;
problem dependent.
k 0.7;
• For complex physics, it is recommended to omega 0.7;
start the simulation with low values (about }
0.3), and then increase the values slowly up }
to 0.7.
657
Pressure-Velocity coupling in OpenFOAM®
The SIMPLE loop in OpenFOAM®
fvVectorMatrix UEqn
(
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
);
solve(UEqn == -fvc::grad(p));
fvScalarMatrix pEqn
(
fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
);
U = HbyA – rAU*fvc::grad(p);
658
Pressure-Velocity coupling in OpenFOAM®
The PISO sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution.
• It controls the options related to the PISO pressure-velocity coupling method.
• The PISO method requires at least one correction (nCorrectors). To improve accuracy and
stability you can increase the number of corrections.
• 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
method. The number of non-orthogonal correctors is specified by the
nNonOrthogonalCorrectors keyword.
• The number of non-orthogonal correctors is chosen according to the mesh quality. For orthogonal
meshes you can use 0, whereas, for non-orthogonal meshes it is recommended to do at least 1
correction.
• However, it is strongly recommended to do are least 1 non-orthogonal correction.
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
659
Pressure-Velocity coupling in OpenFOAM®
The PISO sub-dictionary
• You can use the optional keyword momentumPredictor to enable or disable the momentum
predictor step.
• The momentum predictor helps in stabilizing the solution as we are computing better
approximations for the velocity.
• It is clear that this will add an extra computational cost, which is negligible.
• In most of the solvers, this option is enabled by default.
• It is recommended to use this option for highly convective flows (high Reynolds number). If you
are working with low Reynolds flow or creeping flows it is recommended to turn it off.
• When you enable the option momentumPredictor, you will need to define the linear solvers for
the variables .*Final (we are using regex notation).
PISO
{
momentumPredictor yes;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
660
Pressure-Velocity coupling in OpenFOAM®
The PISO loop in OpenFOAM®
fvVectorMatrix UEqn
(
fvm::ddt(U) + fvm::div(phi, U) - fvm::laplacian(nu, U)
);
solve(UEqn == -fvc::grad(p));
fvScalarMatrix pEqn
(
fvm::laplacian(rAU, p) == fvc::div(phiHbyA)
);
U = HbyA – rAU*fvc::grad(p);
661
Pressure-Velocity coupling in OpenFOAM®
The PIMPLE sub-dictionary
• This sub-dictionary is located in the dictionary file fvSolution.
• It controls the options related to the PIMPLE pressure-velocity coupling method.
• The PIMPLE method works very similar to the PISO method. In fact, setting the keyword
nOuterCorrectors to 1 is equivalent to running using the PISO method.
• The keyword nOuterCorrectors controls a loop outside the PISO loop.
• To gain more stability, especially when using large time-steps, you can use more outer correctors
(nOuterCorrectors). Have in mind that this will highly increase the computational cost.
• Also, if you use under-relaxation factors with more than one nOuterCorrectors, your solution is
not anymore time accurate. You are working in pseudo-transient simulations mode.
PIMPLE
{
momentumPredictor yes;
nOuterCorrectors 1;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
}
662
Roadmap
663
Unsteady and steady simulations
Sliding grids – Continuous stirred tank reactor
• Nearly all flows in nature and industrial applications www.wolfdynamics.com/wiki/FVM_uns/ani5.gif
are unsteady (also known as transient or
time-dependent).
• Unsteadiness can be due to:
• Instabilities.
• Non-equilibrium initial conditions.
• Time-dependent boundary conditions. Multiphase flow
• Source terms. www.wolfdynamics.com/wiki/FVM_uns/ani3.gif
664
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
• Select the time step. The time-step must be chosen in such a way that it resolves the time-dependent features
and maintains solver stability.
• Select the temporal discretization scheme.
• Set the tolerance (absolute and/or relative) of the linear solvers.
• Monitor the CFL number.
• Monitor the stability and boundedness of the solution.
• Monitor a quantity of interest.
• And of course, you need to save the solution with a given frequency.
• Have in mind that unsteady simulations generate a lot of data.
• End time of the simulation?, it is up to you.
• In the controlDict dictionary you need to set runtime parameters and general instructions on how to run the
case (such as time step and maximum CFL number). You also set the saving frequency.
• In the fvSchemes dictionary you need to set the temporal discretization scheme.
• In the fvSolution dictionary you need to set the linear solvers.
• Also, you will need to set the number of corrections of the velocity-pressure coupling method used (e.g. PISO
or PIMPLE), this is done in the fvSolution dictionary.
• Additionally, you may set functionObjects in the controlDict dictionary. The functionObjects are used to
do sampling, probing and co-processing while the simulation is running.
665
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
ddtSchemes • The fvSchemes dictionary contains the information related to
{ time discretization and spatial discretization schemes.
default backward;
} • In this generic case we are using the backward method for time
gradSchemes
discretization (ddtSchemes).
{
default Gauss linear;
• This scheme is second order accurate but oscillatory.
grad(p) Gauss linear;
• The parameters can be changed on-the-fly.
}
divSchemes
{
default none;
div(phi,U) Gauss linear;
}
laplacianSchemes
{
default Gauss linear orthogonal;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default orthogonal;
}
666
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
startFrom latestTime; • The controlDict dictionary contains runtime simulation
controls, such as, start time, end time, time step, saving
startTime 0;
frequency and so on. Most of the entries are self-explanatory.
stopAt endTime;
• This generic case starts from time 0 (startTime), and it will run
endTime 10; up to 10 seconds (endTime).
deltaT 0.0001; • It will write the solution every 0.1 seconds (writeInterval) of
simulation time (runTime).
writeControl runTime;
• The time step of the simulation is 0.0001 seconds (deltaT).
writeInterval 0.1;
• It will keep all the solution directories (purgeWrite).
purgeWrite 0;
• It will save the solution in ascii format (writeFormat) with a
writeFormat ascii; precision of 8 digits (writePrecision).
writePrecision 8; • And as the option runTimeModifiable is on (yes), we can
modify all these entries while we are running the simulation.
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable yes;
adjustTimeStep yes;
maxCo 2.0;
maxDeltaT 0.001;
667
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
startFrom latestTime; • In this generic case, the solver supports adjustable time-step
(adjustTimeStep).
startTime 0;
• The option adjustTimeStep will automatically adjust the time
stopAt endTime;
step to achieve the maximum desired courant number (maxCo)
endTime 10; or time-step size (maxDeltaT).
deltaT 0.0001; • When any of these conditions is reached, the solver will stop
scaling the time-step size.
writeControl runTime;
• Remember, the first time-step of the simulation is done using the
writeInterval 0.1; value defined with the keyword deltaT and then it is
purgeWrite 0;
automatically scaled (up or down), to achieve the desired
maximum values (maxCo and maxDeltaT).
writeFormat ascii;
• It is recommended to start the simulation with a low time-step in
writePrecision 8; order to let the solver scale-up the time-step size.
writeCompression off; • The feature adjustTimeStep is only present in the PIMPLE
family solvers, but it can be added to any solver by modifying
timeFormat general;
the source code.
timePrecision 6;
• If you are planning to use large time steps (CFL much higher
runTimeModifiable yes; than 1), it is recommended to do at least 3 correctors steps
(nCorrectors) in PISO/PIMPLE loop.
adjustTimeStep yes;
maxCo 2.0;
maxDeltaT 0.001;
668
Unsteady and steady simulations
How to run unsteady simulations in OpenFOAM®?
solvers • The fvSolution dictionary contains the instructions of how to
{
p
solve each discretized linear equation system.
{ • As for the controlDict and fvSchemes dictionaries, the
solver PCG;
preconditioner DIC; parameters can be changed on-the-fly.
tolerance 1e-06;
relTol 0; • To set these parameters, follow the guidelines given in the
} previous section.
pFinal
• Depending on the solver you are using, you will need to define
{ the sub-dictionary PISO or PIMPLE.
$p;
• Setting the keyword nOuterCorrectors to 1 in PIMPLE solvers
relTol 0;
} is equivalent to running using the PISO method.
• To gain more stability, especially when using large time-steps,
“U.*”
{
you can use more outer correctors (nOuterCorrectors).
solver smoothSolver;
• If you are using large time steps (CFL much higher than 1), it is
smoother symGaussSeidel;
tolerance 1e-08; recommended to do at least 3 correctors steps (nCorrectors) in
relTol 0; PISO/PIMPLE loop.
}
} • Remember, in both PISO and PIMPLE method you need to do
PIMPLE at least one correction (nCorrectors).
{
nOuterCorrectors 1; • Adding corrections increase the computational cost
nCorrectors 2;
nNonOrthogonalCorrectors 1;
(nOuterCorrectors and nCorrectors).
}
669
Unsteady and steady simulations
How to choose the time-step in unsteady simulations and monitor the solution
• Remember, when running unsteady simulations the time-step must be chosen in such a way
that it resolves the time-dependent features and maintains solver stability.
670
Unsteady and steady simulations
Monitoring unsteady simulations
• When running unsteady simulations, it is highly advisable to monitor a quantity of interest.
• The quantity of interest can fluctuate in time, this is an indication of unsteadiness.
671
Unsteady and steady simulations
What about steady simulations?
• First of all, steady simulations are a big simplification of reality.
• Steady simulations is a trick used by CFDers to get fast outcomes with results that might be
even more questionable.
• 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
governing equations.
• We perform time averaging when dealing with stationary turbulence (RANS modeling)
• The advantage of steady simulations is that they require low computational resources, give fast
outputs, and are easier to post-process and analyze.
• In OpenFOAM® is possible to run steady simulation.
• To do so, you need to use the appropriate solver and use the right discretization scheme.
• As you are not solving the temporal derivative, you do not need to set the time step. However,
you need to tell OpenFOAM® how many iterations you would like to run.
• You can also set the residual controls (residualControl), in the fvSolution dictionary file.
You set the residualControl in the SIMPLE sub-dictionary.
• If you do not set the residual controls, OpenFOAM® will run until reaching the maximum
number of iterations (endTime).
672
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
• In the controlDict dictionary you need to set runtime parameters and
general instructions on how to run the case (such as the number of iterations
to run). You also set the saving frequency.
• In the fvSchemes dictionary you need to set the temporal discretization
scheme, for steady simulations it must be steadyState.
• In the fvSolution dictionary you need to set the linear solvers, under-
relaxation factors and residual controls.
• Also, you will need to set the number of corrections of the velocity-pressure
coupling method used (e.g. SIMPLE), this is done in the fvSolution
dictionary.
• Additionally, you may set functionObjects in the controlDict dictionary.
The functionObjects are used to do sampling, probing and co-processing
while the simulation is running.
673
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
• You also need to set the under-relaxation factors (URF).
• The under-relaxation factors control the change of the variable .
• Under-relaxation is a feature typical of steady solvers using the SIMPLE family of methods.
• These are the URF commonly used with SIMPLE and SIMPLEC (industry standard),
SIMPLE SIMPLEC
• According to the physics involved you will need to add more under-relaxation factors.
• Finding the right URF involved experience and some trial and error.
• Selecting the URF it is kind of equivalent to selecting the right time step
• The URF are bounded between 0 and 1.
• If you set the URF close to one you increase the convergence rate but loose solution stability.
• On the other hand, if you set the URF close to zero you gain stability but reduce convergence rate. 674
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
ddtSchemes • The fvSchemes dictionary contains the information related to
{ time discretization and spatial discretization schemes.
default steadyState;
} • In this generic case and as we are interested in using a steady
gradSchemes
solver, we are using the steadyState method for time
{ discretization (ddtSchemes).
default Gauss linear;
grad(p) Gauss linear; • It is not a good idea to switch between steady and unsteady
} schemes on-the-fly.
divSchemes • For steady state cases, the bounded form can be applied to the
{ divSchemes, in this case, div(phi,U) bounded Gauss linear.
default none;
div(phi,U) bounded Gauss linear; • This adds a linearized, implicit source contribution to the
}
transport equation of the form,
laplacianSchemes
{
default Gauss linear orthogonal;
}
interpolationSchemes
{
default linear; • This term removes a component proportional to the continuity
}
error. This acts as a convergence aid to tend towards a bounded
snGradSchemes solution as the calculation proceeds.
{
default orthogonal; • At convergence, this term becomes zero and does not
} contribute to the final solution.
675
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
startFrom latestTime; • The controlDict dictionary contains runtime simulation
controls, such as, start time, end time, time step, saving
startTime 0;
frequency and so on. Most of the entries are self-explanatory.
stopAt endTime;
• As we are doing a steady simulation, let us talk about iterations
endTime 10000; instead of time (seconds).
deltaT 1; • This generic case starts from iteration 0 (startTime), and it will
run up to 10000 iterations (endTime).
writeControl runTime;
• It will write the solution every 100 iterations (writeInterval) of
writeInterval 100; simulation time (runTime).
purgeWrite 10; • It will advance the solution one iteration at a time (deltaT).
writeFormat ascii; • It will keep the last 10 saved solutions (purgeWrite).
writePrecision 8; • It will save the solution in ascii format (writeFormat) with a
precision of 8 digits (writePrecision).
writeCompression off;
• And as the option runTimeModifiable is on (true), we can
timeFormat general;
modify all these entries while we are running the simulation.
timePrecision 6;
runTimeModifiable yes;
676
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
solvers • The fvSolution dictionary contains the instructions of how to
{
p
solve each discretized linear equation system.
{ • As for the controlDict and fvSchemes dictionaries, the
solver PCG;
preconditioner DIC; parameters can be changed on-the-fly.
tolerance 1e-06;
relTol 0; • To set these parameters, follow the guidelines given in the
} previous section.
U
• Increasing the number of nNonOrthogonalCorrectors
{ corrections will add more stability but at a higher computational
solver smoothSolver; cost.
smoother symGaussSeidel;
tolerance 1e-08; • Remember, nNonOrthogonalCorrectors is used to improve
relTol 0; the gradient computation due to mesh quality.
}
} • The SIMPLE sub-dictionary also contains convergence controls
based on residuals of fields. The controls are specified in the
SIMPLE
{
residualControls sub-dictionary.
nNonOrthogonalCorrectors 2;
• The user needs to specify a tolerance for one or more solved
residualControl fields and when the residual for every field falls below the
{ corresponding residual, the simulation terminates.
p 1e-4;
U 1e-4; • If you do not set the residualControls, the solver will iterate
} until reaching the maximum number of iterations set in the
}
controlDict dictionary.
677
Unsteady and steady simulations
How to run steady simulations in OpenFOAM®?
• The fvSolution dictionary also contains the
relaxationFactors relaxationFactors sub-dictionary.
{
fields • The relaxationFactors sub-dictionary which controls under-
{ relaxation, is a technique used for improving stability when using
p 0.3;
}
steady solvers.
equations
{
• Under-relaxation works by limiting the amount which a variable
U 0.7; changes from one iteration to the next, either by modifying the
} solution matrix and source prior to solving for a field (equations
}
keyword) or by modifying the field directly (fields keyword).
• Under-relaxing the equations is also known as implicit under-
relaxation. Whereas, under-relaxing the fields is also known as
explicit under-relaxation.
• An optimum choice of under-relaxation factors is one that is
small enough to ensure stable computation but large enough to
move the iterative process forward quickly.
• In this case we are using the industry standard URF.
• Remember, URF are problem dependent.
• If you do not define URF, the solver will not under-relax.
678
Unsteady and steady simulations
Steady simulations vs. Unsteady simulations
• Steady simulations require less computational power than unsteady simulations.
• They are also much faster than unsteady simulations.
• But sometimes they do not converge to the right solution.
• They are easier to post-process and analyze (you just need to take a look at the last saved
solution).
• You can use the solution of an unconverged steady simulation as initial conditions for an
unsteady simulation.
• Remember, steady simulations are not time accurate. Therefore is not a good idea to compute
a dominant frequency using steady simulations, e.g., vortex shedding frequency.
679
Roadmap
680
Understanding residuals
• Before talking about residuals, let us clarify something.
• When we talk about iterations in unsteady simulations, we are talking about the time-
step or outer-iterations.
681
Understanding residuals
• This is a typical residual plot for an unsteady simulation. • This is a typical residual plot for a steady simulation.
• Ideally, the solution should converge at every time-step (final • In this case, the initial residuals are falling below the
residuals tolerance). convergence criterion (monolithic convergence), hence we
• If the solution is not converging, that is, the residuals are not have reached a steady-state.
reaching the predefined final residual tolerance, try to reduce
• In the solver does not reach the convergence criteria or the
the time-step size.
residuals get stalled, it does not mean that the solution is
• The first time-steps the solution might not converge, this is diverging, it is just an indication of unsteadiness and it
acceptable. might be better to run using an unsteady solver.
• Also, you might need to use a smaller time-step during the
• In comparison to unsteady solvers, steady solvers require
first iterations to maintain solver stability.
less iterations to arrive to a converge solution, if they arrive.
• You can also increase the number of maximum inner
iterations.
• If the initial residuals fall bellow the convergence criterion, you
might say that you have arrived to a steady solution (the
exception rather than the rule).
682
Understanding residuals
• Remember, residuals are not a direct indication that you are converging to the right solution.
• It is better to monitor a quantity of interest (QOI).
• And by the way, you should get physically realistic values.
• In this case, if you monitor the residuals you might get the impression that the simulation is
diverging.
• Instead, if you monitor a QOI you will realize that there is an initial transient (long one by the
way), then the onset of an instability, and then a periodic behavior of the phenomenon.
• During the window where the behavior of the QOI is periodic, is where should access the
convergence of the solution and compute the unsteady statistics.
• To monitor the stability, you can check the minimum and maximum values of the field variables.
• If you have bounded quantities, check that you do not have over-shoots or under-shoots.
Residuals QOI
683
Understanding residuals
• This is the output of the residuals for • This is the output of the residuals for
all field variables of an unsteady case. all field variables of a steady case.
• The jumps are due to the changes in
tolerance introduced while running
the simulation.
• As you can see, the residuals are
falling in a monolithic way.
684
Understanding residuals
• This is the output of the aerodynamic • This is the output of the aerodynamic
coefficients for an unsteady case. coefficients for a steady case.
685
Roadmap
686
Boundary conditions and initial conditions
On the initial boundary value problem (IBVP)
• First of all, when we use a CFD solver to find the approximate solution of the
governing equations, we are solving an Initial Boundary Value Problem
(IBVP).
• In an IBVP, we need to impose appropriate boundary conditions and initial
conditions.
• No need to say that the boundary conditions and initial conditions need to be
physically realistic.
• Boundary conditions are a required component of the numerical method,
they tell the solver what is going on at the boundaries of the domain.
• You can think of boundary conditions as source terms.
• Initial conditions are also a required component of the numerical method,
they define the initial state of the problem.
687
Boundary conditions and initial conditions
A few words about boundary conditions
• Boundary conditions (BC) can be divided into three fundamental mathematical types:
• Dirichlet boundary conditions: when we use this BC, we prescribe the value of a variable at
the boundary.
• Neumann boundary conditions: when we use this BC, we prescribe the gradient normal to the
boundary.
• Robin Boundary conditions: this BC is a mixed of Dirichlet boundary conditions and Neumann
boundary
• You can use any of these three boundary conditions in OpenFOAM®.
• During this discussion, the semantics is not important, that depends of how you want to call the BCs
or how they are named in the solver, i.e., in, inlet, inflow, velocity inlet, incoming flow and so on.
• Defining boundary conditions involves:
• Finding the location of the boundary condition in the domain.
• Determining the boundary condition type.
• Giving the required physical information.
• The choice of the boundary conditions depend on:
• Geometrical considerations.
• Physics involved.
• Information available at the boundary condition location.
• Numerical considerations.
• And most important, you need to understand the physics involved.
688
Boundary conditions and initial conditions
A few words about boundary conditions
• To define boundary conditions you need to know the location of the boundaries (where they are
in your mesh).
• You also need to supply the information at the boundaries.
• Last but not least important, you must know the physics involved.
689
Boundary conditions and initial conditions
A few words about initial conditions
• Initial conditions (IC) can be divided into two groups:
• Uniform initial conditions.
• Non-uniform initial conditions.
• For non-uniform IC, the value used can be obtained from:
691
Boundary conditions and initial conditions
• Inlets and outlets boundary conditions:
• Inlets are for regions where inflow is expected; however, inlets might support
outflow when a velocity profile is specified.
• Pressure boundary conditions do not allow outflow at the inlets.
• Velocity specified inlets are intended for incompressible flows.
• Pressure and mass flow inlets are suitable for compressible and incompressible
flows.
• Same concepts apply to outlets, which are regions where outflow is expected.
692
Boundary conditions and initial conditions
• Zero gradient and backflow boundary conditions:
• Zero gradient boundary conditions extrapolates the values from the domain.
They require no information.
• Zero gradient boundary conditions can be used at inlets, outlets, and walls.
• Backflow boundary conditions provide a generic outflow/inflow condition, with
specified inflow/outflow for the case of backflow.
• In the case of a backflow outlet, when the flux is positive (out of domain) it
applies a Neumann boundary condition (zero gradient), and when the flux is
negative (into of domain), it applies a Dirichlet boundary condition (fixed value).
• Same concept applies to backflow inlets.
693
Boundary conditions and initial conditions
• On the outlet pressure boundary condition
• Some combinations of boundary conditions are very stable and some are less
reliable.
• And some configurations are unreliable.
• Inlet velocity at the inlet and pressure zero gradient at the outlet. This
combination should be avoided because the static pressure level is not
fixed.
• Qualitatively speaking, the results are very different.
• This simulation will eventually crash.
BCs 1. Inlet velocity and fixed outlet pressure BCs 2. Inlet velocity and zero gradient outlet pressure
www.wolfdynamics.com/wiki/BC/aniBC1.gif www.wolfdynamics.com/wiki/BC/aniBC2.gif
694
Boundary conditions and initial conditions
• On the outlet pressure boundary condition
• If you only rely on a QOI and the residuals, you will not see any major difference
between the two cases with different outlet pressure boundary condition.
• This is very misleading.
• However, when you visualize the solution you will realize that something is
wrong. This is a case where pretty pictures can be used to troubleshoot the
solution.
• Quantitative speaking, the results are very similar.
• However, this simulation will eventually crash.
Residual plot for pressure Quantity of interest – Force coefficient on the body
695
Boundary conditions and initial conditions
• Symmetry boundary conditions:
• Symmetry boundary conditions are a big simplification of the problem. However,
they help to reduce mesh cell count.
• Have in mind that symmetry boundary conditions only apply to planar faces.
• To use symmetry boundary conditions, both the geometry and the flow field must
be symmetric.
• Mathematically speaking, setting a symmetry boundary condition is equivalent
to: zero normal velocity at the symmetry plane, and zero normal gradients of all
variables at the symmetry plane.
• Physically speaking, they are equivalent to slip walls.
696
Boundary conditions and initial conditions
• Location of the outlet boundary condition:
• Place outlet boundary conditions as far as possible from recirculation zones or
backflow conditions, by doing this you increase the stability.
• Remember, backflow conditions requires special treatment.
Far enough so the flow can be
Possible backflow Might be OK
considered fully developed
697
Boundary conditions and initial conditions
• Domain dimensions (when the dimensions are not known):
• If you do not have any constrain in the domain dimensions, you can use as a general guideline the
dimensions illustrated in the figure, 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
are, you should consider increasing the domain dimensions.
698
Boundary conditions and initial conditions
A few considerations and guidelines
• Boundary conditions and initial conditions need to be physically realistic.
• Poorly defined boundary conditions can have a significant impact on your solution.
• Initial conditions are as important as the boundary conditions.
• A good initial condition can improve the stability and convergence rate.
• On the other hand, unphysical initial conditions can slow down the convergence rate or can cause divergence.
• You need to define boundary conditions and initials conditions for every single variable you are solving.
• Setting the right boundary conditions is extremely important, but you need to understand the physics.
• You need to understand the physics in order to set the right boundary conditions.
• Do not force the flow at the outlet, use a zero normal gradient for all flow variables except pressure. The solver
extrapolates the required information from the interior.
• Be careful with backward flow at the outlets (flow coming back to the domain) and backward flow at inlets
(reflection waves), they required special treatment.
• If possible, select inflow and outflow boundary conditions such that the flow either goes in or out normal to the
boundaries.
• At outlets, use zero gradient boundary conditions only with incompressible flows and when you are sure that the
flow is fully developed.
• Outlets that discharge to the atmosphere can use a static pressure boundary condition. This is interpreted as
the static pressure of the environment into which the flow exhausts.
699
Boundary conditions and initial conditions
A few considerations and guidelines
• Inlets that take flow into the domain from the atmosphere can use a total pressure boundary condition (e.g.
open window).
• Mass flow inlets produce a uniform velocity profile at the inlet.
• Pressure specified boundary conditions allow a natural velocity profile to develop.
• The required values of the boundary conditions and initial conditions depend on the equations you are solving
and physical models used, e.g.,
• For incompressible and laminar flows you will need to set only the velocity and pressure.
• If you are solving a turbulent compressible flow you will need to set velocity, pressure, temperature and
the turbulent variables.
• For multiphase flows you will need to set the primitives variables for each phase. You will also need to
initialize the phases.
• If you are doing turbulent combustion or chemical reactions, you will need to define the species, reactions
and turbulent variables.
• Minimize grid skewness, non-orthogonality, growth rate, and aspect ratio near the boundaries. You do not want
to introduce diffusion errors early in the simulation, especially close to the inlets.
• Try to avoid large gradients in the direction normal to the boundaries and near inlets and outlets. That is to say,
put your boundaries far away from where things are happening.
700
Boundary conditions and initial conditions
• OpenFOAM® distinguish between base type boundary conditions and numerical type
boundary conditions.
• Base type boundary conditions are based on • Numerical type boundary condition assigns the
geometry information (surface patches) or on inter- value to the field variables in the given surface
processor communication link (halo boundaries). patch.
• Base type boundary conditions are defined in the • Numerical 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 numerical type boundary
you generate or convert the mesh.
conditions, we are referring to Dirichlet, Neumann
• When you convert a mesh to OpenFOAM® format, or 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
mesh. • Remember, if you forget to define a numerical
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
where and what is the error. • Also, if you misspelled something OpenFOAM® will
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
701
Boundary conditions and initial conditions
• The following base type and numerical type boundary conditions are
constrained or paired.
• That is, the type needs to be same in the boundary dictionary and field
variables dictionaries (e.g. 0/U, 0/p, 0/T, 0/k, 0/omega).
symmetry symmetry
symmetryPlane symmetryPlane
empty empty
wedge wedge
cyclic cyclic
cyclicAMI cyclicAMI
processor processor
702
Boundary conditions and initial conditions
• The base type patch can be any of the boundary conditions available in
OpenFOAM®.
• Mathematically speaking; they can be Dirichlet, Neumann or Robin
boundary conditions.
fixedValue
zeroGradient
inletOutlet
slip
patch
totalPressure
supersonicFreeStream
and so on …
Refer to the doxygen documentation for a list of all numerical
boundary conditions available.
703
Boundary conditions and initial conditions
• The wall base type boundary condition is defined as follows:
type fixedValue;
wall zeroGradient
value uniform (0 0 0);
• This boundary condition is not contained in the patch base type boundary conditions
group, because specialize modeling options can be used on this boundary condition.
• An example is turbulence modeling, where turbulence can be generated or
dissipated at the walls.
704
Boundary conditions and initial conditions
• To deal with backflow at outlets, you can use the following boundary condition:
type inletOutlet;
type fixedValue;
patch inletValue uniform (0 0 0);
value uniform 0;
value uniform (0 0 0);
705
Boundary conditions and initial conditions
• Typical boundary conditions are as follows (external aerodynamics),
zeroGradient or fixedValue 0 or
epsilon epsilonWallFunction
a small number
omegaWallFunction or
omega omegaWallFunction
fixedValue with a big number
• The wall boundary conditions for the turbulence models (wall functions), are
located in the following directory:
• $WM_PROJECT_DIR/src/TurbulenceModels/turbulenceModels
/derivedFvPatchFields/wallFunctions
fixedWalls
startFace 780; fixedWalls
}
frontAndBack
{
type empty;
inGroups 1(empty);
nFaces 800;
startFace 840;
} frontAndBack
)
fixedWalls
710
Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary
3
( Name and type of the surface patches
movingWall
{
type patch; • The name and type of the patch is given by
inGroups 1(patch);
nFaces 20; the user.
startFace 760;
} • You can change the name if you do not like it.
Do not use strange symbols or white spaces.
fixedWalls
{ • You can also change the base type. For
type wall;
inGroups 1(wall); instance, you can change the type of the
nFaces 60; patch movingWall from patch to wall.
startFace 780;
} • When converting the mesh from a third-party
frontAndBack
format, OpenFOAM® will try to recover the
{ information from the original format. But it
type empty; might happen that it does not recognize the
inGroups 1(empty);
nFaces 800; base type and name of the original format. If
startFace 840; that is your case, you will need to modify the
}
)
file manually.
711
Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary
3
( inGroups keyword
movingWall
{
type patch; • This is optional.
inGroups 1(patch);
nFaces 20; • You can erase this information safely.
startFace 760;
} • It is used to group patches during visualization
fixedWalls in ParaView/paraFoam. If you open this mesh
{ in paraFoam you will see that there are two
type wall;
inGroups 1(wall); groups, namely: wall and empty.
nFaces 60;
startFace 780; • As usual, you can change the name.
}
• If you want to put a surface patch in two
frontAndBack groups, you can proceed as follows:
{
type empty; 2(wall wall1)
inGroups 1(empty);
nFaces 800; In this case the surface patch belongs to the
startFace 840;
} group wall (which can have another patch)
) and wall1
712
Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary
3
(
movingWall
{
type patch;
inGroups 1(patch);
nFaces 20; nFaces and startFace keywords
startFace 760;
}
• Unless you know what you are
fixedWalls
{
doing, you do not need to change
type wall; this information.
inGroups 1(wall);
nFaces 60; • Basically, this is telling you the
startFace 780; starting face and ending face of the
}
patch.
frontAndBack
{ • This is created automatically when
type empty; generating the mesh or converting
inGroups 1(empty);
nFaces 800;
the mesh.
startFace 840;
}
)
713
Boundary conditions and initial conditions
The constant/polyMesh/boundary dictionary
3
Remember
(
movingWall
{ Boundary patches that are not recognize or
type patch; assigned to a patch are grouped automatically in
inGroups 1(patch);
nFaces 20;
a default group named defaultFaces of type
startFace 760; empty.
}
For instance, if a boundary patch does not have a
fixedWalls type and a name, they will be grouped as follows:
{
type wall;
inGroups 1(wall);
nFaces 60; defaultFaces
startFace 780; {
} type empty;
inGroups 1(empty);
frontAndBack nFaces 800;
{ startFace 840;
type empty; }
inGroups 1(empty);
nFaces 800;
startFace 840;
}
And as usual, you can manually change the name
) and type.
714
Boundary conditions and initial conditions
The 0/U dictionary
• For a generic case, the numerical type BC are assigned as follows (U),
movingWall
dimensions [0 1 -1 0 0 0 0]; type fixedValue;
value uniform (1 0 0);
internalField uniform (0 0 0);
boundaryField frontAndBack
{ type empty;
type fixedValue;
type fixedValue;
fixedWalls
type fixedValue;
fixedWalls
{
fixedWalls
type fixedValue;
value uniform (0 0 0);
}
frontAndBack
{ frontAndBack
type empty;
type empty;
}
}
fixedWalls
type fixedValue;
value uniform (0 0 0);
715
Boundary conditions and initial conditions
The 0/p dictionary
• For a generic case, the numerical type BC are assigned as follows (p),
boundaryField frontAndBack
{ type empty;
type zeroGradient;
movingWall
{
type zeroGradient;
}
type zeroGradient;
fixedWalls
fixedWalls
{
type zeroGradient; fixedWalls
}
frontAndBack
{
type empty;
} frontAndBack
}
type empty;
fixedWalls
type zeroGradient;
716
Roadmap
717
Numerical playground
Merry-go-round:
Pure convection of a passive scalar in a vector
field – One dimensional tube.
718
Numerical playground
• This is a visual and mental exercise only.
• You will find this case in the directory
$PTOFC/101FVM/pureConvection
• In this directory, you will also find the README.FIRST file with
the instructions of how to run the case.
719
Numerical playground
Pure convection of a scalar in a vector field – One dimensional tube.
U = zeroGradient
T = zeroGradient
U = (1 0 0) U = zeroGradient
T=1 T = zeroGradient
(0 0 0) (1 0 0)
U = zeroGradient
T = zeroGradient
Initial conditions
U = (1 0 0)
T=0
720
Numerical playground
• This problem has an exact solution in the form of a traveling wave.
• We will use this case to study the different discretization schemes implemented in
OpenFOAM®.
• In the figure, we show the solution for time = 0.5 s
www.wolfdynamics.com/wiki/pureconvection/xani1.gif
www.wolfdynamics.com/wiki/pureconvection/xani2.gif
721
Numerical playground
Comparison of different spatial discretization schemes. Comparison of different spatial discretization schemes.
Euler in time – 100 cells – CFL = 0.1 Euler in time – 100 cells – CFL = 0.1
Linear limiter functions on the Sweby diagram. Non-linear limiter functions on the Sweby diagram.
722
Numerical playground
Comparison of different gradient limiters. Comparison of different gradient limiters.
Linear upwind in space – Euler in time – 100 cells – Linear upwind in space – Euler in time – 100 cells –
CFL 0.1 CFL 0.1
723
Numerical playground
Comparison of different temporal discretization Comparison of Crank Nicolson blending factor using
schemes and gradient limiters. cellLimited leastSquares 0.5 gradient limiter.
Linear upwind in space – 100 cells – CFL 0.1 Linear upwind in space – 100 cells – CFL 0.1
724
Numerical playground
Comparison of different time-step size (different CFL Comparison of different mesh sizes.
number). Linear upwind in space – Euler in time
Linear upwind in space – Euler in time – 100 cells
725
Numerical playground
• This case was for your eyes and brain only, but we encourage you to reproduce all
the previous results,
• Use all the time discretization schemes.
• Use all the spatial discretization schemes.
• Use all the gradient discretization schemes.
• Use gradient limiters.
• Use different mesh resolution.
• Use different time-steps.
726
Numerical playground
Exercises
• Which one of the following schemes is useless:
• upwind
• downwind
• linear
• Compare the solution obtained with the following schemes:
• upwind
• linearUpwind
• MUSCL
• QUICK
• cubic
• UMIST
Are all of them bounded? Are they second order accurate?
• Use the linearUpwind method with Gauss linear and leastSquares for gradient computations, which method
is more accurate?
• Imagine that you are using the linearUpwind method with no gradient limiters. How will you stabilize the
solution if it becomes unbounded?
• When using gradient limiters, what is clipping?
• Use the vanLeer method with a CFL number of 0.1 and a CFL number of 0.9, did both solutions converge?
Are both solutions bounded?
727
Numerical playground
Exercises
• By the way, the solver scalarTransportFoam does not report the CFL number on the screen. How will you
compute the CFL number in this case?
(Hint: you can take a look at the post-processing slides or the utilities directory)
• Which one is more diffusive, spatial discretization or time discretization?
• Are all time discretization schemes bounded?
• If you are using the Crank-Nicolson scheme, how will you avoid oscillations?
• Does the solution improve if you reduce the time-step?
• Use the upwind scheme and a really fine mesh. Do the accuracy of the solution improve?
• From a numerical point of view, what is the Peclet number? Can it be compare to the Reynolds number?
• If the Peclet number is more than 2, what will happen with your solution if you were using a linear scheme?
(Hint: to change the Peclet number you will need to change the diffusion coefficient)
• Pure convection problems have analytical solutions. You are asked to design your own tutorial with an
analytical solution in 2D or 3D.
• Try to break the solver using a time step less than 0.005 seconds. You are allow to modify the original mesh
and use any combination of discretization schemes.
728
Numerical playground
Slide:
2D Laplace equation in a square domain.
729
Numerical playground
• This is a visual and mental exercise only.
• You will find this case in the directory
$PTOFC/101FVM/laplace
• In this directory, you will also find the README.FIRST file with
the instructions of how to run the case.
730
Numerical playground
2D Laplace equation in a square domain
731
Numerical playground
2D Laplace equation in a square domain
• This case consist of one domain and three different element types.
Domain
• We will study the influence of the element type on the gradients computation.
• We will study the influence of the gradSchemes method and laplacianSchemes
method on the solution.
733
Numerical playground
2D Laplace equation in a square domain
A B gradSchemes:
Gauss linear
laplacianSchemes:
Gauss linear orthogonal
A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh
T field
734
Numerical playground
2D Laplace equation in a square domain
A B gradSchemes:
Gauss linear
laplacianSchemes:
Gauss linear orthogonal
A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh
field
735
Numerical playground
2D Laplace equation in a square domain
A B gradSchemes:
Gauss linear
laplacianSchemes:
Gauss linear limited 1
A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh
field
736
Numerical playground
2D Laplace equation in a square domain
A B gradSchemes:
Gauss leastSquares
laplacianSchemes:
Gauss linear orthogonal
A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh
field
737
Numerical playground
2D Laplace equation in a square domain
A B gradSchemes:
Gauss leastSquares
laplacianSchemes:
Gauss linear limited 1
A. Hexahedral mesh
B. Triangular mesh
C. Polyhedral mesh
field
738
Numerical playground
• This case was for your eyes and brain only, but we encourage you to reproduce all
the previous results.
• In the subdirectory c1 you will find the hexahedral mesh, in the subdirectory c2 you
will find the triangular mesh, and in the subdirectory c3 you will find the polyhedral
mesh.
• Use the script runallcases.sh to run all the cases automatically.
• When launching paraFoam it will give you a warning, accept the default option (yes).
• In paraFoam, go to the File menu and select Load State. Load the state located
in the directory paraview (state1.pvsm).
• In the window that pops out, give the location of the *.foam files inside each
subdirectory (c1/c1.foam, c2/c2.foam, and c3/c3.foam).
• The file state1.pvsm will load a preconfigured state with all the solutions.
• If you are interested in running the cases individually, enter the subdirectory
and follow the instructions in the README.FIRST file.
739
Numerical playground
Exercises
• Run the case using all gradient discretization schemes available. Which scheme gives the best results?
• According to the previous results, which element type is the best one? Do you think that the choice of the
element type is problem dependent (e.g., direction of the flow)?
• Use the leastSquares method for gradient discretization, and the corrected and uncorrected method for
Laplacian discretization. Do you get the same results in all the meshes? How can you improve the results?
(Hint: look at the corrections)
• Does it make sense to do more non-orthogonal corrections using the uncorrected method?
• Run a case only 1 iteration. Do you get a converged solution? Is there a difference between 1 and 100
iterations? Compare the solutions.
• Use a different interpolation method for the diffusion coefficient. Do you get the same results?
• Try to break the solver (this is a difficult task in this case). You are allow to modify the original mesh and use
any combination of discretization schemes.
740
Numerical playground
Swing:
Flow in a lid-driven square cavity – Re = 100
Effect of grading and non-orthogonality on the
accuracy of the solution
741
Numerical playground
Flow in a lid-driven square cavity – Re = 100
Non-orthogonal mesh vs. orthogonal mesh
• We will use this case to learn how to adjust the numerical schemes according to
mesh non-orthogonality and grading.
742
Numerical playground
LaplacianSchemes orthogonal – Non-orthogonal corrections disabled
Y centerline
High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 743
Numerical playground
LaplacianSchemes orthogonal – Non-orthogonal corrections enabled
Y centerline
High-Re Solutions for incompressible flow using the navier-stokes equations and a multigrid method
U. Ghia, K. N. Ghia, C. T. Shin.
Journal of computational physics, 48, 387-411 (1982) 744
Numerical playground
How to adjust the numerical method to deal with non-orthogonality
17 ddtSchemes • In the dictionary fvSchemes we can enable non-
18 {
19 default backward; orthogonal corrections.
20 }
21 • Non-orthogonal corrections are chosen using the
22 gradSchemes
23 { keywords laplacianSchemes and snGradSchemes.
24 default Gauss linear;
25 //default cellMDLimited Gauss linear 1; • These are the laplacianSchemes and
26
27 grad(p) Gauss linear; snGradSchemes schemes that you will use most of the
28 }
29
times:
30 divSchemes
31 { • orthogonal: second order accurate, bounded on
32 default none; perfect meshes, without non-orthogonal
33 //div(phi,U) Gauss linearUpwind default;
34 div(phi,U) Gauss linear; corrections.
35 }
36 • corrected: second order accurate, bounded
37 laplacianSchemes
38 { depending on the quality of the mesh, with non-
39 default Gauss linear orthogonal;
40 //default Gauss linear limited 1;
orthogonal corrections.
41 }
42 • limited : second order accurate, bounded
43 interpolationSchemes depending on the quality of the mesh, with non-
44 {
45 default linear; orthogonal corrections.
46 }
47 • uncorrected: second order accurate, without
48 snGradSchemes
49 { non-orthogonal corrections. Stable but more
50 default orthogonal;
51 //default limited 1;
diffusive than limited and corrected.
52 }
745
Numerical playground
How to adjust the numerical method to deal with non-orthogonality
17 solvers • Additionally, in the dictionary fvSolution we need to
18 {
19 p define the number of PISO corrections (nCorrectors) and
20 { non-orthogonal corrections (nNonOrthogonalCorrectors).
21 solver PCG;
22 preconditioner DIC;
23 tolerance 1e-06; • You need to do at least one PISO correction. Increasing the
24 relTol 0; number of PISO correctors will improve the stability and
38 }
39 accuracy of the solution at a higher computational cost.
40 pFinal
41
42
{
$p;
• For orthogonal meshes, 1 PISO correction is ok. But as
43 relTol 0; most of the time you will deal with non-orthogonal meshes,
44 }
45 doing 2 PISO corrections is a good choice.
46 U
47 { • If you are using a method with non-orthogonal corrections
48 solver smoothSolver;
49 smoother symGaussSeidel; (corrected or limited 1-0.5), you need to define the number
50 tolerance 1e-08; of non-orthogonal corrections (nNonOrthogonalCorrectors).
51 relTol 0;
52 }
53 } • If you use 0 nNonOrthogonalCorrectors, you are
54
55 PISO
computing the initial approximation using central differences
56 { (accurate but unstable), with no explicit correction.
57 nCorrectors 1;
58
59
nNonOrthogonalCorrectors 0;
pRefCell 0;
• To take into account the non-orthogonality of the mesh, you
60 pRefValue 0; will need to increase the number of corrections (you get
61 }
better approximations using the previous correction).
• Usually 2 nNonOrthogonalCorrectors is ok.
746
Numerical playground
• We will now illustrate a few of the discretization schemes available in
OpenFOAM® using a model case.
• We will use the lid-driven square cavity case to study the effect of grading
and non-orthogonality on the accuracy of the solution
• This case is located in the directory:
$PTOFC/101FVM/nonorthoCavity/
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
747
Numerical playground
What are we going to do?
• This is the same case as the one we used during the first tutorial session.
• The only difference is that we have modified the mesh a little bit in order to add grading and non-orthogonality.
• After generating the mesh, we will use the utility checkMesh to control the quality of the mesh. Is it a good
mesh?
• We will use this case to learn how to adjust the numerical schemes according to mesh non-orthogonality and
grading.
• After finding the numerical solution we will do some sampling and plotting.
1. $> foamCleanTutorials
2. $> blockMesh
3. $> checkMesh
4. $> icoFoam | log
5. $> postProcess -func sampleDict -latestTime
6. $> gnuplot gnuplot/gnuplot_script
7. $> paraFoam
748
Numerical playground
To run the case, follow these steps
• First run the case using the original dictionaries. Did it crash right?
• Now change the laplacianSchemes and snGradSchemes to limited 1. It crashed again but
this time it ran a few more time-steps, right?
• Now increase the number of nNonOrthogonalCorrectors to 2. It crashed again but it is running
more time-steps, right?
• Now increase the number of PISO corrections to 2 (nCorrectors). Did it run?
• Basically we enabled non-orthogonal corrections, we computed better approximations of the
gradients, and we increased the number of PISO corrections to get better predictions of the field
variables (U and p).
• Now set the number of nNonOrthogonalCorrectors to 0. Did it crash right? This is telling us
that the mesh is sensitive to the gradients.
• Now change the laplacianSchemes and snGradSchemes to limited 0 (uncorrected). In this
case we are not using non-orthogonal corrections, therefore there is no need to increase the
value of nNonOrthogonalCorrectors.
• We are using a method that uses a wider stencil to compute the Laplacian, this method is more
stable but a little bit more diffusive. Did it run?
• At this point, compare the solution obtained with corrected and uncorrected schemes. Which
one is more diffusive?
749
Numerical playground
• When it comes to laplacianSchemes and snGradSchemes this is how we
proceed most of the times (a robust setup),
laplacianSchemes
{
default Gauss linear limited 1; PISO
} {
nCorrectors 2;
snGradSchemes nNonOrthogonalCorrectors 1;
{ }
default limited 1;
}
• This method works fine for meshes with non-orthogonality less than 75.
• If the non-orthogonality is more than 75, you should consider using limited
0.5, and increasing nCorrectors and nNonOrthogonalCorrectors.
• When the non-orthogonality is more than 85, the best solution is to redo the
mesh.
750
Numerical playground
Exercises
• Using the non-orthogonal mesh and the original dictionaries, try to run the solver reducing the time-step. Do
you get a solution at all?
• Try to get a solution using the method limited 1 and two nNonOrthogonalCorrectors (leave nCorrectors
equal to 1).
(Hint: try to reduce the time-step)
• If you managed to get a solution using the previous numerical scheme. How long did it take to get the
solution? Use the robust setup, clock the time and compare with the previous case. Which one is faster? Do
you get the same solution?
• Instead of using the non-orthogonal mesh, use a mesh with grading toward all edges. How will you stabilize
the solution?
(Hint: take a look at the blockMesh slides in order to add grading to the mesh)
• Try to get a solution using a time-step of 0.05 seconds. Use the original discretization schemes for the gradient
and convective terms.
(Hint: increase nCorrectors and nNonOrthogonalCorrectors)
• Try to break the solver and interpret the output screen. You are allow to modify the original mesh and use any
combination of discretization schemes.
751
Numerical playground
Seesaw:
Sod’s shock tube.
752
Numerical playground
Sod’s shock tube
• This case has an analytical solution and plenty of experimental data.
• This is an extreme test case used to test solvers.
• Every single commercial and open source solver use this case for validation of the
numerical schemes.
• The governing equation of this test case are the Euler equations.
753
Numerical playground
High Purity Photolysis Shock Tube (NASA Tube)
Shock tube. The driver section, including vacuum pumps, controls, and helium driver gas.
Photo credit: Stanford University. http://hanson.stanford.edu/index.php?loc=facilities_nasa
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose. 754
Numerical playground
Sod’s shock tube
755
Numerical playground
Sod’s shock tube
$PTOFC/101FVM/shockTube/
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
757
Numerical playground
What are we going to do?
• Now is your turn.
• You are asked to select the best discretization scheme for the physics involve.
Remember: accuracy, stability and boundedness.
• We will compare your numerical solution with the analytical solution.
• At this point, we are very familiar with the numerical schemes. It is up to you to
choose the best setup.
• You can start using the original dictionaries.
• To find the numerical solution we will use sonicFoam.
• sonicFoam is a transient solver for trans-sonic/supersonic, laminar or turbulent flow
of a compressible gas.
• After finding the numerical solution we will do some sampling.
• At the end, we will do some plotting (using gnuplot or Python) and scientific
visualization.
758
Numerical playground
Running the case
• You will find this tutorial in the directory $PTOFC/101FVM/schockTube
• Before running the case, you will need to choose the discretization scheme.
• In the terminal window type:
1. $> foamCleanTutorials
2. $> blockMesh
3. $> checkMesh
4. $> rm –rf 0
5. $> cp –r 0_org 0
6. $> setFields
7. $> sonicFoam | tee log
8. $> foamCalc mag U
9. $> postProcess -func sampleDict -latestTime
10. $> paraFoam
• To plot the analytical solution against the numerical solution, go to the directory python and run the Python script.
• In the terminal window type:
1. $> cd python
2. $> python3 sodschocktube.py
• The Python script will save four .png files with the solution. Feel free to explore and adapt the Python script to your needs.
• Remember, Python (version 3)must be installed in order to use the script
759
Numerical playground
Exercises
• Run the case using different time discretization schemes.
• Run the case using different gradient discretization schemes.
• Run the case using different convective discretization schemes for the term div(phi,U).
• Run the case using different convective discretization schemes for the terms div(phi,e) and div(phi,K). What
are the variables e and K?
• Extend the case to 2D and 3D. Do you get the same solution?
• Try to run a 2D case using a triangular mesh and adjust the numerical scheme to get an accurate and stable
solution.
• Try to run the 1D case using an explicit solver. For the same CFL number, do you have the same time step
size as for the implicit solver?
(Hint: look for the solver with the word Central)
• Try to break the solver (this is extremely easy in this case). You are allowed to modify the original mesh and
use any combination of discretization schemes.
760
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.
• 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®.
• Therefore, we are involuntarily omitting other references which are equally or even more important.
• The Finite Volume Method in Computational Fluid Dynamics: An Advanced Introduction With OpenFOAM and Matlab
F. Moukalled, L. Mangani, M. Darwish. 2015, Springer-Verlag
• Finite Volume Methods for Hyperbolic Problems
R. Leveque. 2002, Cambridge University Press
• Computational Gasdynamics
C. Laney. 1998, Cambridge University Press
• Computational Techniques for Multiphase Flows
G. H. Yeoh, J. Tu. 2009, Butterworth-Heinemann
• 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
• Computational Methods for Fluid Dynamics
J. H. Ferziger, M. Peric. 2001, Springer
• Numerical Heat Transfer and Fluid Flow
S. Patankar. 1980, Taylor & Francis
• A Finite Volume Method for the Prediction of Three-Dimensional Fluid Flow in Complex Ducts
M. Peric. PhD Thesis. 1985. Imperial College, London
• 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
761
Module 7
Highlights – Implementing boundary
conditions and initial conditions using
codeStream
762
Roadmap
1. codeStream – Highlights
2. Implementing boundary conditions using
codeStream
3. Solution initialization using codeStream
763
codeStream – Highlights
codeStream – Boundary conditions
• There are many boundary conditions available in OpenFOAM®.
• But from time to time it may happen that you do not find what you are looking for.
• It is possible to implement your own boundary conditions, so in theory you can do whatever you
want.
• Remember, you have the source code.
• To implement your own boundary conditions, you have three options:
• Use codeStream.
• Use high level programing.
• Use an external library (e.g., swak4foam).
• codeStream is the simplest way to implement boundary conditions, and most of the times you
will be able to code boundary conditions with no problem.
• If you can not implement your boundary conditions using codeStream, you can use high level
programming. However, this requires some knowledge on C++ and OpenFOAM® API.
• Hereafter, we are going to work with codeStream and basic high-level programming.
• We are not going to work with swak4Foam because it is an external library that is not officially
supported by the OpenFOAM® foundation. However, it works very well and is relatively easy to
use.
764
codeStream – Highlights
codeStream – Initial conditions
• When it comes to initial conditions, you can use the utility setFields.
• This utility is very flexible, you can even read STL files and use them to initialize fields.
• But again, it may happen that you can not get the desired results.
• As for boundary conditions, to implement your own initials conditions you have three options:
• Use codeStream.
• Use high level programing.
• Use an external library (e.g., swak4foam).
• codeStream is the simplest way to implement initial conditions, and most of the times you will
be able to code initial conditions with no problem.
• If you can not implement your initial conditions using codeStream, you can use high level
programming. However, this requires some knowledge on C++ and OpenFOAM® API.
• Hereafter, we are going to work only with codeStream.
• Using high level programming is a little bit trickier, and we guarantee you that 99% of the times
codeStream will work.
• We are not going to work with swak4Foam because it is an external library that is not officially
supported by the OpenFOAM foundation®. However, it works very well and is relatively easy to
use.
765
codeStream – Highlights
• Hereafter we will work with codeStream, which will let us program directly in the input
dictionaries.
• With codeStream, we will implement our own boundary conditions and initial
conditions without going thru the hustle and bustle of high-level programming.
• If you are interested in high level programming, refer to the supplements.
• In the supplemental slides, we address the following topics: building blocks,
implementing boundary conditions using high level programming, modifying
applications, implementing an application from scratch, and adding the scalar
transport equation to icoFoam.
• High level programming requires some knowledge on C++ and OpenFOAM® API
library. This is the hard part of programming in OpenFOAM®.
• Before doing high level programming, we highly recommend you to try with
codeStream, most of the time it will work.
• Also, before modifying solvers or trying to implement your own solvers, understand
the theory behind the FVM.
• Remember, you can access the API documentation in the following link,
https://cpp.openfoam.org/v5/
766
Roadmap
1. codeStream – Highlights
2. Implementing boundary conditions using
codeStream
3. Solution initialization using codeStream
767
Implementing boundary conditions using codeStream
• OpenFOAM® includes the capability to compile, load and execute C++ code
at run-time.
• This capability is supported via the directive #codeStream, that can be used
in any input file for run-time compilation.
• This directive reads the entries code (compulsory), codeInclude (optional),
codeOptions (optional), and codeLibs (optional), and uses them to
generate the dynamic code.
• The source code and binaries are automatically generated and copied in the
directory dynamicCode of the current case.
• The source code is compiled automatically at run-time.
• The use of codeStream is a very good alternative to avoid high level
programming of boundary conditions or the use of external libraries.
• Hereafter we will use codeStream to implement new boundary conditions,
but have in mind that codeStream can be used in any dictionary.
768
Implementing boundary conditions using codeStream
Body of the codeStream directive for boundary conditions
codeOptions
#{
-I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
#};
code
#{ Insert your code here.
At this point, you need to know
#}; how to access mesh information
};
}
769
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream
• Let us implement a parabolic inlet profile.
• The firs step is identifying the patch, its location and the dimensions.
• You can use paraview to get all visual references.
Outlet
pressure-outlet-7
Inlet
velocity-inlet-5
• 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,
771
Implementing boundary conditions using codeStream
• The codeStream BC in the body of the file U is as follows,
code
#{ Insert your code here.
At this point, you need to know
#}; how to access mesh information
};
}
772
Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows,
• Lines 3-11, are always standard, they are used to access boundary mesh information.
• In lines 3-6 we access the current dictionary.
• In line 8 we access the mesh database.
• In line 9 we get the label id (an integer) of the patch velocity-inlet-5 (notice that you need to give the name of
the patch).
• In line 10 using the label id of the patch, we access the boundary mesh information.
• In line 12 we initialize the vector field. The statement patch.size() gets the number of faces in the patch, and
the statement vector(0, 0, 0) initializes a zero vector field in the patch. 773
Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows,
1 code Index used to access the
2 #{ y coordinate
3 ... 0→x
4 ...
5 ...
1→y
6 const scalar pi = constant::mathematical::pi; 2→z
7 const scalar U_0 = 2.; //maximum velocity
8 const scalar p_ctr = 8.; //patch center
9 const scalar p_r = 8.; //patch radius
10
11 forAll(U, i) //equivalent to for (int i=0; patch.size()<i; i++)
12 {
13 const scalar y = patch.Cf()[i][1];
14 U[i] = vector(U_0*(1-(pow(y - p_ctr,2))/(p_r*p_r)), 0., 0.);
15 }
16 Assign input profile to vector field U (component x)
17 U.writeEntry("", os);
18 #};
1. $> cd $PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet
2. $> foamCleanTutorials
3. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh
775
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codeStream
• If everything went fine, you should get something like this
776
Implementing boundary conditions using codeStream
codeStream works with scalar and vector fields
• We just implemented the input parabolic profile using a vector field.
• You can do the same using a scalar field, just proceed in a similar way.
• Remember, now we need to use scalars instead of vectors.
• And you will also use an input dictionary holding a scalar field.
1 code
2 #{
3 ...
4 ...
5 ...
6 scalarField S(patch.size(), scalar(0) ); Initialize scalar field
7
8 forAll(S, i) Loop using scalar field size
9 {
10 const scalar y = patch.Cf()[i][1];
11 S[i] = scalar( 2.0*sin(3.14159*y/8.) );
Write profile values
12 } in scalar field
13
14 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
777
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• Let us work in a case a little bit more complicated, a paraboloid input profile.
• As usual, the first step is to get all the spatial references.
Inlet
auto3
779
Implementing boundary conditions using codeStream
• The codeStream BC in the body of the file U is as follows,
codeLibs
#{
-lmeshTools \
-lfiniteVolume
#};
Insert your code here.
code
#{
We will implement the following
equation
#};
};
}
780
Implementing boundary conditions using codeStream
• Hereafter, we only show the actual implementation of the codeStream boundary
condition.
• The rest of the body is a template that you can always reuse. Including the section of
how to access the dictionary and mesh information.
• Remember, is you are working with a vector, you need to use vector fields. Whereas,
if you are working with scalars, you need to use scalars fields.
1 code
2 #{
3 ...
4 ...
5 ...
6 vectorField U(patch.size(), vector(0, 0, 0) ); Initialize vector field
7
8 const scalar s = 0.5; Initialize scalar
9
10 forAll(U, i)
11 {
12 const scalar x = patch.Cf()[i][0]; Access faces center
13 const scalar y = patch.Cf()[i][1]; coordinates (x, y, and z)
14 const scalar z = patch.Cf()[i][2];
15
16 U[i] = vector(-1.*(pow(z/s, 2) + pow((y-s)/s,2) - 1.0), 0, 0);
17 }
18
19 U.writeEntry("", os);
20 #};
781
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/3Delbow_Uparaboloid/
• To run the case, type in the terminal,
1. $> cd $PTOFC/101programming/codeStream_BC/3Delbow_Uparaboloid/
2. $> foamCleanTutorials
3. $> gmshToFoam ../../../meshes_and_geometries/gmsh_elbow3d/geo.msh
782
Implementing boundary conditions using codeStream
Implementation of a paraboloid inlet profile using codeStream
• If everything went fine, you should get something like this
783
Implementing boundary conditions using codeStream
codedFixedValue and codedMixed boundary conditions
• OpenFOAM® also includes the boundary conditions codedFixedValue and
codedMixed.
• These boundary conditions are derived from codeStream and work in a
similar way.
• They use a friendlier notation and let you access more information of the
simulation database (e.g. time).
• The source code and binaries are automatically generated and copied in the
directory dynamicCode of the current case.
• Another feature of these boundary conditions, is that the code section can be
read from an external dictionary (system/codeDict), which is run-time
modifiable.
• The boundary condition codedMixed works in similar way. This boundary
condition gives you access to fixed values (Dirichlet BC) and gradients
(Neumann BC).
• Let us implement the parabolic profile using codedFixedValue.
784
Implementing boundary conditions using codeStream
Body of the codedFixedValue boundary conditions
codeInclude
#{
#include "fvCFD.H"
#include <cmath> Files needed for compilation
#include <iostream>
#};
In this section we do the actual
code implementation of the boundary
#{ condition.
This is the only part of the body
#}; that you will need to change. The
} rest of the body is a template that
you can always reuse. 785
Implementing boundary conditions using codeStream
• The code section of the codeStream BC in the body of the file U is as follows,
1 code
2 #{
3 const fvPatch& boundaryPatch = patch();
4 const vectorField& Cf = boundaryPatch.Cf();
5 vectorField& field = *this;
6
7 scalar U_0 = 2, p_ctr = 8, p_r = 8;
8
9 forAll(Cf, faceI)
10 {
11 field[faceI] = vector(U_0*(1-(pow(Cf[faceI].y()-p_ctr,2))/(p_r*p_r)),0,0);
12 }
13 #};
• Lines 3-5, are always standard, they give us access to mesh and field information in the patch.
• The coordinates of the faces center are stored in the vector field Cf (line 4).
• In this case, as we are going to implement a vector profile, we initialize a vector field where we are going to
assign the profile (line 5).
• In line 7 we initialize a few constants that will be used in our implementation.
• In lines 9-12 we use a forAll loop to access the boundary patch face centers and to assign the velocity profile
values.
• In line 11 we do the actual implementation of the boundary profile (similar to the codeStream case). The
vector field was initialize in line 5.
786
Implementing boundary conditions using codeStream
codedFixedValue and codedMixed boundary conditions
• As you can see, the syntax and use of the codedFixedValue and codedMixed
boundary conditions is much simpler than codeStream.
• You can use these instructions as a template. At the end of the day, you only need to
modify the code section.
• Depending of what you want to do, you might need to add new headers and
compilation options.
• Remember, is you are working with a vector, you need to use vector fields. Whereas,
if you are working with scalars, you need to use scalars fields.
• One disadvantage of these boundary conditions, is that you can not visualize the
fields at time zero. You will need to run the simulation for at least one iteration.
• On the positive side, accessing time and other values from the simulation database is
straightforward.
• Time can be accessed by adding the following statement,
this->db().time().value()
787
Implementing boundary conditions using codeStream
• Let us add time dependency to the parabolic profile.
1 code
2 #{
3 const fvPatch& boundaryPatch = patch();
4 const vectorField& Cf = boundaryPatch.Cf();
5 vectorField& field = *this;
6
7 scalar U_0 = 2, p_ctr = 8, p_r = 8;
8
9 scalar t = this->db().time().value(); Time
10
11 forAll(Cf, faceI)
12 {
13 field[faceI] = vector(sin(t)*U_0*(1-(pow(Cf[faceI].y()-p_ctr,2))/(p_r*p_r))),0,0);
14 }
15 #};
Time dependency
• This implementation is similar to the previous one, we will only address how to deal with time.
• In line 8 we access simulation time.
• In line 13 we do the actual implementation of the boundary profile (similar to the codeStream
case). The vector field was 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).
788
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet_timeDep
• To run the case, type in the terminal,
1. $> cd $PTOFC/101programming/codeStream_BC/2Delbow_UparabolicInlet_timeDep
2. $> foamCleanTutorials
3. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh
789
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• If everything went fine, you should get something like this
www.wolfdynamics.com/wiki/BCIC/elbow_unsBC1.gif
790
Implementing boundary conditions using codeStream
Filling a tank using codedFixedValue
• 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
791
Implementing boundary conditions using codeStream
• Definition of the vector field boundary condition (dictionary file U),
792
Implementing boundary conditions using codeStream
• Definition of the vector field boundary condition (dictionary file U),
7 code Code section. The actual implementation of the BC is done in this section
8 #{
...
... Loop using size of boundary patch (Cf) and iterator
... faceI.
19 This is equivalent to:
20 forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
21 {
22
23 if (
24 (Cf[faceI].z() > minz) &&
Use conditional structure to
25 (Cf[faceI].z() < maxz) &&
26 (Cf[faceI].y() > miny) && select faces according to the
27 (Cf[faceI].y() < maxy) variables defined in lines 13-16
28 )
29 {
30 if ( t < 1.)
31 { Use conditional structure to
32 field[faceI] = vector(1,0,0); add time dependency and
33 } assign values to the
34 else
selected faces.
35 {
36 field[faceI] = vector(0,0,0); The variable field was
37 } initialize in line 11.
38 }
39 }
40 #};
41 }
793
Implementing boundary conditions using codeStream
• Definition of the scalar field boundary condition (dictionary file alpha.water),
7 code Code section. The actual implementation of the BC is done in this section
8 #{
...
Loop using size of boundary patch (Cf) and iterator
...
... faceI.
22 This is equivalent to:
23 forAll(Cf, faceI) for (int faceI=0; Cf.size()<faceI; faceI++)
24 {
25 if (
26 (Cf[faceI].z() > minz) && Use conditional structure to
27 (Cf[faceI].z() < maxz) && select faces according to the
28 (Cf[faceI].y() > miny) &&
variables defined in lines 13-16
29 (Cf[faceI].y() < maxy)
30 )
31 {
32 if ( t < 1.)
33 { Use conditional structure to add
34 field[faceI] = 1.; time dependency and assign
35 }
36 else
values to the selected faces.
37 { The variable field was initialize in
38 field[faceI] = 0.; line 11.
39 }
40 }
41 }
42 #};
43 }
795
Implementing boundary conditions using codeStream
Implementation of a parabolic inlet profile using codedFixedValue
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_BC/fillBox_BC/
• To run the case, type in the terminal,
1. $> 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
00
00
00
0 02
0 01
0
0 02 0 0 0 1 12 1 1 1 2
1. codeStream – Highlights
2. Implementing boundary conditions using
codeStream
3. Solution initialization using codeStream
798
Solution initialization using codeStream
• When it comes to initial conditions, you can use the utility setFields.
• This utility is very flexible, you can even read STL files and use them to
initialize your fields.
• But in case that you can not get the desired results using setFields, you
can implement your own initial conditions using codeStream.
• To implement initial conditions using codeStream, we proceed in a similar
way as for boundary conditions.
• The source code and binaries are automatically generated and copied in the
directory dynamicCode of the current case.
• The source code is compiled automatically at run-time.
• The use of codeStream is a very good alternative to avoid high level
programming of initial conditions or the use of external libraries.
• Hereafter we will use codeStream to implement new initial conditions.
799
Solution initialization using codeStream
Body of the codeStream directive for initial conditions
#};
codeOptions
#{
-I$(LIB_SRC)/finiteVolume/lnInclude \ Compilation options
-I$(LIB_SRC)/meshTools/lnInclude
#};
codeLibs
Libraries needed for compilation.
#{
-lmeshTools \ Needed if you want to visualize the
-lfiniteVolume output of the initial conditions at
#}; time zero
code
#{
Insert your code here.
#}; At this point, you need to know
}; how to access internal mesh
} information
800
Solution initialization using codeStream
Implementation of an elliptic initialization using codeStream
• Let us implement an elliptic initialization using codeStream.
• The firs step is to know your domain and identify the region that you want to initialize.
• Then you will need to do a little bit of math to get the expression for the initialization.
• In this example, we are also going to show you how to do the same initialization by
reading a STL file with the utility setFields.
Phase 1
801
Solution initialization using codeStream
• The codeStream IC in the body of the file alpha.phase1 is as follows,
code
#{
Insert your code here.
#}; At this point, you need to know
}; how to access internal mesh
} information
802
Solution initialization using codeStream
• The code section of the codeStream IC in the body of the file alpha.phase1 is as follows,
following statement
}
alpha.writeEntry("", os);
#};
803
Solution initialization using codeStream
Implementation of an elliptic initialization using codeStream
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_INIT/elliptical_IC
• To run the case, type in the terminal,
1. $> 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
Surface tension driven flow - Bubble in a zero gravity flow using interFoam
805
Solution initialization using codeStream
Elliptic initialization using setFields
• Let us do the same initialization using a STL file with setFields.
• First, you will need to create the solid model that encloses the region you want to
initialize. For this, you can use your favorite CAD/solid modeling software.
Remember to save the geometry is STL format.
• Then you will need to read in the STL file using setFields. You will need to modify
the setFieldsDict dictionary.
Region defined by
the STL file
Computational domain
806
Solution initialization using codeStream
The setFieldsDict dictionary
defaultFieldValues
(
volScalarFieldValue alpha.phase1 0 Initialize the whole domain to zero
);
regions
setFields method to read STL files.
( If you want to know all the options
available use a word that does not exist
surfaceToCell in the enumerator list (e.g. banana)
{
file "./geo/ellipse.stl"; Location of the STL file to read
outsidePoints ((0.5 0.85 0)); A point located outside the STL
1. $> cd $PTOFC/101programming/codeStream_INIT/elliptical_IC
2. $> foamCleanTutorials
3. $> blockMesh
4. $> rm –rf 0
5. $> cp –r 0_org 0
6. $> setFields
7. $> paraFoam
808
Solution initialization using codeStream
Rayleigh-Taylor instability initialization
809
Solution initialization using codeStream
• The code section of the codeStream IC in the body of the file alpha.phase1 is as follows,
{
const scalar x = mesh.C()[i][0];
const scalar y = mesh.C()[i][1];
Access cell centers coordinates
if (y >= -0.05*cos(2*constant::mathematical::pi*x))
{
alpha[i] = 1.;
}
}
alpha.writeEntry("", os);
#}; Write output to input dictionary
810
Solution initialization using codeStream
Rayleigh-Taylor instability initialization
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/codeStream_INIT/rayleigh_taylor
• To run the case, type in the terminal,
1. $> cd $PTOFC/101programming/codeStream_INIT/rayleigh_taylor
2. $> foamCleanTutorials
3. $> blockMesh
4. $> interFoam | tee log
5. $> paraFoam
811
Solution initialization using codeStream
Rayleigh-Taylor instability initialization
• If everything went fine, you should get something like this
812
Solution initialization using codeStream
Filling a tank using codeStream and codedFixedValue
• Let us do a final example.
• We will implement BCs and ICs at the same.
• For simplicity, we will only show the code section of the input files.
• This setup is similar to the last example of the previous section (filling a tank using
codedFixedValue).
813
Solution initialization using codeStream
• The code section of the codeStream IC in the body of the file alpha.water is as follows,
internalField #codeStream
Use codeStream to set the
{ value of the initial conditions
if (y <= 0.2)
{ Assign value to alpha according to
alpha[i] = 1.; conditional structure
}
}
814
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file U is as follows,
815
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file U is as follows,
if (
(Cf[faceI].z() > min) &&
(Cf[faceI].z() < max) && Use conditional structure to
(Cf[faceI].y() > min) && select faces.
(Cf[faceI].y() < max)
)
{
if ( t < 2.)
{
field[faceI] = vector(1,0,0); Use conditional structure to
} add time dependency and
else
assign values to the
{
field[faceI] = vector(0,0,0); selected faces.
}
}
}
#};
816
Solution initialization using codeStream
• The code section of the codeFixedValue BC in the body of the file alpha.water is as follows,
field = patchInternalField(); Assign value from the internal field to the patch
818
Solution initialization using codeStream
Filling a tank using codeStream and codedFixedValue
• If everything went fine, you should get something like this
02
02
02
0 22
02
01
0 0 1 1 2 2
819
Module 8
Advanced physics
Turbulence modeling – Multiphase flows –
Compressible flows – Moving bodies –
Source terms – Passive scalars
820
• In this module, we will deal with advanced modeling capabilities.
• Advanced modeling capabilities rely a lot in physical models, such as,
turbulence, multiphase flows, porous media, combustion, radiation, heat
transfer, phase change, acoustics, cavitation, and so on.
• Therefore, it is extremely important to get familiar with the theory behind the
models.
822
A crash introduction to turbulence modeling in OpenFOAM®
What is turbulence?
• For the purpose of this training, let us state the following:
• Turbulence is an unsteady, aperiodic motion in which
all three velocity components fluctuate in space and
time.
• Every transported quantity shows similar fluctuations
(pressure, temperature, species, concentration, and
so on)
• Turbulent flows contains a wide range of eddy sizes
(scales):
• Large eddies derives their energy from the mean
flow. The size and velocity of large eddies are on
the order of the mean flow.
• Large eddies are unstable and they break-up into
smaller eddies.
• The smallest eddies convert kinetic energy into
thermal energy via viscous dissipation.
• The behavior of small eddies is more universal in
nature. Buoyant plume of smoke rising from a stick of incense
Photo credit: https://www.flickr.com/photos/jlhopgood/
This work is licensed under a Creative Commons License
(CC BY-NC-ND 2.0)
823
A crash introduction to turbulence modeling in OpenFOAM®
Wake turbulence behind individual wind turbines Flow visualization over a spinning spheroid
Photo credit: NREL's wind energy research group. Photo credit: Y. Kohama.
Copyright on the images is held by the contributors. Apart from Fair Use, Copyright on the images is held by the contributors. Apart from Fair Use,
permission must be sought for any other purpose. permission must be sought for any other purpose.
Von Karman vortices created when prevailing winds sweeping east across Vortices on a 1/48-scale model of an F/A-18 aircraft inside a Water
the northern Pacific Ocean encountered Alaska's Aleutian Islands Tunnel
Photo credit: USGS EROS Data Center Satellite Systems Branch. Photo credit: NASA Dryden Flow Visualization Facility.
Copyright on the images is held by the contributors. Apart from Fair Use, Copyright on the images is held by the contributors. Apart from Fair Use,
permission must be sought for any other purpose. permission must be sought for any other purpose. 824
A crash introduction to turbulence modeling in OpenFOAM®
Flow around two spheres. Left image: smooth sphere. Right image: sphere with rough surface at the nose
Photo credit: http://www.mhhe.com/engcs/civil/finnemore/graphics/photos/AuthorRecommendedImages/index.html
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 825
A crash introduction to turbulence modeling in OpenFOAM®
826
A crash introduction to turbulence modeling in OpenFOAM®
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
References:
Lyn, D.A. and Rodi, W., The flapping shear layer formed by flow separation from the forward corner of a square cylinder. J. Fluid Mech., 267, 353, 1994.
Lyn, D.A., Einav, S., Rodi, W. and Park, J.H., A laser-Doppler velocimetry study of ensemble-averaged characteristics of the turbulent near wake of a square
cylinder. Report. SFB 210 /E/100.
828
A crash introduction to turbulence modeling in OpenFOAM®
Convective effects
where
Viscous effects
Buoyancy effects
Momentum diffusivity
• Notice that other factors such as free-stream turbulence, surface conditions, blowing, suction,
roughness and other disturbances, may cause transition to turbulence at lower Reynolds
number.
• If you are dealing with natural convection and buoyancy, turbulent flows occurs when
831
A crash introduction to turbulence modeling in OpenFOAM®
• The Reynold number in this case is 100, for these conditions the flow still is laminar.
• We are in the presence of the Von Karman vortex street, which is the periodic shedding of vortices caused by
the unsteady separation of the fluid around blunt bodies.
• Vorticity is not a direct indication of turbulence.
• However turbulent flows are rotational, they exhibit vortical structures. 833
A crash introduction to turbulence modeling in OpenFOAM®
• We have defined turbulence as an unsteady, aperiodic motion in which velocity components and every
transported quantity fluctuate in space and time.
• For most engineering application it is impractical to account for all these instantaneous fluctuations.
• Therefore, we need to somehow remove those small scales by using models.
• To remove the instantaneous fluctuations or small scales, two methods can be used: Reynolds averaging and
Filtering
• Both methods introduce additional terms that must be modeled for closure.
• We are going to talk about closure methods later. 834
A crash introduction to turbulence modeling in OpenFOAM®
Laminar flow profile Averaged turbulent flow profile Instantaneous turbulent flow profile
• In the laminar flow case, the velocity gradients close to the walls are low and the velocity profile
is parabolic.
• Turbulence has a direct effect on the velocity profiles and mixing of transported quantities.
• The turbulent case shows two regions. One thin region close to the walls with very large velocity
gradients, and a region far from the wall where the velocity profile is nearly uniform.
• The thin region close to the walls has very large velocity gradients and is laminar.
• Far from the flows, the flow becomes turbulent. 835
A crash introduction to turbulence modeling in OpenFOAM®
ogarit mi layer
uffer layer
is ous sublayer
riti al lengt
integral s ales
inertial s ales
• The use of the non-dimensional velocity u+ and non-dimensional distance from the wall y+, results in a
predictable boundary layer profile for a wide range of flows.
• Turbulence models require different considerations depending on whether you solve the viscous sublayer of
model the log-law layer.
838
A crash introduction to turbulence modeling in OpenFOAM®
839
A crash introduction to turbulence modeling in OpenFOAM®
840
A crash introduction to turbulence modeling in OpenFOAM®
Cell size
This cell is resolving the eddies
• Turbulence modelling aims at predicting velocity and transported quantities fluctuations without
calculating the complete turbulent flow pattern as a function of time.
• Everything below grid scales or sub-grid scales (SGS) is modelled or filtered.
• Therefore, if we want to capture all scales we need very fine meshes in the whole domain.
MODEL
URANS
complexity
Unsteady Reynolds-Averaged Navier-Stokes equations
SAS
Scale Adaptive Simulations
Scale-Resolving Simulations
DES
SRS
LES
Large Eddy Simulations
DNS
Direct Numerical Simulations
842
A crash introduction to turbulence modeling in OpenFOAM®
Robust. Widely used despite the known limitations of the model. Performs poorly for complex
Standard k–epsilon flows involving severe pressure gradient, separation, strong streamline curvature. Suitable for
initial iterations, initial screening of alternative designs, and parametric studies.
Suitable for complex shear flows involving rapid strain, moderate swirl, vortices, and locally
transitional flows (e.g. boundary layer separation, massive separation, and vortex shedding
Realizable k–epsilon behind bluff bodies, stall in wide-angle diffusers, room ventilation). It overcome the limitations of
the standard k-epsilon model.
Superior performance for wall-bounded boundary layer, free shear, and low Reynolds number
Standard k–omega flows compared to models from the k-epsilon family. Suitable for complex boundary layer flows
under adverse pressure gradient and separation (external aerodynamics and turbomachinery).
Offers similar benefits as standard k–omega. Not overly sensitive to inlet boundary conditions
SST k–omega like the standard k–omega. Provides more accurate prediction of flow separation than other
RANS models. Probably the most widely used RANS model.
844
A crash introduction to turbulence modeling in OpenFOAM®
NSE
If we retain this term, we talk about URANS equations and if we drop it we talk about RANS equations
• To derive the RANS equations we used Reynolds decomposition and a few averaging
rules (a lot of algebra is involved),
846
A crash introduction to turbulence modeling in OpenFOAM®
• The Reynolds stress tensor can be modeled using the Boussinesq hypothesis, Reynolds stress models, non-
linear eddy viscosity models or algebraic models.
• Let us address the Boussinesq hypothesis which is the most widely used approach to model the Reynolds
stress tensor.
• By using this hypothesis we can relate the Reynolds stress tensor to the mean velocity gradient such that,
• These are the closure equations of the turbulence problem using Reynolds average.
• These are not physical quantities. They kind of represent the generation and
destruction of turbulence.
• In the model, the turbulent eddy viscosity can be computed as follows,
• It is worth mentioning that different turbulence models will have different ways of
computing the turbulent eddy viscosity. 849
A crash introduction to turbulence modeling in OpenFOAM®
• The initial value for the specific kinetic energy can be found as follows
1 10 100
• By the way, use these guidelines for external aerodynamics only. 850
A crash introduction to turbulence modeling in OpenFOAM®
• Follow these guidelines to find the boundary conditions for the near-wall treatment.
• We highly recommend you to read the source code and find the references used to
implement the model.
• As for the free-stream boundary conditions, you need to give the boundary conditions
for the near-wall treatment.
• When it comes to near-wall treatment, you have three options:
• Use wall functions:
• Use scalable wall functions, this only applies with the model:
851
A crash introduction to turbulence modeling in OpenFOAM®
nutUSpaldingWallFunction** or
nut(–)WallFunction* or
nut nutLowReWallFunction or
nutUSpaldingWallFunction**
fixedValue 0 (or a small number)
zeroGradient or fixedValue 0
epsilon epsilonWallFunction
(or a small number)
omegaWallFunction** or
omega omegaWallFunction
fixedValue (with a large number)
* $WM_PROJECT_DIR/src/TurbulenceModels/turbulenceModels/derivedFvPatchFields/wallFunctions/nutWallFunctions
** For scalable wall functions 852
A crash introduction to turbulence modeling in OpenFOAM®
1.
(Skin friction coefficient of a flat plate, there are
2. similar correlations for pipes)
3.
4.
Your desired value
5.
• You will find a simple calculator for the wall distance estimation in the following link:
http://www.wolfdynamics.com/tools.html?id=2
855
A crash introduction to turbulence modeling in OpenFOAM®
• Similar to , the wall distance units can be computed in the stream-wise ( ) and span-
wise ( ) directions.
• DES and RANS simulations do not have stream-wise and span-wise wall distance units
requirements as in LES simulations. Therefore, they are more affordable.
• Typical requirements for LES are:
856
A crash introduction to turbulence modeling in OpenFOAM®
858
A crash introduction to turbulence modeling in OpenFOAM®
References
• Turbulent Flows
Stephen B. Pope
• Turbulence Modeling for CFD
David C. Wilcox
• Turbulence: An Introduction for Scientists and Engineers
P. A. Davidson
• Large Eddy Simulation for Incompressible Flows
Pierre Sagaut
• A First Course in Turbulence
H. Tennekes and J. L. Lumley
• Boundary-Layer Theory
H. Schlichting
• https://turbmodels.larc.nasa.gov/
859
Turbulence modeling hands-on tutorials
$PTOFC/advanced_physics/turbulence/flatPlate
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
860
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate
• The best way to understand the near the wall treatment and the effect of turbulence near the
walls, is by reproducing the law of the wall.
• By plotting the velocity in terms of the non-dimensional variables u+ and y+, we can compare
the profiles obtained from the simulations with the theoretical profiles. 861
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate
• In the directory python of each case, you will find a jupyter notebook (a python
script), that you can use to plot the non-dimensional u+ and y+ profiles.
• The notebook uses some precomputed results, but you can adjust it to any case.
• Remember, the u+ vs. y+ plot is kind of a universal plot.
• It does not matter your geometry or flow conditions, if you are resolving well the
turbulent flow, you should be able to recover this profile.
• To compute this plot, you must sample the wall shear stresses.
• Then, you can compute the shear velocity, friction coefficient, and u+ and y+ values.
862
Turbulence modeling hands-on tutorials
Laminar-Turbulent flat plate
• We are going to use the following solver: simpleFoam (for RANS).
• This case is rather simple but we will use it to explain many features used in
OpenFOAM® when dealing with turbulence, especially when dealing with near the
wall treatment.
• We will also show you how to do the post-processing in order to reproduce the law of
the wall. For this, we will use a jupyter notebook (a python script).
• Remember, as we are introducing new closure equations for the turbulence problem,
we need to define initial and boundary conditions for the new variables.
• We also need to define the discretization schemes and linear solvers to use to solve
the new variables.
• It is also a good idea to setup a few functionObjects, such as: y+, minimum and
maximum values, forces, time average, and online sampling.
• You will find the instructions of how to run this case in the file README.FIRST
located in the case directory.
863
Turbulence modeling hands-on tutorials
$PTOFC/advanced_physics/turbulence/squarecil
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend you to open the README.FIRST file and type the commands in the terminal, in this
way, you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
864
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
865
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
References:
Lyn, D.A. and Rodi, W., The flapping shear layer formed by flow separation from the forward corner of a square cylinder. J. Fluid Mech., 267, 353, 1994.
Lyn, D.A., Einav, S., Rodi, W. and Park, J.H., A laser-Doppler velocimetry study of ensemble-averaged characteristics of the turbulent near wake of a square
cylinder. Report. SFB 210 /E/100.
866
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• We will use this case to learn how to setup a turbulent case (RANS and LES).
• To run this case we will use the solvers simpleFoam (steady solver) and pimpleFoam
(unsteady solver).
• To get fast outcomes, we will use a coarse mesh. But feel free to refine the mesh, specially
close to the walls.
• Remember, as we are introducing new closure equations for the turbulence problem, we need to
define initial and boundary conditions for the new variables.
• We will use a few functionObjects to compute some additional quantities, such as, Q criterion,
y+, minimum and maximum values, forces, time average, and online sampling.
• After finding the solution, we will visualize the results.
• We will also compare the numerical solution with the experimental results.
• At the end, we will do some plotting and advanced post-processing using gnuplot and Python.
• Have in mind that the unsteady case will generate a lot of data.
• You will find the instructions of how to run this case in the file README.FIRST located in the
case directory.
867
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• We select the turbulence model in the turbulenceProperties dictionary file.
• This dictionary file is located in the directory constant.
• To select the K-Omega SST turbulence model,
• Remember, you need to assign boundary and initial conditions to the new variables (k, omega,
and nut).
868
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• We select the turbulence model in the turbulenceProperties dictionary file.
• This dictionary file is located in the directory constant.
• To select the LES (Smagorinsky) turbulence model,
27 delta cubeRootVol;
31 cubeRootVolCoeffs
LES filter
32 {
33 deltaCoeff 1;
34 }
100 }
• Remember, you need to assign boundary and initial conditions to the new variables (nut).
869
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• To select wall functions, follow this table,
• In this tutorial,
• Use High RE for RANS.
• Use High RE and Low RE for URANS.
• Use High RE and Low RE for LES.
870
Turbulence modeling hands-on tutorials
Vortex shedding past square cylinder
• The initial value for the turbulent kinetic energy can be found as follows,
• The initial value for the specific kinetic energy can be found as follows,
• At this point, we are ready to run. But before running, remember to setup the right
numerics in the dictionary files fvSolution and fvSchemes.
• Also, for the LES simulation try to keep the CFL number below 0.9
• Finally, do not forget to setup the functionObjects to compute the forces, do the
sampling, and compute y+ on-the-fly.
871
Roadmap
872
A crash introduction to multiphase flows modeling OpenFOAM®
873
A crash introduction to multiphase flows modeling OpenFOAM®
Propeller cavitation
http://www.veempropellers.com/features/cavitationresistance
Siltation & Sedimentation
http://blackwarriorriver.org/siltation-sedimentation/
874
A crash introduction to multiphase flows modeling OpenFOAM®
Fermentation of beer and spirits Chemical reactor for the pharmaceutical and
http://www.distillingliquor.com/2015/02/05/how-to-make-alcohol-and-spirits/ biotechnology industry
http://www.total-mechanical.com/Industrial/CaseStudies.aspx
875
A crash introduction to multiphase flows modeling OpenFOAM®
Modeling requirements
turbulence modelling.
Computational power
• Eulerian-Lagrangian: solves idealized
isolated particles that are transported
with the flow. One- or two-way coupling
is possible. Can account for turbulence,
momentum transfer, and mass transfer.
• Eulerian-eulerian: solves two or more
co-existing fluids. The system can be
dispersed or separated, and can account
for turbulence, momentum transfer, and
Increase
mass transfer.
878
A crash introduction to multiphase flows modeling OpenFOAM®
Eulerian-Eulerian approach
Eulerian-Eulerian approach Eulerian-Lagragian approach
(Multi-fluid and mixture
(VOF) (Particle tracking)
models)
879
A crash introduction to multiphase flows modeling OpenFOAM®
VOF ≈ 0.5
Average phase
properties
In theory, the VOF method can resolve the smallest bubbles/droplets but the mesh requirements are
too prohibitive (equivalent to DNS). In multiphase flows, this is called fully resolved approach.
880
A crash introduction to multiphase flows modeling OpenFOAM®
881
A crash introduction to multiphase flows modeling OpenFOAM®
Eulerian-Eulerian Eulerian-Eulerian
Eulerian-Lagrangian
(VOF) (Dispersed systems)
http://www.wolfdynamics.com/training/mphase/image2.gif http://www.wolfdynamics.com/training/mphase/image3.gif
• Simulation showing free surface tracking, bubble tracking, bubble coalescence, bubble break-up and wake
entrainment using the VOF method.
• In this simulation the free surface and bubbles are capture by using AMR. However, the smallest bubble that
can be resolved is at the smallest grid size. 885
A crash introduction to multiphase flows modeling OpenFOAM®
www.wolfdynamics.com/training/mphase/image10.gif http://www.wolfdynamics.com/training/mphase/image16.gif
http://www.wolfdynamics.com/training/mphase/image18.gif
References:
[1] Vivek V. Buwa, Vivek V. Ranade, Dynamics of gas–liquid flow in a rectangular bubble column: experiments and single/multi-group CFD simulations.
Chemical Engineering Science 57 (2002) 4715 – 4736 887
A crash introduction to multiphase flows modeling OpenFOAM®
twoPhaseEulerFoam twoPhaseEulerFoam
Air volume fraction Air volume fraction
Turbulent case Laminar case
http://www.wolfdynamics.com/training/mphase/image42.gif http://www.wolfdynamics.com/training/mphase/image41.gif
DPMFoam twoPhaseEulerFoam
Particle-particle interactions colored by velocity Air volume fraction
magnitude (particles not to scale) Turbulent case
http://www.wolfdynamics.com/training/mphase/image43.gif http://www.wolfdynamics.com/training/mphase/image42.gif
• You can see the volume fraction as a pointer that indicates what phase (with the
corresponding physical properties), is inside each cell of the computational domain. 890
A crash introduction to multiphase flows modeling OpenFOAM®
• The fluid properties can be written on either side of the interface as follows,
891
A crash introduction to multiphase flows modeling OpenFOAM®
Source terms:
• Porous media
• Coriolis forces
• Centrifugal forces
• Mass transfer
• and so on …
892
A crash introduction to multiphase flows modeling OpenFOAM®
894
A crash introduction to multiphase flows modeling OpenFOAM®
• You will find the source code of all the multiphase solvers in the directory:
• OpenFOAM-6/applications/solvers/multiphase
• You will find the source code all the particle tracking solvers in the directory:
• OpenFOAM-6/applications/solvers/lagrangian
895
A crash introduction to multiphase flows modeling OpenFOAM®
898
A crash introduction to multiphase flows modeling OpenFOAM®
899
A crash introduction to multiphase flows modeling OpenFOAM®
• When you create the dictionaries for the boundary conditions and initials
conditions for the volume fraction (or alpha), you use the same naming
convention as in the dictionary transportProperties.
• That is to say, if you are naming you primary phase phase1, you should
create the dictionary alpha.phase1.
• This dictionary will contain the initial and boundary conditions of the volume
fraction
900
A crash introduction to multiphase flows modeling OpenFOAM®
901
Multiphase flows hands-on tutorials
$PTOFC/advanced_physics/multiphase/wigleyHull
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
902
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
Drag coefficient
904
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
905
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• The next step is to set the boundary conditions and initial conditions.
• In the dictionary constant/transportProperties we defined the phases water
and air, where water is the primary phase.
• Therefore, in the directory 0 we define the dictionary alpha.water that will take
the values of the phase water.
• In this case, you will find the directory 0_org, here is where we keep a backup of the
original files as we are doing field initialization using setFields.
• In the directory 0, you will find the dictionary p_rgh, in this dictionary we set the
boundary and initial conditions for the pressure field, and the dimensions are in
Pascals.
• The turbulence variables values were calculated using an eddy viscosity ratio equal
to 1, turbulence intensity equal 5%, and the water properties.
• If you are simulating numerical towing tanks, the setup of the boundary conditions is
always the same.
• Feel free to reuse this setup.
906
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
Opening
Air phase Wall
Inlet outlet
Note:
Phases must be initialized
on the internal cells and
boundary faces
Symmetry
Physical domain and boundary patches 907
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
fixedValue
inflow fixedFluxPressure fixedValue fixedValue
calculated (nut)
inletOutlet
outflow inletOutlet outletPhaseMeanVelocity variableHeightFlowRate
calculated (nut)
inletOutlet
top totalPressure pressureInletOutletVelocity inletOutlet
calculated (nut)
kqRWallFunction (k)
ship fixedFluxPressure fixedValue omegaFunction (omega) zeroGradient
nutkWallFunction (nut)
Typical setup of boundary conditions for numerical towing tank simulations 908
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• 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.
911
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
divSchemes
These terms are related to the
{
volume fraction equation
• Notice that we are using a high resolution scheme for the surface tracking or
div(phi,alpha). 912
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• For time discretization we can use an unsteady formulation (Euler in this case).
• This scheme requires setting the time-step, and it should be choosing in such a way
that it resolves the mean physics.
• Remember, as the free surface is a strong discontinuity, for stability and good
resolution we need to use a CFL less than one for the interface courant.
ddtSchemes
{
default Euler;
}
• Hereafter, we are using what is know as global time stepping, that is, the CFL
number is limited by the smallest cell.
• The simulation is time-accurate, but it requires a lot of CPU time to reach a steady
state (if it reaches one).
913
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• A way to accelerate the convergence to steady state, is by using local time stepping.
• In LTS or local time steeping, the time-step is manipulated for each individual cell in
the mesh, making it as high as possible to enable the simulation to reach steady-
state quickly.
• When we use LTS, the transient solution is no longer time accurate.
• The stability and accuracy of the method are driven by the local CFL number of each
cell.
• To avoid instabilities caused by sudden changes in the time-step of each cell, the
local time-step can be smoothed and damped across the domain.
• To enable LTS, we use the localEuler method.
ddtSchemes
{
default localEuler;
}
914
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
• In the LTS method, the maximum flow CFL number, maximum interface CFL number,
and the smoothing and damping of the solution across the cells, can be controlled in
the dictionary fvSolution, in the sub-dictionary PIMPLE.
PIMPLE
{
momentumPredictor yes;
nOuterCorrectors 1;
nCorrector 3;
nNonOrthogonalCorrectors 2;
915
Multiphase flows hands-on tutorials
Free surface – Ship resistance simulation
916
Roadmap
917
A crash introduction to compressible flows modeling OpenFOAM®
Large Natural Convection Plume, as effect of combustion of excess Rayleigh–Bénard convection cells
non-useable gases behind oilfield. https://en.wikipedia.org/wiki/File:B%C3%A9nard_cells_convection.ogv
https://en.wikipedia.org/wiki/Plume_(fluid_dynamics)#/media/File:Naturalc
onvectionplume.JPG
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 920
A crash introduction to compressible flows modeling OpenFOAM®
Copyright on the images is held by the contributors. Apart from Fair Use, permission must be sought for any other purpose 921
A crash introduction to compressible flows modeling OpenFOAM®
NSE
Thermal boundary layer vs. Viscous boundary layer Thermal boundary layer in function of Prandtl number (Pr)
Forced convection
Horizontal heated plate immersed in a quiescent fluid. Vertical heated plate immersed in a quiescent fluid.
Natural convection Natural convection.
926
A crash introduction to compressible flows modeling OpenFOAM®
931
A crash introduction to compressible flows modeling OpenFOAM®
divSchemes “( | | )”
{ {
div(phi,T) Gauss linearUpwind Grad(T); solver PBiCGStab;
div(phi,K) Gauss linear; preconditioner DILU;
div(phi,h) Gauss linear; tolerance 1e-8;
… relTol 0.01;
… }
… …
} …
…
divSchemes “( | | )”
{ {
div(phi,T) Gauss linearUpwind Grad(T); solver PBiCGStab;
div(phi,K) Gauss linear; preconditioner DILU;
div(phi,e) Gauss linear; tolerance 1e-8;
div(phiv,p) Gauss linear; relTol 0.01;
… }
… …
… …
} …
Final remarks
• When solving the enthalpy formulation of the energy equation,
• Finally, when you work with compressible solvers you use absolute
pressure and the working units are in Pascals.
935
Compressible flows hands-on tutorials
$PTOFC/advanced_physics/compressible/2Dcylinder_plumes/buoyantPimpleFoam/
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
936
Compressible flows hands-on tutorials
2D Heated cylinder – Thermal plumes
937
Compressible flows hands-on tutorials
2D Heated cylinder – Thermal plumes
• In this case we will use the solver buoyantPimpleFoam.
• This family of solvers is specifically formulated for buoyancy driven flows and HVAC
applications.
• When we deal with buoyant flows, we also need to define the gravity vector. This is done in the
dictionary constant/g.
• As the flow is compressible, we need to define the thermodynamical properties of the working
fluid.
• This is done in he 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.
• As an exercise, try to use the different formulations of the energy equation and compare the
solutions.
• Alternatively, you can use the solver buoyantBoussinesqPimpleFoam, which instead of
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
case directory.
938
Compressible flows hands-on tutorials
$PTOFC/advanced_physics/compressible/supersonic_cyl
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
939
Compressible flows hands-on tutorials
2D supersonic cylinder – Shock waves
• Shock waves are strong discontinuities that need to be treated using high resolution
schemes.
• Additionally, the non-orthogonality add extra complications to this problem.
940
Compressible flows hands-on tutorials
2D supersonic cylinder – Shock waves
941
Compressible flows hands-on tutorials
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.
• This is done in the PIMPLE block of the dictionary fvSolution ( transonic yes; ).
• You will find the instructions of how to run the cases in the file README.FIRST
located in the case directory.
942
Roadmap
943
A crash introduction to moving bodies OpenFOAM®
Prescribed motion with multiple bodies Layering with mesh zones interface
http://www.wolfdynamics.com/training/dynamicMeshes/meshMotion1 http://www.wolfdynamics.com/training/dynamicMeshes/layeringMesh.gif944
A crash introduction to moving bodies OpenFOAM®
• Setting moving bodies simulations is not so different from what we have done so far.
• The main difference is that we must assign a motion type to a surface patch, a cell
region, or the whole domain.
946
A crash introduction to moving bodies OpenFOAM®
947
A crash introduction to moving bodies OpenFOAM®
• You will find the source code of the prescribed patch motion in the directory:
• OpenFOAM-6/src/fvMotionSolver/pointPatchFields/derived
• You will find the source code of the restraints/constraints of rigid body motion solvers
in the directory:
• OpenFOAM-6/src/sixDoFRigidBodyMotion/sixDoFRigidBodyMotion
948
Moving bodies hands-on tutorials
$PTOFC/advanced_physics/sliding_meshes_MRF/CSTR
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
949
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
950
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• We already created this mesh during the meshing module.
• We will only address the differences in meshing for 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
(fix region)s
951
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• In the MRF approach, the governing equations are solved in a relative rotating frame
in the selected rotating zone.
• Additional source terms that model the rotation effect are taken into account.
• You select the rotating zone and set the rotation properties in the dictionary
constant/MRFProperties.
• In this case, the mesh is conforming.
Shaft
type rotatingWallVelocity;
origin (0 0 0);
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);
Impeller
type movingWallVelocity;
value uniform (0 0 0); Inner region generated during
meshing - MRFProperties
952
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• In the sliding meshes approach, the selected rotating region is physically rotating.
• As the meshes are non-conforming, the solution between the rotating region and the
fix region must be interpolated using arbitrary mesh interface.
• In the sliding meshes approach, is not enough to only identify the rotating region.
• We also need to create the interface patches between the fix zone and the rotating
zone.
Shaft
type rotatingWallVelocity;
origin (0 0 0);
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);
Impeller
type movingWallVelocity;
value uniform (0 0 0); Inner region – dynamicMeshDict
953
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
Shaft
type rotatingWallVelocity;
origin (0 0 0);
axis (0 0 1);
omega constant 12.566370;
value uniform (0 0 0);
Impeller
type movingWallVelocity;
value uniform (0 0 0); Inner region and arbitrary mesh
interface
cellZone cell_inner_volume;
dynamicFvMesh dynamicMotionSolverFvMesh; active yes;
motionSolverLibs ( "libfvMotionSolvers.so" );
solver solidBody; // Fixed patches (by default they move’ with the MRF zone)
cellZone cell_inner_volume; nonRotatingPatches ();
solidBodyMotionFunction rotatingMotion;
origin (0 0 0); origin (0 0 0);
axis (0 0 1); axis (0 0 1);
omega constant 12.566370; omega constant 12.566370;
954
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
• For siding meshes, we need to create separated regions.
• In this case, to create the two regions we proceed as follows,
• In step 1, we split the mesh in regions using the baffles (faceZone), created during the meshing
stage.
• We also create the cyclicAMI patches AMI1 and AMI2.
• At this point we have two regions and one zone. However, the two regions are stich together
via the patches AMI1 and AMI2.
• In step 2, we topologically split the patches AMI1 and AMI2. As we removed the link between
AMI1 and AMI2, the regions are free to move.
955
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
baffles
{
rotating Name of the baffle group
{
type faceZone; Use faceZone
zoneName face_inner_volume; Face to use to construct the AMI patches.
The name was defined in snappyHexMeshDict
patches
{
master Parameters for the master patch
{
name AMI1; Name of the master patch (user defined)
Boundary condition type cyclicAMI;
for sliding grids matchTolerance 0.0001;
neighbourPatch AMI2; Neighbour patch (slave patch or AMI2)
transform 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
share a common face 956
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
http://www.wolfdynamics.com/training/movingbodies/image8.gif
• At this point the mesh is ready to use. You can visualize the mesh using
paraFoam.
• If you use checkMesh, it will report that there are two regions.
• In the dictionary constant/dynamicsMeshDict we set which region will
move and the rotation parameters.
• To preview the region motion, in the terminal type:
• $> moveDynamicMesh
• To preview the region motion and check the quality of the AMI interfaces, in
the terminal type:
• $> moveDynamicMesh -checkAMI -noFunctionObjects
Calculating AMI weights between owner patch: AMI1 and neighbour patch: AMI2
Number of faces in
AMI: Creating addressing and weights between 2476 source faces and 2476 target faces the AMI patches
AMI: Patch source sum(weights) min/max/average = 0.94746705, 1.0067199, 0.99994232 AMI1 patch weights
AMI: Patch target sum(weights) min/max/average = 0.94746692, 1.0004497, 0.99980782 AMI2 patch weights
…
…
…
959
Moving bodies hands-on tutorials
Continuous stirring tank reactor – Sliding meshes and MRF
960
Moving bodies hands-on tutorials
$PTOFC/advanced_physics/prescribed_motion/oscillatingCylinder
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
961
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
Moving boundary
http://www.wolfdynamics.com/training/movingbodies/image10.gif
962
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
• In the dictionary constant/dynamicMeshDict we select the mesh morphing
method and the boundary patch that it is moving (lines 21 and 25, respectively).
• There are many mesh morphing methods implemented in OpenFOAM®.
• Mesh morphing is based in diffusing or propagating the mesh deformation all over the
domain.
• You will need to find the best method for your case.
• But in general, the setup used in this case works fine most of the times.
37 in
38 {
39 type fixedValue;
40 value uniform (0 0 0);
41 }
42 cylinder
43 {
44 type oscillatingDisplacement;
45 amplitude ( 0 1 0 );
46 omega 6.28318;
47 value uniform ( 0 0 0 ); Dummy value for paraview
48 }
964
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
• 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.
• This is done in the dictionary 0/U.
41 cylinder
42 {
43 type movingWallVelocity;
44 value uniform (0 0 0);
45 }
• And as usual, you will need to adjust the numerics according to your physics.
• In this case we need to solve the new fields cellDisplacement and diffusivity, which
are related to the mesh motion and morphing.
• In the dictionary fvSolution, you will need to add a linear solver for the field
cellDisplacement.
• In the dictionary fvSchemes, you will need to add the discretization schemes related
to the mesh morphing diffusion method, laplacian(diffusivity, cellDisplacement).
965
Moving bodies hands-on tutorials
Oscillating cylinder – Prescribed motion
966
Moving bodies hands-on tutorials
$PTOFC/advanced_physics/rigid_body_motion/floatingBody
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
967
Moving bodies hands-on tutorials
Floating body – Rigid body motion
ime/ s
http://www.wolfdynamics.com/training/movingbodies/image11.gif
t v s o ientation u (acos( ) /pi/ )
position
c
ime/ s
http://www.wolfdynamics.com/training/movingbodies/image12.gif
23 sixDoFRigidBodyMotionCoeffs
24 {
25 patches (floatingObject); Moving patch
26
Mesh deformation limits.
27 innerDistance 0.1;
The mesh will not be deformed in the fringe located within
28 outerDistance 0.4;
innerDistance and outerDistance (distance normal to the wall)
33 centreOfMass (0.5 0.5 0.5);
34 mass 5; Physical properties of the body
35 momentOfInertia (0.08 0.08 0.1);
innerDistance
Set it to zero if you do not want to apply mesh morphing to the inner region 970
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• The dictionary constant/dynamicMeshDict (continuation).
50 constraints
51 {
55 fixedAxis
56 {
57 sixDoFRigidBodyMotionConstraint axis;
58 axis (0 1 0);
59 } Motion constraints
If you do not give any
63 fixedLine constraint, the body is free
64 { to move in all directions.
65 sixDoFRigidBodyMotionConstraint line;
66 centreOfRotation (0.5 0.5 0.5);
67 direction (0 0 1);
68 }
70 }
Body restraints
72 restraints
Restraints can be used to
73 {
damp the acceleration of the
body.
76 }
In this case, we are not
using restraints
78 }
971
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• In the dictionary 0/pointDisplacement we select the body motion.
• For rigid body motion, the body motion is computed by the solver, therefore, we use
the boundary condition calculated.
33 floatingObject
34 {
35 type calculated;
36 value uniform (0 0 0);
37 }
• 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.
• This is done in the dictionary 0/U.
33 floatingObject
34 {
35 type movingWallVelocity;
36 value uniform (0 0 0);
37 }
972
Moving bodies hands-on tutorials
Floating body – Rigid body motion
• And as usual, you will need to adjust the numerics according to your physics.
• In the case directory, you will find the script extractData.
• This script can be used to extract the position of the body during the
simulation.
• In order to use the extractData script, you will need to save the log file of
the simulation.
• At this point, we are ready to run the simulation.
• We will use the solver interDyMFoam.
• You will find the instructions of how to run the cases in the file
README.FIRST located in the case directory.
973
Roadmap
974
A crash introduction to source terms OpenFOAM®
975
A crash introduction to source terms OpenFOAM®
Set of cell
Point selection
976
A crash introduction to source terms OpenFOAM®
$PTOFC/advanced_physics/source_terms/filter/porous_source
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
978
Source terms hands-on tutorials
Filter source term
• In this case we are going to use the source term explicitPorositySource.
• Using this source term we can apply a porous region (e.g., Darcy-Forchheimer) in the
cell selection.
• The source term is activated after 2 seconds of simulation time.
Set of cell
(filter)
http://www.wolfdynamics.com/training/sourceterms/image1.gif 979
Source terms hands-on tutorials
Filter source term
system/fvOptions
• The source terms can be selected in the
17 filter1
18 {
dictionary fvOptions, and they can be modified
19 type explicitPorositySource; on-the-fly.
20 active yes;
22 explicitPorositySourceCoeffs • In this case we are using the source term
23 {
25 timeStart 2; explicitPorositySource (line 19).
26 duration 5;
28 selectionMode cellZone; • Using this source term we can apply a porous
29 cellZone filter; region (of the type Darcy-Forchheimer) in the cell
31 type DarcyForchheimer;
selection (line 28).
38 DarcyForchheimerCoeffs
39 { • The source term is used in a cellZone (line 28)
41 d (5000000 5000000 5000000); named filter (line 29), this zone must be created
44 f (0 0 0);
46 coordinateSystem at meshing time or using the utility topoSet.
47 {
49 type cartesian; • In lines 38-60, we define the input parameters of
50 origin (0 0 0);
52 coordinateRotation
the model.
53 {
54 type axesRotation;
• In this case, the coefficients f and d are
55 e1 (1 0 0); resistance/impermiability coefficients, and e1 and
56 e2 (0 1 0);
57 }
e2 are the vectors that are used to specify the
59 } porosity.
60 }
61 }
62 }
980
Source terms hands-on tutorials
Filter source term
system/topoSetDict
• To create the cellZone used in fvOptions, we
first create a cellSet.
• The set of cells (cellSet) is constructed using the
utility topoSet.
• This utility reads the dictionary topoSetDict,
which is located in the directory system.
982
Source terms hands-on tutorials
Filter source term
983
Roadmap
984
Scalar transport pluggable solver
985
Scalar transport pluggable solver
enabled true;
writeControl outputTime;
Number of corrector iterations.
log yes; It is recommended to do t least one iteration.
nCorr 1;
Diffusion coefficient.
D 0; If turbulent modeling is in use, you can define the
//alphaD 0; laminar diffusion coefficient alphaD and the turbulent
//alphaDt 0; diffusion coefficient alphaDt
Boundary conditions
0/s1
• Assuming that you named the new scalar s1, you
dimensions [0 0 0 0 0 0 0]; will need to define the boundary conditions and
initial conditions for the field s1.
internalField uniform 0;
• This is done in the dictionary 0/s1.
boundaryField
{ • In this case, the scalar is entering in the patch
walls
{ inlet with a value of 1 (this is a concentration
type zeroGradient; therefore it has no dimensions).
}
inlet
• The initial concentration of the scalar is zero.
{
type fixedValue;
value uniform 1;
}
outlet
{
type inletOutlet;
inletValue uniform 0;
value uniform 0;
}
}
987
Scalar transport pluggable solver
system/fvSchemes system/fvSolution
gradSchemes s1
{ {
default Gauss linear; solver smoothSolver;
grad(s1) cellLimited Gauss linear 1; smoother symGaussSeidel;
} tolerance 1e-08;
relTol 0;
}
divSchemes
{
default none;
div(phi,U) Gauss linearUpwindV default;
div(phi,s1) Gauss vanLeer;
}
988
Scalar transport pluggable solver hands-on tutorials
$PTOFC/advanced_physics/source_terms/2Delbow_passive_scalar
• In the case directory, you will find the README.FIRST file. In this file, you will find the general instructions of
how to run the case. In this file, you might also find some additional comments.
• You will also find a few additional files (or scripts) with the extension .sh, namely, run_all.sh,
run_mesh.sh, run_sampling.sh, run_solver.sh, and so on. These files can be used to run the case
automatically by typing in the terminal, for example, sh run_solver.
• We highly recommend to open the README.FIRST file and type the commands in the terminal, in this way
you will get used with the command line interface and OpenFOAM® commands.
• If you are already comfortable with OpenFOAM®, use the automatic scripts to run the cases.
989
Scalar transport pluggable solver hands-on tutorials
Scalar transport in an elbow – Internal geometry
• Notice that we are adding two scalars, s1 and s2.
S1
U → (2 0 0)
http://www.wolfdynamics.com/training/sourceterms/image2.gif
S2
U → (0 3 0)
http://www.wolfdynamics.com/training/sourceterms/image3.gif 990
Scalar transport pluggable solver hands-on tutorials
Scalar transport in an elbow – Internal geometry
991
This is the end
Training material
You can download the training material in the following link:
http://www.wolfdynamics.com/tutorials.html?layout=edit&id=50