You are on page 1of 31

CFD with OpenSource software

A course at Chalmers University of Technology


Taught by Håkan Nilsson

Project work:

Modelling of chemical batch reactor

Developed for OpenFOAM-2.4x

Peer reviewed by:


Author:
Sankar Menon
Rajukiran Antham
Håkan Nilsson

Disclaimer: This is a student project work, done as part of a course where OpenFOAM and some
other OpenSource software are introduced to the students. Any reader should be aware that it
might not be free of errors. Still, it might be useful for someone who would like learn some details
similar to the ones presented in the report and in the accompanying files. The material has gone
through a review process. The role of the reviewer is to go through the tutorial and make sure that
it works, that it is possible to follow, and to some extent correct the writing. The reviewer has no
responsibility for the contents.

January 26, 2016


CONTENTS CONTENTS

Contents
1 Introduction 2

2 Meshing 2
2.1 Meshing Procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.1 Stator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.2 Rotor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.3 Combining both Meshes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3 Setting up case using MRF 10


3.1 Pre-processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

4 Setting up case using sliding grid 17


4.1 Pre-processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

5 Scalar Transport equation 19


5.1 Implementation in simpleFoam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
5.2 Running MRF case with modified solver . . . . . . . . . . . . . . . . . . . . . . . . . 22
5.3 Implementation in pimpleDyMFoam . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

6 Conclusions 27
6.1 Meshing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
6.2 Physical Modelling of rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

7 Appendix 28

i
CONTENTS CONTENTS

Learning outcomes
• Using cfMesh to generate Mesh for this case and learning how to work with cfMesh.
• Physical modelling of rotation using MRF.
• Physical modelling of rotation using mesh motion.

• Implementation of scalar transport equation representing concentration.


• Implementation of probes at point locations to check mixing statistics.

1
2 MESHING

1 Introduction
The purpose of the project is to look at the suitability, pros and cons for alternative techniques
available in OpenFOAM for modelling of rotating impeller and static baffles in a reactor. One more
purpose is also to evaluate the use of cfMesh to generate mesh for this application.

In Chemical engineering, chemical reactors are the vessels designed to contain chemical reactions.
Vessels which are widely used in the process industries are generally called batch reactors. A typical
batch reactor consists of a tank with an agitator and a heating or cooling system. They may also
contain static baffles depending on the application. These vessels may vary in size from less than 1
litre to 15000 litres. Batch reactors are used for a variety of operations such as solids dissolution,
product mixing, chemical reactions, batch distillation and crystallization.

In this tutorial a lab scale reactor is used. This vessels are in sizes of about 500 to 1000 millilitres.
They are used in production systems which are used for preparing small volumes of medical sub-
stances. The difficulty in modelling this kind of reactors is modelling of rotation. In OpenFOAM
modelling of rotation is handled using three techniques Single reference frame (SRF), Multiple refer-
ence frame and Sliding grid technique. In this tutorial MRF and Sliding grid technique are used. In
MRF method a separate rotating region is defined and modelled using rotating frame of reference.
Most OpenFOAM steady state solvers are capable of handling MRF using fvOptions. In Sliding grid
technique, reactor is divided into two regions stationary and a rotating region. The rotating region
is rotated using sliding grid technique and therefore transient problems with strong rotor-stator
interaction can be solved.

Figure 1 shows the geometry of batch reactor. It consists of a reactor vessel of radius 50 mm and
height 90mm. The reactor Vessel contains a stationary baffle rod with a baffle wing attached to it.
Impeller is attached to a rotating shaft . The small rotating shaft is attached to a long shaft which
is stationary. The region around the impeller is the MRF region.

Figure 1: Geometry of reactor

2 Meshing
cfMesh was used to generate mesh. cfMesh is an open source library for automatic mesh generation
built on top of OpenFOAM. It is compatible with all recent versions of OpenFOAM and FOAM-
extend. cfMesh is currently available for following work flows. The mesher operates on triangulated
geometry inputs in one of the formats fms, ftr and stl. It builds meshes using the choice of basic

2
2 MESHING

a) b)

Figure 2: Geometry divided into two regions a) stator and b) rotor

meshing strategies:

• CartesianMesh - Used to generate 3D hexahedral cells with polyhedral cells in the transition
regions between the cells of different sizes. The meshing process can be started by typing
cartesianMesh in the console.
• Cartesian2DMesh - Used to generate 2D meshes. By default cfMesh will generate a bound-
ary layer which can be further refined. Meshing process can be started by typing cartesian2DMesh
in the console.

• Tetrahedral - Used to generate tetrahedral cells. By default it does not generate any bound-
ary layer but such can be generated later using refinement settings. The meshing process can
be started by typing tetMesh in the console.
• Polyhedral - Used to generate meshes with arbitrary polyhedral cells. It can be used for
poor geometries. The meshing process can be started by typing pMesh in console.

All sharp features in the geometry must be defined prior to the meshing process. The edges at the
border between the two patches are treated as sharp features in the meshing process. This sharp
edges are captured only if there is an edge of a triangulation surface at that location.

