Implement Multiphase Chalmers Student Project
Implement Multiphase Chalmers Student Project
Implementation of a
myinterFoamDiabatic
Solver with OpenFOAM
Developed for OpenFOAM-1.7.x
Requires:
Author:
Qingming Liu
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 les.
November 22 , 2011
Contents
Chapter 1
Introduction
Mathematical background
Implementation of myinterFoamDiabatic
12
Reference
23
Chapter 1
Introduction
Multi-phase simulation has been a very important topic both in industry and academy. There are
several multi-phase solvers available in OpenFOAM. interFoam is one of the widely used solver
which can be applied for isothermal 2 incompressible flow calculation. However, as the other multiphase solvers in OpenFOAM, it cannot be used to simulate non-isothermal phenomena due to the lack
of energy equation implementation1. This project is aiming to implement a new non-isothermal solver
called myinterFoamDiabatic based on the solver interFoam by introducing energy equation. A
simulation tutorial on bubbly 2 phase flow through a mini channel is done as well.
Since the bubbly flow in microchannel is a diabatic process, we need to implement thermal equations
which have not included in interFoam so far. We need to add new thermalphysical properties of 2
phase as well.
The tasks of this project can be summarized as follows:
Study the flow pattern and pressure drop of elongated bubble flow in microchannels(with diameter 1.7mm).
Chapter 2
Mathematical background
The governing equations in the new solver myinterFoamDiabatic are summarized as follows:
(1)
(2)
(3)
(4)
They are the momentum equation (equation 1) the mass equation (equation 2), the energy equation
(equation 3) and the volume fraction (equation 4).
Except the energy equation(eq. 3), the rest of equations has been implemented in the based solver
interFoam already, so all we need to do in this project is to implement this equation. However, for
simplicity, the source term () is assuming to be 0 at this project.
In eq.3, and k denote the specific heat capacity and the thermal conductivity respectively.
is the viscosity.
The equation 4 is the volume fraction equation which will be used to capture the 2 phase interface by
using a VOF method.
The volume fraction field() determines the liquid volume fraction in each cell. It has a value of 0 in
all vapor cells, a value of 1 in all liquid cells and a value between 0 and 1 in cells that are cut by the
liquid-vapor interface3 4(Figure 1).
4
Chapter 3
Implementation of myinterFoamDiabatic
The myinterFoamDiabatic application has a structure according to Figure 2. It contains a solver
called myinterFoamDiabatic which called the shared library transportModels dynamically at
runtime. Due to the introducing of thermal properties, the transportModels library should be modified
to adapt the change. Hence we need to modify and compile the transportModels library independently
before compiling the solver and setting up the case.
transportModels.H
myinterFoamdiabatic.C
#include"transportModels"
transportModels.C
myinterFoamdiabatic
executable
transportModels.so
Solver
Library
Before implementing the solver, we should modify the transportModels library which is calling at run
time by adding thermal properties for each phase and mixture.
First, copy the model to our own directory by the following command:
cp -r $WM_PROJECT_DIR/src/transportModels $WM_PROJECT_USER_DIR/src
cd $WM_PROJECT_USER_DIR/src/transportModels/incompressible/
wclean
cd incompressibleTwoPhaseMixture
Then we need to add the specific heat capacity(cp1, cp2)and Prandtl number (Pr1, Pr2)for each phase.
Moreover, the thermal conductivity for the mixture is calculated according to the following
expression:
(5)
Open the file twoPhaseMixture.H and declaring the specific heat capacity(cp1, cp2)and Prandtl
number s(Pr1, Pr2)for each phase by adding the following lines after line 67:
dimensionedScalar rho2_;
// line 67
//------------------------Modified---------------------//
dimensionedScalar cp1_;
dimensionedScalar cp2_;
dimensionedScalar Pr1_;
dimensionedScalar Pr2_;
//-------------------------End-----------------------//
Modified lines after line 141 as follows:
const dimensionedScalar& rho2() const
{
return rho2_;
};
// line 141
//------------------------Modified---------------------//
const dimensionedScalar& Pr1() const
{
return Pr1_;
}
const dimensionedScalar& Pr2() const
{
return Pr2_;
};
const dimensionedScalar& cp1() const
{
return cp1_;
}
const dimensionedScalar& cp2() const
{
return cp2_;
};
//--------------------------End-----------------------//
Add the thermal conductivity, specific heat capacity and Prandlt number as follows:
tmp<surfaceScalarField> nuf() const;
//------------------------Modified---------------------//
tmp<surfaceScalarField> kappaf() const;
//------------------------Modified---------------------//
rho2_(nuModel1_->viscosityProperties().lookup("rho2_"));
Open
the file twoPhaseMixture.C and defining the specific heat capacity(cp1, cp2)and Prandtl
//---------------------------------------Modified-----------------------------------//
numbers(Pr1,
Pr2)for each phase by adding the following lines in line 92:
cp1_(nuModel1_->viscosityProperties().lookup("cp")),
cp2_(nuModel2_->viscosityProperties().lookup("cp")),
Pr1_(nuModel1_->viscosityProperties().lookup("Pr")),
Pr2_(nuModel2_->viscosityProperties().lookup("Pr")),
//-----------------------------------------End--------------------------------------//
(
alpha1f*rho1*fvc::interpolate(nuModel1_->nu())
+ (scalar(1) - alpha1f)*rho2_*fvc::interpolate(nuModel2_->nu())
) /(alpha1f*rho1_ + (scalar(1) - alpha1f)*rho2_)
)
);
}
//-------------------------------------Modified--------------------------------------//
tmp<surfaceScalarField> twoPhaseMixture::kappaf() const
{
surfaceScalarField alpha1f =
min(max(fvc::interpolate(alpha1_), scalar(0)), scalar(1));
return tmp<surfaceScalarField>
(
new surfaceScalarField
(
"kappaf",
alpha1f*rho1_*cp1_*(1/Pr1_)*fvc::interpolate(nuModel1_->nu())
+ (scalar(1) - alpha1f)*rho2_*cp2_*(1/Pr2_)*fvc::interpolate(nuModel2_->nu())
)
);
}
//-----------------------------------------End--------------------------------------//
myinterFoamDabatic
alphaEqnSubCycle.H
alphaEqnSubCycle.H
interFoam.C
interFoam.C
correctPhi.H
correctPhi.H
UEqn.H
UEqn.H
pEqn.H
pEqn.H
alphaEqn.H
alphaEqn.H
setDeltaT.H
setDeltaT.H
CreateFields.H
CreateFields.H
Make/
Make/
alphaCourantNo.H
alphaCourantNo.H
Teqn.H
Open createFields.H and create the thermal properties we specified in the models before by adding
following lines after line 68 and line 148 respectively:
const dimensionedScalar& rho2 = twoPhaseProperties.rho2();
//------------------Modified---------------------//
const dimensionedScalar& cp1 = twoPhaseProperties.cp1();
const dimensionedScalar& cp2 = twoPhaseProperties.cp2();
//---------------------End----------------------//
// line 68
// . line 148
//------------------Modified---------------------//
Info<< "Reading / calculating rho*cp\n" << endl;
volScalarField rhoCp
(
IOobject
(
"rho*Cp",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
alpha1*rho1*cp1 + (scalar(1) alpha1)*rho2*cp2,
alpha1.boundaryField().types()
);
rhoCp.oldTime();
Info<< "Reading / calculating rho*phi*cp\n" << endl;
surfaceScalarField rhoPhiCpf
(
IOobject
(
"rho*phi*cpf",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
rhoPhi*cp1
);
//---------------------End-----------------------//
Open file alphaEqnSubCycle.H and add the following line after line 37:
rho == alpha1*rho1 + (scalar(1) alpha1)*rho2;
//-------------------Modified--------------------//
rhoCp == alpha1*rho1*cp1 + (scalar(1) alpha1)*rho2*cp2;
//----------------------End-----------------------//
Open file alphaEqn.H and add the following line after line 31:
rhoPhi= phiAlpha*(rho1 - rho2) + phi*rho2;
//-------------------Modified--------------------//
rhoPhiCpf = phiAlpha*(rho1*cp1 - rho2*cp2) + phi*rho2*cp2;
//----------------------End-----------------------//
Create file TEqn.H and add the following line:
10
11
Length
mm
Diameter
mm
15.5
1.7
R134a
Inlet
temperature
K
Pressure:
bar
293
The mesh generation using an O-grid according to the ERCOFTAC conical diffuser test case5. One
main advantage of the O-grid method is that the mesh is refined in the near-wall places. The refining
process has 2 steps. First , the cross-section of the channel was separated to two parts, namely: squarelike inner and outer. As it is shown in Figure 6, the refines parameter rRelA is defined as the ratio of
the diagonal of the square-like inner to the diameter of the cross section circle while rRelAc
denotes the ratio of the distance between mid-point of the arcs and the circle center to rRelA.
rRelAc=1 , the arc become a part of the circle with diameter rRelA.
rRelAc= , the 4 arcs become 4 straight lines and form an inner square with diagonal rRelA.
Usually a value of rRelAc between 1 and
a)
b)
13
myinterFoamDiabaticCase
constant
constant
system
controlDict
polyMesh
system
transportProperties
turbulenceProperties
fvSchemes
fvSolutions
decomposeParDict
0
alpha1
p_rgh
T
U
First of all, download the case file from the course homepage:
http://www.tfd.chalmers.se/~hani/kurser/OS_CFD/
The modification which had been done by the author can be summarized as follows:
The Cp and Prandlt number have added in the constant/transportProperties file as following lines:
phase1
{
.
Pr
Pr [0 0 0 0 0 0 0] 3.366;
cp
cp [0 2 -2 -1 0 0 0] 1433.4;
}
phase2
{
.
Pr
cp
Pr [0 0 0 0 0 0 0] 0.87;
cp [0 2 -2 -1 0 0 0] 1045.2;
Tell the code to use myinterFoamDiabatic solver and the new libraries by opening system/controlDict
and add the following lines:
application
myinterFoamDiabatic;
libs("libmyincompressibleTransportModels.so");
A new finite divergence schemes for Temperature was added in system/ fvSchemes as follows:
14
divSchemes
{
div(rho*phi,U) Gauss limitedLinearV 1;
.
div(rho*phi*cpf, T) Gauss upwind;
..
}
Anew finite volume solution method for Temperature was added in system/ fvSolution as follows:
T
{
solver BICCG;
preconditioner DILU;
tolerance 1e-7;
relTol 0;
}
A Temperature field file was created under 0/ directory in 0/T as following lines:
15
dimensions
[0 0 0 1 0 0 0];
fixedValue;
value
uniform 300;
}
wall
{
type
fixedValue;
value
uniform 300;
}
outlet
{
type
zeroGradien;
}
}
As there is no constant heat flux boundary in OpenFOAM so far, we need to set this boundary
condition indirectly. According to Fouriers law, heat flux can be expressed as the following equation:
So here we set a Temperature gradient which available in OpenFOAM instead of heat flux.
wall
{
type
value
fixedGradient;
uniform 183.765;
}
outlet
{
type
}
zeroGradient;
16
3.3.3 SetField
Now we need to initialized a gas bubble in the inlet of the channel by the help of the utility called
funkySetFields which is part of swak4foam. This utility can set the value of a scalar or a vector field
depending on an expression that can be entered via the command line or a dictionary. It can also be
used to set the value of fields on selected patches. It's like the setFields utility6.
It can be used to set non-uniform initial-conditions without programming.
Since it is very difficult to initialize the bubble shape accurately, here a simplified cylinder bubble is
set as the initial condition. The diameter of the bubble is set slightly smaller than the channel(1.7mm)
to 1.5mm and the length is set to 0.35mm.
The expression of this initial bubble cylinder in Cartesian coordinate is as follows :
&& 0< z <0.003
(7)
cd $WM_PROJECT_USER_DIR/src
svn checkout https://openfoam-extend.svn.sourceforge.net/svnroot/openfoamextend/trunk/Breeder_1.7/libraries/swak4Foam
Since only the funkySetFields utility is needed in this project, we do not compile the whole package.
Instead, we do:
cd $WM_PROJECT_USER_DIR/src/swak4Foam/Utilities/funkySetFields
wmake
Then, we go to directory constant/polyMesh and set the initial bubble by funkySetFields utility
according to the following command
funkySetFields -field alpha1 -expression 1 -time 0 -keepPatches -condition "pow(pos().x,2)
+ pow(pos().y,2) < pow(0.00075,2) && pos().z <0.003"
17
Because of the big size of the mesh, it is better to run the case in parallel. In order to do this, we have
to decompose the mesh to 4 parts by using the decomposeParDict. Open the file
system/decomposeParDict and edit the contents as follows:
numberOfSubdomains 4;
method simple;
simpleCoeffs
{
n
(2 2 1);
delta
0.001;
}
After we run the decompose by type command >>decompsePar, we can get the 4 parts of the mesh as
Figure 10.
18
19
boundaryField
inlet
{
type
timeVaryingUniformFixedValue;
fileName
"ramp";
outOfBounds
clamp;
}
}
myinterFoamDiabatic;
startFrom
latestTime;
startTime
0;
stopAt
endTime;
endTime
deltaT
0.02;
2e-4;
writeControl
adjustableRunTime;
writeInterval
0.001;
purgeWrite
0;
writeFormat
ascii;
writePrecision
6;
writeCompression
uncompressed;
timeFormat
general;
timePrecision
6;
runTimeModifiable
adjustTimeStep
maxCo
maxAlphaCo
maxDeltaT
yes;
on;
0.5;
0.5;
1;
libs (libmyincompressibleTransportModels.so);
We just need to type the following command to run the case in parallel:
20
0 s
0.0005s
Figure 11 Alpha1 gas bubble in the channel
0.015 s
0.02 s
From Figure11 and 12 the bubble going through the channel periodically according to the ramped
boundary conditions. The temperature field in Figure 13 indicate that the heat was simulated
21
successfully in the case. A further study by adding source terms to mass and energy equation should
be implement in order to investigate the phase change phenomena.
22
Reference
1
23