An STL file describes a raw unstructured triangulated surface by the unit normal vertices of the
triangles using a threedimensional Cartesian coordinate system. They describe only the surface
geometry without any representation of color or texture. The STL file formats specifies both ASCII
and binary representations. Below is an example of STL file in ASCII representation.
solid xx
facet normal 1.954537e-01 8.563388e-01 4.779976e-01
outer loop
vertex -3.547176e+01 -4.186972e+00 1.980803e+01
vertex -3.639162e+01 -3.977019e+00 1.980803e+01
vertex -3.603364e+01 -4.528674e+00 2.064995e+01
endloop
endfacet
endsolid xx

In the above file xx is a patch name. A patch always starts with solid Name and ends with
endsolid Name. Giving name for the patch is not compulsory. Two STL files can be joined
together by just copying the contents of one file to other. In the below example, an STL file which
contains patch YY is added to the above STL file.

solid xx
facet normal 1.954537e-01 8.563388e-01 4.779976e-01

3
2.1 Meshing Procedure 2 MESHING

outer loop
vertex -3.547176e+01 -4.186972e+00 1.980803e+01
vertex -3.639162e+01 -3.977019e+00 1.980803e+01
vertex -3.603364e+01 -4.528674e+00 2.064995e+01
endloop
endfacet
endsolid xx
solid YY
facet normal 4.201081e-01 8.723634e-01 2.499825e-01
outer loop
vertex -3.701545e+01 -4.185124e+00 2.064995e+01
vertex -3.761253e+01 -4.157825e+00 2.155811e+01
vertex -3.662183e+01 -4.634923e+00 2.155811e+01
endloop
endfacet
endsolid YY

We can also split an STL file into different STL files by just copying all triangles of a single patch
to a new text file. Two patches can also be combined into a single patch by just copying triangles
of a patch into other patch.

The CartesianMesh strategy is used to generate the mesh in this particular case. cfMesh generates
the mesh based on the settings given in the meshDict file which is present in the system directory.
cfMesh requires only two mandatory settings to start the meshing process:
• surfaceFile - this files points to the file that contains triangulated geometry and the path of
the file is same as the path of the case directory.
• maxCellSize - this represents the default cell size used for the meshing. It is the maximum cell
size generated in the domain.
cfMesh has number of refinement settings that can be used to generate a good mesh. All the refine-
ment settings are not explained in the report. They are explained in detail in the cfMesh user guide.

cfMesh generates the mesh in a single domain. If there are multiple disconnected domains, cfMesh
keeps the region which contains the most number of cells and removes the cells of the other region(s).
In the case of a rotorstator simulations it is useful, and in some cases necessary, to generate the mesh
in more than one region. Therefore the mesh in this case is generated as a single mesh region for
rotor and a single mesh region for the stator. These regions are later merged to form the entire mesh.

Given geometry is divided into two regions stator and rotor. Below Table shows how different parts
in the geometry are divided into two regions. This can also be seen in Figure 2.

Stator Rotor
baffle rod, baffle wing, stationary Impeller, rotating shaft, MRF
shaft, reactor vessel and MRF interface
interface
cfMesh is not installed in OpenFOAM-2.4 X and FOAM-extend 3.1. It can be easily installed by
following the instructions given in Appendix.

2.1 Meshing Procedure


The following section explains the meshing procedure for the given geometry. As discussed above
geometry is divided into two regions. STL files used for generating the mesh are provided along
with other files.

4
2.1 Meshing Procedure 2 MESHING

2.1.1 Stator
The following section explains the meshing procedure for stator. This tutorial is based on asmoOctree
tutorial in cfMesh tutorials. you can copy asmoOctree tutorial to your run directory by using the
command
run
cp-r \$FOAM_TUTORIALS/mesh/cartesianMesh/asmoOctree/ stator

It should be noted that cfMesh tutorials are not copied to OpenFOAM tutorials directory while
installing it. This should be done manually.

cd stator
rm -r geom.stl
rm -r Allclean
rm -r Allrun
copy stator_updated.stl file from the given files to this directory
vi system/meshDict

Below is the meshDict file of stator. you need to paste this in system/meshDict file. Comments in
the meshDict file will give an idea on different things used in the meshDict file.
Below table gives which part corresponds to which patch. As you can see from table reactor vessel
is divided into two patches WALL SURFACE and WALL REACTOR and MRF interface is divided
into three patches TOP,BOTTOM, CYLINDER.

Part Patch
reactor vessel WALL SURFACE, WALL REACTOR
baffle wing WALL BAFFLE WING,
baffle rod WALL BAFFLE ROD
stationary shaft WALL STAT SHAFT
MRF interface TOP, CYLINDER, BOTTOM
renameBoundary is used in the meshDict file to change the patch names and types while generating
meshes. Here TOP, BOTTOM and CYLINDER patches are renamed to tops, bottoms and cylinders.
All other patches are combined into a single patch called stator. localRefinement is used to refine
cells at that particular patch. In the meshDict file maxcellSize is specified in meters because cfMesh
assumes that the geometry is in meters. The mesh generated will be scaled to required dimensions
later.
surfaceFile "stator_updated.stl";
maxCellSize 2; // [m]
localRefinement //allows for local refinement regions at the boundary
{
WALL_SURFACE // patch
{
cellSize 1.2; // requested cell size
}
WALL_STAT_SHAFT
{
cellSize 1.2;
}

WALL_REACTOR
{
cellSize 2;
}

5
2.1 Meshing Procedure 2 MESHING

WALL_BAFFLE_WING
{
cellSize 1;
refinementThickness 1; // thickness of refinement zone
}
WALL_BAFFLE_ROD
{
cellSize 1;
}
TOP
{
cellSize 2;
}
CYLINDER
{
cellSize 2;
//refinementThickness 1;
}
BOTTOM
{
cellSize 2;
//refinementThickness 1;
}
}

boundaryLayers //Used to generate boundary layers


{
patchBoundaryLayers //Used to specify boundary layers for individual patches
{
WALL_BAFFLE_WING
{
nLayers 4; // number of layers
thicknessRatio 1.1; // ratio between the thickness of two successive layers
allowDiscontinuity 1;//ensures that number of layers of a patch do not spread to other patches
}
}

renameBoundary // used to rename patches


{
defaultName stator; //default name for all patches
defaultType wall; //default type for all patches
newPatchNames // new patch names
{

TOP
{
newName tops; //new Name
type wall; //new Patch Type
}
BOTTOM
{
newName bottoms;
type wall;
}

6
2.1 Meshing Procedure 2 MESHING

CYLINDER
{
newName cylinders;
type wall;
}
}
}
The meshing process can be initiated by typing cartesianMesh in the console.
cartesianMesh
improveMeshQuality
checkMesh
improveMeshQuality is used to improve the mesh quality and checkMesh is used to check the quality
of mesh.

2.1.2 Rotor
The meshing procedure for rotor is similar to stator. asmoOctree tutorial should be copied to run
directory.

run
cp-r $FOAM_TUTORIALS/mesh/cartesianMesh/asmoOctree/ stator
cd stator
rm -r geom.stl
rm -r Allclean
rm -r Allrun
copy rotor_updated.stl file from the given files to this directory
vi system/meshDict

Below table shows which part corresponds to which patch. renameBoundary is used in meshDict
file to rename the patches. New patch Names can also be seen in below table

Part Patch New Patch name


Impeller WALL IMPELLER impeller
rotating shaft WALL ROT SHAFT, rshaft
MRF interface TOP, CYLINDER, TOPR, CYLINDERR,
BOTTOM BOTTOMR
Below is meshDict file of rotor.

surfaceFile "rotor_updated.stl";
maxCellSize 1;
localRefinement
{
WALL_IMPELLER
{
cellSize 0.8;
}
WALL_ROT_SHAFT
{
cellSize 0.5;
}

TOP

7
2.1 Meshing Procedure 2 MESHING

{
cellSize 0.8;
}
BOTTOM
{
cellSize 0.8;
}
CYLINDER
{
cellSize 0.8;
}
}
boundaryLayers
{
patchBoundaryLayers
{
WALL_IMPELLER
{
nLayers 3;
thicknessRatio 1.2;

}
}
}

renameBoundary
{
newPatchNames
{

WALL_IMPELLER
{
newName impeller;
type wall;
}
WALL_ROT_SHAFT
{
newName rshaft;
type wall;
}
CYLINDER
{
newName CYLINDERR;
type wall;
}
BOTTOM
{
newName BOTTOMR;
type wall;
}
TOP
{
newName TOPR;
type wall;

8
2.1 Meshing Procedure 2 MESHING

}
}
}

The meshing process can be initiated by typing cartesianMesh in the console.


cartesianMesh
checkMesh
Figure 3 shows pictures of mesh generated in both stator and rotor regions.

a) b)

Figure 3: Mesh generated using cfMesh in two separate regions a) stator and b) rotor

2.1.3 Combining both Meshes


Now mesh generated in both regions should be combined into a single mesh. This can be done using
mergeMeshes utility in OpenFOAM.

run
cp -r rotor Project
cp -r stator Project
cd Project
mergeMeshes stator rotor
rm -r rotor
cd stator
rm -r constant/polyMesh
mv 1/polyMesh constant/
rm -r 1

In the above commands stator is the master case and rotor is the case that has the mesh to be
merged into the stator mesh. The merged mesh ends up in the master case, in a time directory
corresponding to startTime+deltaT. There is also a flag -overwrite that will force mergeMeshes to
directly rewrite to the constant/polyMesh directory in master case.

run
cp -r rotor Project
cp -r stator Project
cd Project
mergeMeshes -overwrite stator rotor

9
3 SETTING UP CASE USING MRF

The original geometry was generated in millimeters, but cfMesh and OpenFOAM assume that the
geometry is in meters. Therefore the mesh is transformed to meters using
transformPoints -scale '(0.001 0.001 0.001)'

Now we have a domain with two separate regions which are not coupled to each other. This can be
seen using the checkMesh command.
checkMesh
Figure 4 is a clip with normal in the Z-direction, at the center of the rotor. Both stator and rotor
regions can be seen in the figure.

Figure 4: combined mesh after using mergeMeshes

3 Setting up case using MRF


In MRF approach fluid flow is computed using different reference frames. Rotating zone is solved
in the rotating frame and stationary zone is solved in the stationary frame. This approach accounts
the rotation of the rotor without having to physically rotate any part of the mesh. The approach is
also called the frozen rotor technique. In MRF approach cells in the rotating region should be kept
in a separate cellZone. The Navier-Stokes equations are solved in a relative reference frame, as

∂(ur ) p
+ ∇ · (ur ur ) + 2Ω × ur + (Ω × (Ω + r)) = −∇( ) + ∇ · (υ∇ur ), (1)
∂t ρ
where p, ρ and υ denote pressure, density and kinematic viscosity respectively. The relative velocity
ur is defined by

ur = u − Ω ∗ r, (2)
and Ω represents the angular velocity.

equ(1) reduces to equ(3) if Ω = 0, which is in the stationary region.

∂(ρu)
+ ∇ · (ρuu) = −∇p + ∇ · (µ∇u) (3)
∂t
where µ represents dynamic viscosity.
In this case mesh is generated in two regions and merged together using mergeMeshes utility. The
connection between two regions is handled using a mesh interface. OpenFOAM supports different
mesh interfaces like General Grid interface (GGI), mixing plane and Arbitrary Mesh Interface (AMI).
GGI and mixing plane are used only in FOAM-extend. In this case AMI (Arbitrary Mesh Interface) is
used. AMI operates by projecting one of the patch faces onto the other. From these weighting factors
will be calculated, to determine how an AMI boundary cell should couple to the AMI boundary cells
on the other side of the interface. This weighting factors should be close to 1 always. AMI interface
can be used even if the patches are not perfectly conformal, but it is better to keep both patches as
conformal as possible.

10
3.1 Pre-processing 3 SETTING UP CASE USING MRF

3.1 Pre-processing
The MRF technique is implemented in different ways in OpenFOAM and FOAM-extend. Rotation
is defined in system/fvOptions in OpenFOAM and in constant/MRFZones in Foam-extend. Below
table shows how the MRF technique is implemented in OpenFOAM and FOAM-extend

OpenFOAM FOAM-extend
simpleFoam + fvOptions MRFsimpleFoam + MRFZones
This tutorial is based on the mixerVessel2D tutorial in OpenFOAM-2.4.x. This tutorial can be
copied to your run folder by using the command
cp -r $FOAM_TUTORIALS/incompressible/simpleFoam/mixerVessel2D $FOAM_RUN

run
cp -r Project ProjectMRF
cd ProjectMRF
cd stator
vi constant/polyMesh/boundary

Interface between patches of rotor and stator region should be coupled using AMI interface, this can
be done by editing boundary file in constant/polyMesh/boundary

9
(
tops
{
type cyclicAMI;
inGroups 1(cyclicAMI);
nFaces 1224;
startFace 1174428;
matchTolerance 0.0001;
transform noOrdering;
neighbourPatch TOPR; //neighbor patch on rotor side
}
bottoms
{
type cyclicAMI;
inGroups 1(cyclicAMI);
nFaces 968;
startFace 1175652;
matchTolerance 0.0001;
transform noOrdering;
neighbourPatch BOTTOMR; //neighbor patch on rotor side
}
cylinders
{
type cyclicAMI;
inGroups 1(cyclicAMI);
nFaces 1376;
startFace 1176620;
matchTolerance 0.0001;
transform noOrdering;
neighbourPatch CYLINDERR; //neighbor patch on rotor side
}
stator

11
3.1 Pre-processing 3 SETTING UP CASE USING MRF

{
type wall;
inGroups 1(wall);
nFaces 27664;
startFace 1177996;
}
impeller
{
type wall;
inGroups 1(wall);
nFaces 25320;
startFace 1205660;
}
rshaft
{
type wall;
inGroups 1(wall);
nFaces 704;
startFace 1230980;
}
CYLINDERR
{
type cyclicAMI;
inGroups 1(cyclicAMI);
nFaces 18856;
startFace 1231684;
matchTolerance 0.0001;
transform noOrdering;
neighbourPatch cylinders; //neighbor patch on stator side
}
BOTTOMR
{
type cyclicAMI;
inGroups 1(cyclicAMI);
nFaces 14448;
startFace 1250540;
matchTolerance 0.0001;
transform noOrdering;
neighbourPatch bottoms; //neighbor patch on stator side
}
TOPR
{
type cyclicAMI;
inGroups 1(cyclicAMI);
nFaces 14432;
startFace 1264988;
matchTolerance 0.0001;
transform noOrdering;
neighbourPatch tops; //neighbor patch on stator side
}
)

In the above boundary file tops, bottoms and cylinders are the AMI interfaces on the stator side
and TOPR, BOTTOMR, and CYLINDERR are the AMI interfaces on the rotor side. Each patch

12
3.1 Pre-processing 3 SETTING UP CASE USING MRF

should be given a corresponding neighbour patch. Corresponding changes are also to be done in the
0 directory.

For example 0/U file is written as

dimensions [0 1 -1 0 0 0 0];

internalField uniform (0 0 0);

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

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

TOPR
{
type cyclicAMI;
value $internalField;
}

BOTTOMR
{
type cyclicAMI;
value $internalField;
}
CYLINDERR
{
type cyclicAMI;
value $internalField;
}

tops
{
type cyclicAMI;
value $internalField;
}
bottoms
{
type cyclicAMI;

13
3.1 Pre-processing 3 SETTING UP CASE USING MRF

value $internalField;
}

cylinders
{
type cyclicAMI;
value $internalField;
}
}

All the files in 0 directory are provided. They can be copied directly from there. This can also be
done by copying the O/files from mixerVessel2D tutorial and doing the corresponding changes.

Next step is to create a cellZone for defining the rotation of the impeller. cfMesh does not automat-
ically create cell sets and cell zones while generating meshes. This can be done by using the setSet
and topoSet utilities in OpenFOAM and Foam-extend. There are a number of options available in
both setSet and topoSet to do mesh manipulations. In this case both setSet and topoSet are used
to get an idea how both of them work. Since we already have a cellSet of the rotor region which is
written when checkMesh is done, we can use it directly to create the rotor cellZone using

setSet
cellZoneSet rotor new setToCellZone region1
quit

In the above command rotor is the name of the cellZone and region1 is the cell set which contains
all the cells of the rotor region.
The next step is to create a faceSet containing all the faces of the AMI interfaces.This is done using
the topoSet utility and a topoSetDict file. This file is located in system/topoSetDict, and should in
this contain

actions
(

{
name AMI; // Get both sides of AMI
type faceSet;
action new; // Get all faces in cellSet
source patchToFace;
sourceInfo
{
name bottoms;
}
}

{
name AMI;
type faceSet;
action add; //Add faces to faceset AMI
source patchToFace;
sourceInfo
{
name tops;
}
}
{

14
3.1 Pre-processing 3 SETTING UP CASE USING MRF

name AMI;
type faceSet;
action add;
source patchToFace;
sourceInfo
{
name cylinders;
}
}
{
name AMI;
type faceSet;
action add;
source patchToFace;
sourceInfo
{
name CYLINDERR;
}
}
{
name AMI;
type faceSet;
action add;
source patchToFace;
sourceInfo
{
name BOTTOMR;
}
}
{
name AMI;
type faceSet;
action add;
source patchToFace;
sourceInfo
{
name TOPR;
}
}

);

The above topoSetDict file is provided along with the case files. In the above topoSetDict file ini-
tially faceSet with name AMI is created which contains all the faces of patch bottoms. This is done
by using the action command new. After that all the faces from other patches are added to faceSet
AMI using the action command add.

topoSet
The settings for the rotation component in OpenFOAM-2.4.x is defined using the system/fvOptions
file. Patches which are adjacent to rotating patches and which are non-rotating should be included
in nonRotatingpatches () . As you can see in the below fvOptions file tops, bottoms, and cylinders
patches are non-rotating stator AMI interface patches. Angular velocity of 40 rad/sec along Z-axis

15
3.2 Results 3 SETTING UP CASE USING MRF

is given for the rotating region.


Below fvOptions file is provided along with the case files.

MRF1
{
type MRFSource;
active true;
selectionMode cellZone;
cellZone rotor;

MRFSourceCoeffs
{
nonRotatingPatches (tops bottoms cylinders);
active true;
origin (0 0 0);
axis (0 0 1);
omega 40; // in rad/sec
}
}

fvSchemes, fvSolution and controlDict can be copied from the given case files to system directory.
This can also be done by copying this files from mixerVessel2D tutorial, but necessary changes should
be done to fvSolution file to implement turbulence model. turbulence properties, RAS properties
and transport properties files should be added to constant directory to implement turbulence model.
This files can be copied from given case files.

Now the set-up for MRF is done and the simulation is started by typing simpleFoam in console.

simpleFoam

3.2 Results

U Magnitude
1.21
1
0.75

0.5
0.25

Figure 5: U magnitude at Z=0.0032 m plane

16
4 SETTING UP CASE USING SLIDING GRID

Figure 6: Vector arrows (Umagnitude) representing flow direction

Figure 5 is a velocity contour at Z=0.0032 m plane. From the figure we can see high velocities near
the tip of the blade which is expected. Velocity magnitude at the tip of the blade is in agreement
with analytical solution which is 1.2 m/s.

V = r ∗ Ω = 0.03 ∗ 40 = 1.2m/s

Figure 6 shows the velocity vectors entering from the top of the impeller and a recirculation region
at the side of the impeller. We can also observe high velocity at the tip of the impeller.

4 Setting up case using sliding grid


The sliding grid method allows adjacent grids to slide relative to each other along the internal inter-
face surface. We need to have two mesh regions and an interface that couples the two regions. Using
this approach the interaction between the stator and rotor can be fully resolved. The pimpleDyM-
Foam solver in OpenFOAM is employed to obtain a unsteady solution. This method takes more
computational time than the MRF technique discussed above. AMI is used as interface between the
stator and rotor patches.

4.1 Pre-processing
The setup used for AMI is very much similar to that of MRF. This is because we are using the same
mesh interface (AMI) between stator and rotor. We can use the same meshes as MRF. The only
change is how the mesh motion is defined. Here mesh motion is defined using a dynamicMeshDict
file which is present in constant directory. Here mesh motion is obtained by using solidBodyMo-
tionFvMesh class which is a sub class of dynamicFvMesh. To start with the case copy the MRF case

run
cp -r ProjectMRF ProjectAMI
cd constant

Below is the dynamicMeshdict file. This file is provided along with the case files. In the dynam-
icMeshDict file cellZone specifies which region to rotate. solidBodyMotionFunction specifies the

17
4.1 Pre-processing 4 SETTING UP CASE USING SLIDING GRID

type of motion. Here angular velocity of 5 rad/sec is taken. Angular velocity should be increased
gradually over time to attain the an angular velocity of 40 rad/sec. The reason behind this is mean
courant number. In order to keep the mean courant number low we need to decrease either time
step or angular velocity for a given mesh.

FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object dynamicMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dynamicFvMesh solidBodyMotionFvMesh;

motionSolverLibs ( "libfvMotionSolvers.so" );

solidBodyMotionFvMeshCoeffs
{
cellZone rotor;

solidBodyMotionFunction rotatingMotion;
rotatingMotionCoeffs
{
origin (0 0 0);
axis (0 0 1);
omega 5; // rad/s
}
}

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

We need to remove constat/fvOptions file from the system directory since we are not defining rotation
using this file. This is not compulsory because we are not using the same solver and pimpleDyM-
Foam won’t use MRF settings from that file.

cd ..
rm -r system/fvOptions

Time step to be used in the simulation can be given in controlDict file. we can use adjustTimeStep
to decrease the time step during the simulation if the mean courant number is increasing more than
1. In this case time step of 1e-4 is used.
copy the below controlDict file to system/controlDict file

FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object controlDict;

18
4.2 Results 5 SCALAR TRANSPORT EQUATION

}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

application pimpleDyMFoam;

startFrom latestTime;

startTime 0;

stopAt endTime;

endTime 5;

deltaT 1e-4;

writeControl adjustableRunTime;

writeInterval 0.01;

purgeWrite 10;

writeFormat ascii;

writePrecision 6;

writeCompression off;

timeFormat general;

timePrecision 6;

runTimeModifiable true;

//adjustTimeStep yes;

maxCo 2;

Now the set-up for sliding grid is done and the simulation is started by typing pimpleDyMFoam in
console.

pimpleDyMFoam

4.2 Results
Figure 7 shows the velocity contours at various time steps. Effect of impeller position on the flow
field can be clearly seen from the figure. Here you can see high velocities near the tip of the impeller.
Compared to MRF case we don’t have high velocities in between impeller blades.

5 Scalar Transport equation


Scalar transport equation representing concentration is implemented to check the mixing properties
of reactor. This is done by introducing a transport equation in the solver.

19
5.1 Implementation in simpleFoam 5 SCALAR TRANSPORT EQUATION

U Magnitude U Magnitude
1.31 1.31
1.2 1.2

0.8 0.8

0.4 0.4

0 0

a) at t=4.925s b) at t=4.935s

U Magnitude U Magnitude
1.31 1.31
1.2 1.2

0.8 0.8

0.4 0.4

0 0

c)at t=4.945s d) at t=4.955s

Figure 7: Velocity contours at Z=0.0032 m

The scalar transport equation representing concentration is


∂C
∂C ∂(ui C) ∂(D ∂x i
)
+ = + S, (4)
∂t ∂xi ∂xi
where C is concentration, D is Diffusion coefficient and S is a source term.

5.1 Implementation in simpleFoam


The scalar transport equation can be implemented done by the following steps.

foam
cp -r --parents applications/solvers/incompressible/simpleFoam $WM_PROJECT_USER_DIR
cd $WM_PROJECT_USER_DIR/applications/solvers/incompressible
mv simpleFoam mysimpleFoam
cd mysimpleFoam
wclean
mv simpleFoam.C mysimpleFoam.C
rm -r SRFSimpleFoam porousSimpleFoam
Allwmake

In the above steps the simpleFoam directory is copied to the user directory and renamed as mysim-
pleFoam. simpleFoam/simpleFoam.C is renamed as mysimpleFoam.C. Now we need to add the
transport equation in mysimpleFoam.C file before runTime.write().

volScalarField alphaEff("alphaEff", turbulence->nu()/Sc + turbulence->nut()/Sct);


solve (fvm::ddt(C)+fvm::div(phi, C)-fvm::laplacian(alphaEff, C));

20
5.1 Implementation in simpleFoam 5 SCALAR TRANSPORT EQUATION

where Sc and Sct are Schmidt’s number and turbulent Schmidt’s number.

Next we should add volumeScalarField C in the createFields.H file. We can copy the same as p and
change p to C, since both are scalar fields. we should also define Sc and Sct, this can be done by
defining it in createFields.H file by adding below code

Info<< "Reading field C\n" << endl;


volScalarField C
(
IOobject
(
"C",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
Info<< "Reading transportProperties\n" << endl;

IOdictionary transportProperties
(
IOobject
(
"transportProperties",
runTime.constant(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
dimensionedScalar Sc
(
transportProperties.lookup("Sc")
)
dimensionedScalar Sct
(
transportProperties.lookup("Sct")
)

This code will look for the value of Sc and Sct in a transportPropoerties file in the constant directory.
We should also change the name of file in Make/files to compile the modified solver, which can be
done by using the command

string="mysimpleFoam.C\nEXE = \$(FOAM_USER_APPBIN)/mysimpleFoam"
printf "%b\n" "$string" > Make/files

Compile with wmake command in mysimpleFoam directory.

wmake

21
5.2 Running MRF case with modified solver 5 SCALAR TRANSPORT EQUATION

5.2 Running MRF case with modified solver


The scalar transport equation can be implemented to the converged solution. In this tutorial MRF
case is used.

run
cp -r ProjectMRF ProjectMRFT
cd ProjectMRFT
cd stator

We need to add a new file C in the last time step, containing

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


| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 2.4.0 |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object C;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [1 -3 0 0 0 0 0];

internalField uniform 0;

boundaryField
{
rshaft
{
type zeroGradient;
}

stator
{
type zeroGradient;
}
impeller
{
type zeroGradient;
}

TOPR
{
type cyclicAMI;
value $internalField;
}

BOTTOMR

22
5.2 Running MRF case with modified solver 5 SCALAR TRANSPORT EQUATION

{
type cyclicAMI;
value $internalField;
}
CYLINDERR
{
type cyclicAMI;
value $internalField;
}

tops
{
type cyclicAMI;
value $internalField;
}
bottoms
{
type cyclicAMI;
value $internalField;
}

cylinders
{
type cyclicAMI;
value $internalField;
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

We should also add a dimensioned scalar in the constant/transportProperties file:


Sc Sc [ 0 0 0 0 0 0 0 ] 0.7; //Schmidt's number
Sct Sct [ 0 0 0 0 0 0 0 ] 0.7; //Turbulent Schmidt's number

We should also add a divergence scheme in system/fvSchemes file for C:


div(phi,C) Gauss linearUpwind Gauss;
We should also define the settings for the solution of the linear system for C in fvSolution:

C
{
solver smoothSolver;
smoother GaussSeidel;
nSweeps 2;
tolerance 1e-08;
relTol 0.1;
}

We need to initialize C and this can be done by using the setFields utility. We can copy the
setFieldsDict file from damBreak tutorial using the following command

cp $FOAM_TUTORIALS/multiphase/interFoam/laminar/damBreak/system/setFieldsDict system

23
5.2 Running MRF case with modified solver 5 SCALAR TRANSPORT EQUATION

The following changes are made to the setFieldsDict file. I used a cylinderToCell option here to pick
up a region to set the field values.

defaultFieldValues
(
volScalarFieldValue C 0
);

regions
(
cylinderToCell
{
p1 (0 0 0.036); // centre of first circle
p2 (0 0 0.043); // centre of second circe
radius 0.035; // radius of cylinder
fieldValues
(
volScalarFieldValue C 1
);
}
);

Now C is initialized by running setFields in console.

setFields
I have introduced probes at different point locations in the reactor vessel to look at the concentration
at those locations over iterations. This is done by using probes utility in OpenFOAM. This is
implemented by adding the following code to the controlDict file.

functions
{
concentraionProbes
{
type probes;
functionObjectLibs ("libsampling.so");
outputControl timeStep;
outputInterval 1;
probeLocations
(
( 0.010 0.010 0.043 ) // Probe(0) probe locations coordinates
( 0.010 -0.010 0.043 ) // Probe (1)
( 0.010 0.010 -0.010 ) // Probe (2)
);
fields // field to plot
(
C
);
}

Now the set-up for case is done and simulation is started by typing mysimpleFoam in console.

mysimpleFoam

24
5.3 Implementation in pimpleDyMFoam 5 SCALAR TRANSPORT EQUATION

5.3 Implementation in pimpleDyMFoam


The implementation of a scalar transport equation in pimpleDyMFoam is similar to that described
for simpleFoam. This is left as an exercise to the reader, but the results will be explained below.

Results
Project AMI case is solved initially till t=4.995 sec to attain convergence. Then the scalar transport
equation is introduced and solved for more 0.65 sec. Concentration is plotted at three probe locations
and plotted over time. Location of the probes are given below

Probe 0 ( 0.010 0.010 0.043 ) //(x y z) coordinates


Probe 1 ( 0.010 -0.010 0.043 )
Probe 2 ( 0.010 0.010 -0.010 )

Figure 8: Concentration vs Time

Figure 8 shows the plot of concentration over time. It can be seen from figure that at Probe 2 the
concentration is zero till t=5.1 sec. This is as expected because Probe 2 is at the top of the reactor.
Concentration at Probe 0 and 1 is decreasing and attaining a uniform value as time passes. It can
also be seen that concentration at Probe 2 is decreasing from t=5.28 sec and reaching a uniform
value. In order to achieve a uniform concentration thought the reactor the simulation should be
continued for more time. This is not done because of time constraints.

Figure 9 shows the concentration contours in a plane normal to Y. At t=4.995s the concentration is 1
in the middle of the reactor. From the figure it can also be seen how the water is moving downwards
in the reactor. This is as expected because the impeller is located close to the bottom of the reactor
vessel. Effect of baffle rod and wing can also be seen from the figures. The concentration at probe
2 is almost zero till 5.345s and increases over time to reach a uniform concentration.

25
5.3 Implementation in pimpleDyMFoam 5 SCALAR TRANSPORT EQUATION

C C
1 0.936
0.8
0.75
0.6
0.5
0.4
0.25
0.2

0 -0.00557 0

a) at t=4.995s b) at t=5.045s

C C
0.687 0.295
0.6
0.2
0.4

0.2 0.1

0 0

c)at t=5.095s d) at t=5.195s

C C
0.245 0.155

0.2
0.12

0.08
0.1
0.04

0 0

e) at t=5.245s f) at t=5.345s

C C
0.101 0.1 0.0827 0.08

0.075 0.06

0.05 0.04

0.025 0.02

0 0

g) at t=5.445s h) at t=5.545s

C
0.0749

0.06

0.04

0.02

i) at t=5.645s

Figure 9: Concentration at different times

26
6 CONCLUSIONS

6 Conclusions
6.1 Meshing
cfMesh is a robust and easy to use meshing tool. It can generate hexa, tetra and polyhedral meshes.
It can handle bad geometries very well. One of the main advantage is its ability to run in parallel
which saves lot of time when generating large meshes. The available refinement settings are easy to
use. It is very good with handling sharp edges if the given input geometry is good. It is very easy
to generate an initial mesh, however it takes some time to generate an ideal mesh.
The main disadvantage with cfMesh is, it can’t generate multi region meshes if there are multiple
disconnected regions. Even though it is good at handling geometries with poor quality, final mesh
quality still depends largely on the quality of input geometry.

Below figure shows mesh generated in the rotor region. As you can see from below figure (a), when
the input geometry is given as a single patch, edges of the rotor region are not captured properly.
This problem is solved by dividing the geometry into individual patches. In figure (b) rotor region
is divided into 3 different patches top, bottom and cylinder.

a)with single patch b)with individual patches

Figure 10: Comparison between using a single patch and individual patches

6.2 Physical Modelling of rotation


Physical modelling of rotation is done using two methods MRF and sliding grid. The advantages
and disadvantages of both methods will be discussed in below section.

MRF
MRF is a steady state solution with a fixed impeller position. Hence the name Frozen rotor tech-
nique. The main advantage with MRF is, it is not computationally expensive. All steady state
OpenFOAM solvers support MRF and it is easy to implement using fvOptions. One more advan-
tage with MRF is, it is not necessary to generate mesh in two regions. The rotor region can be picked
easily using topoSet and setSet utilities in OpenFOAM. There are number of options available in
both of these utilities to manipulate meshes. It is possible to get an unsteady solution using MRF,
but this is not accurate because the stator and rotor interaction cannot be resolved. This is because
impeller or rotor is fixed at a single position. It can be used when there is weak interaction between
the stator and rotor and when unsteady solution is not required.

Sliding grid Method


It is used for unsteady simulations. In this method the rotor is rotated and the interface between
rotor and stator is coupled using a mesh interface AMI, GGI or mixing plane. Implementation of this

27
REFERENCES 7 APPENDIX

method in OpenFOAM needs more tedious work flow. The rotating and stationary regions should be
generated as separate meshes and should be merged later. In OpenFOAM you can use mergeMeshes
utility to merge meshes. This method employs PIMPLE solver to obtain an unsteady solution. This
is computationally very expensive compared to MRF, but the rotor-stator interactions can be fully
resolved. In OpenFOAM computational time can be decreased by running it in parallel. One more
disadvantage with sliding grid is we need to implement a ramp-up function or increase the angular
velocity of the rotor gradually. This is because of the Courant-Friedrichs-Lewy (CFL) condition.
This problem can be solved by properly choosing the time step and cell size during mesh generation.

References
[1] Magnus Winter. Benchmark and validation of Open Source CFD codes, with focus on compressible
and rotating capabilities, for integration on the SimScale platform. ”Chalmers University of
Technology”
[2] Weidong Huang; Kun Li. CFD Simulation of Flows in Stirred Tank Reactors. ”Nuclear Reactor
Thermal Hydraulics and Other Applications”, book edited by Donna Post Guillen, ISBN 978-
953-51-0987-7
[3] Håkan Nilsson. Lecture Slides, Rotating Machinery. ”Chalmers University of Technology”
[4] Userguide cfMesh-V 1.1.1

7 Appendix
Installing cfMesh
Go to http://sourceforge.net/projects/cfmesh/ and download the cfMesh-v1.1.1.tgz file.

• Export WM NCOMPPROCS=[number of cores on your CPU]


• Extract the tgz file to the folder of your choice
• Source your OpenFOAM or foam-extend environment (source [foam install folder]/etc/bashrc)

• make sure you have the gcc compiler set up properly. We compile using gcc 4.8.2 or newer.
• Make sure you have lnInclude directories generated in OpenFoam source directories for triSur-
face, meshTools, foam/openFOAM, pstream/mpi, OSSPecific/Posix and edgeMEsh libraries.
If you dont have them, generate them like this:
to generate lnInclude:
– go to src/trisurface, wmake libso, wait untill it starts to build (or fails)
– go to src/meshTools, wmake libso, wait untill it starts to build (or fails)
– go to src/foam or src/openFoam, wmake libso, wait untill it starts to build (or fails)
– go to src/pstream/mpi, wmake libso, wait untill it starts to build (or fails)
– go to src/edgeMesh, wmake libso, wait untill it starts to build (or fails)
– go to src/OSspecific/MsWindows or POSIX, wmake libo, wait untill it starts to build (or
fails)
• You can now use ./Allwmake script in cfMesh source folder to compile cfMesh
• This will build cfMesh libraries and binaries in FOAM USER APPBIN and FOAM USER LIBBIN.

28
7 APPENDIX

cfMesh can be installed by following below commands,

tar -xvzf cfMesh-v1.1.1.taz


cd cfMesh-v1.1.1/
export WM_NCOMPPROCS=[8]
source $WM_PROJECT_DIR/etc/bashrc
./Allwmake

Plotting with gnuplot


In order to plot using gnuplot, we need to go the directory of the file and follow below commands,

cd postProcessing/concentrationProbes/4.995
gnuplot
set xlabel "time"; set ylabel "C"; plot "C" using 1:2 title "Probe 0", "C" using 1:3
title "Probe 1", "C" using 1:4 title "Probe 2"
exit

Study questions
• How do you give refinement settings for a edge in cfMesh?
• Does cfMesh support regular expressions?
• How do you create a cellSet using a stl surface?
• How can you plot a graph from multiple files using gnu plot?

• Is it possible to get a unsteady solution using MRF method?

29

You might also like