Está en la página 1de 16

Numerical Solution of Incompressible Laminar Flow

over a backstep
Christian Frias
University of Pittsburgh

Introduction

Herein, a numerical model to solve the hydrodynamics of a laminar flow over a backstep is presented. The numerical schemes for this model have been developed by
Roache (1968) and are explained in section 2. In order to obtain a laminar flow field
a small value of viscosity was selected ( = 0.15cm2 /s). The goal of the model was to
predict the recirculation pattern expected downstream the backstep face. Therefore,
the vorticity is an important parameter to calculate and from it calculate the stream
function and velocities vectors. This model solves all the scales of turbulence, thus,
we can consider it as a direct numerical simulation for small Reynolds. Although, we
have used this model only for a laminar flow case it can be extended for turbulent
flows at small scales. Nowadays, in contrast to what Roache(1968) mentioned in his
paper, the simulation of turbulent flows is possible using the current computer resources that we have. Thus, it could be possible to model turbiulent fluids such as
water over a backstep obstacle. The latter is a common phenomenon in environmental flows such as migration of dunes or ripples on river beds. The main characteristics
or these cases are the flow reattachment and the shear stress at the boundary walls
which case the erosion and deposition patterns of river beds.

C. Frias

Numerical Schemes and Boundary Conditions

2.1

Numerical Schemes

The equation solved by the model is the vorticity equation given in equation (1).
 2

w
w
w 2w
w
+u
+v
=
.
+
t
x
y
x2
y 2

(1)

Where the vorticity is expressed in terms of the velocities by equation (2) and in
terms of the stream function by equation (3).
u v
+
.
y x

(2)

2 2
+ 2.
x2
y

(3)

w=

w =

Where
= u,
= v.
y
x
The steps that the model follows to solve the vorticity equation are:
1. Initialize all the variables: Mean velocity (Umean ), kinematic viscosity (), time
step (t). The initial time step has been calculated as 0.9 of the critical time
step. This critical time step is given in equation (4).
tcrit =

1
uij /x + vij /y + 2/((1/x2 + 1/y 2 ))

(4)

2. Creates the grid and input the initial values for the velocities. The grid used
and the type of boundary condition as well as the code given in the program
is shown in Figure 1. The origin of the grid is the upper left corner (i=0, j=0)
ant the last point of the grid is in the lower right corner (i= Number points
in x, j = Number of points in y )For the inlet a parabolic profile was used for
the velocities (see equation (5)) The initial values of velocities for the internal
points, the top wall and the outlet boundary were the mean velocity for the
velocities in the x direction and zero values for the velocity in the y direction.
Whereas, for the walls the two components of the velocity vector u and v were
initialized with zero values. The values of the stream function for the inlet were
considered as the integral of the velocity in y and the maximum value on this
Re
boundary zone was used for the top wall boundary ( c u(y)dy).e

Numerical Solution of Incompressible Laminar Flow over a backstep

u = 6Umean

(y e)(y c)
(e c)2

(5)

Figure 1: Mesh Layout


The vorticity in the inlet is calculated from the values of u and v according to
equation (7). Whereas the values of vorticity in the walls are assumed to be the
same of the internal points that are next to the wall points in the perpendicular
direction. For example, the vorticity in a vertical wall (wverticalwall ) is equal to
the point to the right wverticalwall = wi+1,j and the vorticity in a bottom wall
(wbottomwall ) is equal to the point that is above wbottomwall = wi,j1
uinlet = 6Umean

(y e)(y c)
(e c)2

winlet = 6Umean

2y e c
(e c)2

(6)

(7)

3. The vorticity is calculated at the internal points with an upwind scheme for
the convection and a centered difference for dispersion. The expressions of the
discretized vorticity equation is given in equations (8) and (9).

C. Frias

n+1
wij

n
wij

2 wn
2 wn
(uw)n (vw)n

+
+

+ t
xij
xij
x2ij
yij2



(8)

.
Where,

n
n
(uw)i+1,j (uw)i,j , for u < 0
(uw)
ij
= (uw)n x
n
i,j (uw)i1,j

xij
, for u > 0
xij
n

(9)

4. Knowing the values of velocities, vorticity and stream function the program
advances in time for the stream function by over relaxation and calculates again
the new values of w and from them the values of the velocities.
5. Finally, if the steady state is reached the program stops and call a function
PrintReport.cpp to print the results in Tecplot.

2.2

Boundary Conditions

A summary of the boundary conditions is given next:


1. Inlet: The inlet has code (1) in the program and have a parabolic velocity profile
with v = 0. The vorticity and stream function are calculated by the procedure
described in the previous section.
2. Bottom Wall: This boundary has a Dirichlet no slip boundary conditions
which means that the values of the velocities u and v are zero. Also the value
for the stream function is given as zero and the vorticity is calculated by the
procedure described in the previous section.
3. Top Wall: This boundary has a Dirichlet slip boundary condition. It means
that initially the velocities are zero but the stream function is the total flowrate
of the domain at the beginning. The vorticity is calculated as a wall boundary
and was explained before.
4. Outlet: This is a Neumman zero gradient boundary condition. It means that
the derivatives in x and y for all the variables are set to zero.

Numerical Solution of Incompressible Laminar Flow over a backstep

Results

Unfortunately, the program did not succeed and no logical results are showed in this
section. The initial conditions of the simulation are presented in Figures 2 and Figure
3 for the vorticity and the stream function respectively.

Figure 2: Initial Vorticity

Figure 3: Initial Stream Function

C. Frias

The steady state was reached at 10s. Therefore the plots for the vorticity and the
stream function are showed in Figure 4 and Figure 5.

Figure 4: Initial Vorticity

Figure 5: Initial Stream Function

Conclusions

Although the program could not reproduce the physics of the problem we can make
some conclusions about the behaviour of the code flaws.

Numerical Solution of Incompressible Laminar Flow over a backstep

1. As we can see from the results the vorticity is not being transported. At the
beginning in the debug process we noticed that the array of stream function was
taken the values of the vorticity directly without any processing. This caused
that the vorticity and the stream function was not being transported. We fixed
that error however the vorticity remained the same. It seems that the initial
values of vorticity are not the correct ones at the inlet. Thus, the flows does not
complete a recirculation pattern and instead of that it resulted in an upward
flow at the beginning and a downward flow at the end as seen in Figure 4 and
Figure 5.
2. Concerning to the stream function and the velocities we can say that they are
correlated as expected. As we can see in Figure 5 the stream function has
negative values when the velocities are downward and positive values when
the velocities are upward. Thus, we conclude that the error in the code is
not because of the equations used to calculate the velocities from the stream
function values.
3. On the future, this code can be corrected by beginning to check the treatment
of the equations used at the boundaries. It seems that the scheme used at the
walls is failing because with a detailed inspection of the plots we have found
vectors going upstream in the top wall and the bottom walls when the opposite
direction is expected.

References
[1] P.Roache, Numerical Soltions of Laminar Separated Flows (AIAA Journal, Vol. 8
No. 3, 1968).

5
5.1

Code
LaminarBackStep.h

#include <vector>
using namespace std;
struct POINT
{

C. Frias

double w;
double psi;
double u;
double v;
double x;
double y;
int code;//
};

-3-verticalwall, -2-bottomwall, -1-topwall, 0-internal , 1-inlet, 2-outlet

double Sign(const double & Num);


void GridGenerator(vector< vector<POINT> >& Grid, double Umean, int Nx, double a, double b, double c, double d, double e);
void PrintReport(vector<vector<POINT> >& Grid);

5.2

LaminarBackStep.cpp

#include<vector>
#include<fstream>
#include<iostream>
#include<cmath>
#include "LaminarBackStep.h"
int main()
{
vector < vector < POINT > > Grid;
double Umean, nu, a=0.5, b=1.5, c=0.5, d=7.0, e;
double dx,dy,dt,dtc,t,tf,ap,afx,abx,afy,aby,wfx,wbx,wfy,wby,psifx,psibx,psify,psiby,f,err,errc,errmax;
int Nt,Nx;
e=a+c;
nu=0.15;//0.0000001002;
/*cout<<"Please enter the number of points in x direction: "<<endl;
cin>>Nx;
cout<<"Please enter the final time: "<<endl;
cin>>tf;
cout<<"Please enter the mean velocity: "<<endl;
cin>>Umean;
cout<<"Please enter the accurancy: "<<endl;
cin>>errc;*/
Nx=51;tf=500;Umean=3;errc=0.5;
GridGenerator(Grid, Umean, Nx, a, b, c, d, e);
dx=Grid[1][0].x-Grid[0][0].x;
dy=Grid[0][0].y-Grid[0][1].y;
//cout<<dy<<endl;
t=0; dtc=0;
while(t<=tf)
{
cout<<"Time: "<<t<<endl;
for(int i=0;i<Grid.size();i++)
{
for(int j=0;j<Grid[i].size();j++)

Numerical Solution of Incompressible Laminar Flow over a backstep


{
dt=1/(Grid[i][j].u/dx+Grid[i][j].v/dy+2/nu*(1/dx/dx+1/dy/dy));
if (dt>dtc) dtc=dt;
}
}
dt=0.9*dtc;t=t+dt;
for(int i=0;i<Grid.size();i++)
{
for(int j=0;j<Grid[i].size();j++)
{
//switch (Grid[i][j].code)
if (Grid[i][j].code==-3)
{
Grid[i][j].w=Grid[i+1][j].w;
}
if (Grid[i][j].code==-2)
{
Grid[i][j].w=Grid[i][j-1].w;
}
if (Grid[i][j].code==-1)
{
Grid[i][j].w=Grid[i][j+1].w;
}
if (Grid[i][j].code==0)
{
abx=(1+Sign(Grid[i][j].u))*Grid[i-1][j].u/2/dx+nu/dx/dx;
afx=-(1-Sign(Grid[i][j].u))*Grid[i+1][j].u/2/dx+nu/dx/dx;
afy=-(1-Sign(Grid[i][j].v))*Grid[i][j-1].v/2/dy+nu/dy/dy;
aby=(1+Sign(Grid[i][j].v))*Grid[i][j+1].v/2/dy+nu/dy/dy;
wfx=Grid[i+1][j].w;wbx=Grid[i-1][j].w;
wfy=Grid[i][j-1].w;wby=Grid[i][j+1].w;
ap=-Sign(Grid[i][j].u)*Grid[i][j].u/dx-Sign(Grid[i][j].v)*Grid[i][j].v/dy-2*nu*(1/dx/dx+1/dy/dy);
Grid[i][j].w=Grid[i][j].w*(1+ap*dt)+dt*(afy*wfy+afx*wfx+abx*wbx+aby*wby);
}
if(Grid[i][j].code==2)
{
Grid[i][j].w=Grid[i-1][j].w;
/*afy=-(1-Sign(Grid[i][j].v))*Grid[i][j-1].v/2/dy+nu/dy/dy;
aby=(1+Sign(Grid[i][j].v))*Grid[i][j+1].v/2/dy+nu/dy/dy;
wfy=Grid[i][j].w;wby=Grid[i][j+1].w;
ap=-Sign(Grid[i][j].v)*Grid[i][j].v/dy-2*nu/dy/dy;
Grid[i][j].w=Grid[i][j].w*(1+ap*dt)+dt*(afy*wfy+aby*wby);*/
}
}
}
do
{
errmax=0;
//err=0;
for(int i=0;i<Grid.size();i++)
{

10
for(int j=0;j<Grid[i].size();j++)
{
if (Grid[i][j].code==-3)
{
err=Grid[i+1][j].psi+Grid[i][j].w*dx*dx/2-Grid[i][j].psi;
Grid[i][j].psi=Grid[i][j].psi+err;
if (abs(err)>errmax) errmax=abs(err);
}
if (Grid[i][j].code==-2)
{
err=Grid[i][j-1].psi+Grid[i][j].w*dy*dy/2-Grid[i][j].psi;
Grid[i][j].psi=Grid[i][j].psi+err;
if (abs(err)>errmax) errmax=abs(err);
}
if (Grid[i][j].code==-1)
{
err=Grid[i][j+1].psi+Grid[i][j].w*dy*dy/2-Grid[i][j].psi;
Grid[i][j].psi=Grid[i][j].psi+err;
if (abs(err)>errmax) errmax=abs(err);
}
if (Grid[i][j].code==0)
{
f=Grid[i][j].w;ap=2*(1/dx/dx+1/dy/dy);
afx=1/dx/dx;abx=1/dx/dx;afy=1/dy/dy;aby=1/dy/dy;
psifx=Grid[i+1][j].psi;psibx=Grid[i-1][j].psi;
psify=Grid[i][j-1].psi;psiby=Grid[i][j+1].psi;
err=(f+afx*psifx+abx*psibx-ap*Grid[i][j].psi+afy*psify+aby*psiby)/ap;
Grid[i][j].psi=Grid[i][j].psi+/*1.5**/err;
if (abs(err)>errmax) errmax=abs(err);
}
if (Grid[i][j].code==2)
{
Grid[i][j].psi=2*Grid[i-1][j].psi-Grid[i-2][j].psi;
/*f=Grid[i][j].w;ap=2*(1/dx/dx+1/dy/dy);
afx=1/dx/dx;abx=1/dx/dx;afy=1/dy/dy;aby=1/dy/dy;
psifx=Grid[i][j].psi;psibx=Grid[i-1][j].psi;
psify=Grid[i][j-1].psi;psiby=Grid[i][j+1].psi;
err=(f+afx*psifx+abx*psibx-ap*Grid[i][j].psi+afy*psify+aby*psiby)/ap; //ficticious point
Grid[i][j].psi=Grid[i][j].psi+1.5*err;
if (abs(err)>errmax) errmax=abs(err);*/
//cout<<errmax<<" "<<i<<" "<<j<<endl;
}
}
}
}
while (errmax>errc);
for(int i=1;i<Grid.size();i++)
{
for(int j=0;j<Grid[i].size();j++)
{
if (Grid[i][j].code==-3)
{
Grid[i][j].v=(Grid[i][j].psi-Grid[i+1][j].psi)/dx;

C. Frias

Numerical Solution of Incompressible Laminar Flow over a backstep

11

}
if (Grid[i][j].code==-2)
{
Grid[i][j].u=(Grid[i][j-1].psi-Grid[i][j].psi)/dy;
}
if (Grid[i][j].code==-1)
{
Grid[i][j].u=(Grid[i][j].psi-Grid[i][j+1].psi)/dy;
}
if (Grid[i][j].code==0)
{
Grid[i][j].u=(Grid[i][j-1].psi-Grid[i][j+1].psi)/2/dy;
Grid[i][j].v=(Grid[i-1][j].psi-Grid[i+1][j].psi)/2/dx;
}
if (Grid[i][j].code==2)
{
Grid[i][j].u=(Grid[i][j-1].psi-Grid[i][j+1].psi)/2/dy;
Grid[i][j].v=(Grid[i-1][j].psi-Grid[i][j].psi)/dx;
}
}
}
}
PrintReport(Grid);
return 0;
}

5.3

GridGenerator.cpp

#include<vector>
#include<iostream>
#include<cmath>
#include "LaminarBackStep.h"
double uIntegral(double A, double B, double Umean, double c, double e);

double uIntegral(double A, double B, double Umean, double c, double e)


{
return -6*Umean / ((e-c)*(e-c)) * (c*e*B - 0.5*c*B*B - 0.5*e*B*B + B*B*B/3) + 6*Umean / ((e-c)*(e-c)) * (c*e*A - 0.5*c*A*A }
void GridGenerator(vector<vector<POINT> >& Grid, double Umean, int Nx, double a, double b, double c, double d, double e)
{
POINT TempPoint;
vector<POINT> TempVecPoint;
double dxtemp, dx, dytemp, dy, x, y, psi;
int Ny_a, Ny_c, Ny_e, Nx_b, Nx_d, Nx_final;
dxtemp = (b+d)/(Nx);
if ( (int) floor((b+d)/dxtemp)% 2 == 0) Nx_final=floor((b+d)/dxtemp) +1; else Nx_final=floor((b+d)/dxtemp); // CHECK NUMBER
dx = (b+d) / (Nx_final);
Nx_b = (int) floor(b/dx) +1 ;
Nx_d = (int) floor(d/dx) +1 ;

12

dytemp = dx/2;
if ( (int) floor(e/dytemp)% 2 == 0) Ny_e=floor(e/dytemp) +1; else Ny_e=floor(e/dytemp);
dy= e / (Ny_e -1);
Ny_a = (int) floor(a/dy) +1 ;
Ny_c = (int) floor(c/dy) +1 ;
cout<<"
Creating inlet..."<<endl;
//Inlet Boundary Condition
for (int j=0; j< Ny_a ; j++) //CHECK NUMBER OF POINTS!
{
x = 0;
//y = c + j*dy;
y = c + a - j*dy;
TempPoint.x = x;
TempPoint.y = y;
TempPoint.u = -6*Umean/((e-c)*(e-c)) * (y-e) * (y-c);
TempPoint.v = 0;
TempPoint.code = 1;
TempPoint.psi =0; //initialized, this will change later
TempPoint.w = 6*Umean / ((e-c)*(e-c)) * (2*y-e-c); //initialized, this will change later
TempVecPoint.push_back(TempPoint);
}
Grid.push_back(TempVecPoint); //stores the inlet vector of points
TempVecPoint.clear();
cout<<"
Creating walls, internal points and outlet..."<<endl;
//Walls and internal points before the corner
x=0;
for (int i=0; i< Nx_b-2; i++)
{
x = x+dx;
y = c+a;
TempPoint.x = x;
TempPoint.y = y;
TempPoint.u = 0;
TempPoint.v = 0;
//TempPoint.code = -2; //bottomwall
TempPoint.code = -1; //topwall
TempPoint.psi =0; //initialized, this will change later
TempPoint.w = 0; //initialized, this will change later
TempVecPoint.push_back(TempPoint);
for (int j=1; j< Ny_a-1; j++)
{
//x = x;
y = c + a - j*dy;
TempPoint.x = x;
TempPoint.y = y;
TempPoint.u = Umean; //inputs the mean velocity for the internal points
TempPoint.v = 0;
TempPoint.code = 0; //internal point
TempPoint.psi =0; //initialized, this will change later
TempPoint.w = 0; //initialized, this will change later

C. Frias

Numerical Solution of Incompressible Laminar Flow over a backstep

13

TempVecPoint.push_back(TempPoint);
}
//x = 0;
y = c;
TempPoint.x = x;
TempPoint.y = y;
TempPoint.u = 0;
TempPoint.v = 0;
//TempPoint.code = -1; //topwall
TempPoint.code = -2; //bottomwall
TempPoint.psi =0; //initialized, this will change later
TempPoint.w = 0; //initialized, this will change later
TempVecPoint.push_back(TempPoint);
Grid.push_back(TempVecPoint); //stores the vector of points
TempVecPoint.clear();
}
//Walls, internal points after the corner and outlet
//x=0;
for (int i=0; i< Nx_d; i++)
{
x = x+dx;
y = a+c;
TempPoint.x = x;
TempPoint.y = y;
TempPoint.u = 0;
TempPoint.v = 0;
TempPoint.code = -1; //topwall
//TempPoint.code = -2;//bottomwall
TempPoint.psi =0; //initialized, this will change later
TempPoint.w = 0; //initialized, this will change later
TempVecPoint.push_back(TempPoint);
for (int j=1; j< Ny_e-1; j++)
{
//x = x;
y = a + c -j*dy;
TempPoint.x = x;
TempPoint.y = y;
//if (i == (Nx_d-1)) TempPoint.u =0; else TempPoint.u = Umean; //inputs the mean velocity for the internal points
/*if (i == (Nx_d-1))*/ TempPoint.u=Umean;//outlet and interior points
//else TempPoint.u = 0; //internal point
if(i == 0 && (y>=0 && y<=c )) TempPoint.u=0; //vertical wall
TempPoint.v = 0;
if (i == (Nx_d-1)) TempPoint.code=2;//outlet
else TempPoint.code = 0; //internal point
if(i == 0 && (y>=0 && y<=c )) TempPoint.code=-3; //vertical wall

14

C. Frias

TempPoint.psi =0; //initialized, this will change later


TempPoint.w = 0; //initialized, this will change later
TempVecPoint.push_back(TempPoint);
}
//x = 0;
y = 0;
TempPoint.x = x;
TempPoint.y = y;
//if (i == (Nx_d-1))TempPoint.u = Umean;
TempPoint.u=0;
TempPoint.v = 0;
//if (i == (Nx_d-1)) TempPoint.code = 2; //outlet
/*else*/ TempPoint.code = -2; //bottomwall
TempPoint.psi =0; //initialized, this will change later
TempPoint.w = 0; //initialized, this will change later
TempVecPoint.push_back(TempPoint);
Grid.push_back(TempVecPoint); //stores the vector of points
TempVecPoint.clear();
}
cout<<"
Finishing the Psi vector..."<<endl;
//Psi update for the inlet and the top wall.
for (int j=Grid[0].size()-1; j>=0; j--)
{
Grid[0][j].psi = uIntegral(c, Grid[0][j].y, Umean, c, e);
}
for (int i=1; i<Grid.size(); i++)
{
Grid[i][0].psi = Grid[0][0].psi; // for the top wall the max psi is the top psi at the inlet
}
}

5.4

PrintReport.cpp

#include<vector>
#include<fstream>
#include<cmath>
#include "LaminarBackStep.h"
void PrintReport(vector<vector<POINT> >& Grid)
{
ofstream solutionFile("SteadySolution.txt");
ofstream boundaryFile("boundary.txt");
double dx, dy;
dx = Grid[1][0].x - Grid[0][0].x;
dy = Grid[0][1].y - Grid[0][0].y;

Numerical Solution of Incompressible Laminar Flow over a backstep

15

for (int i=0; i<Grid.size(); i++)


{
for(int j=0; j< Grid[i].size(); j++)
{
solutionFile<<Grid[i][j].x<<" "<<Grid[i][j].y<<" "<<Grid[i][j].u<<" "<<Grid[i][j].v<<" "<<Grid[i][j].w<<" "<<Grid[i][j].psi<
}
}

/* for (int i=0; i<Grid.size(); i++)


{
for(int j=0; j< Grid[i].size(); j++)
{
if (Grid[i][j].code != 0)
boundaryFile<<Grid[i][j].x<<" "<<Grid[i][j].y<<" "<<Grid[i][j].u<<" "<<Grid[i][j].v<<" "<<Grid[i][j].w<<" "<<Grid[i][j].psi<
}
}*/

// BOTTOM WALL 1
int inii, inij;
for (int i=0; i< (int) floor(1.5 / dx); i++)
{
boundaryFile<<Grid[i][Grid[i].size()-1].x<<" "<<Grid[i][Grid[i].size()-1].y<<" "<<Grid[i][Grid[i].size()-1].u<<" "<<Grid[i][
inii=i+1;
inij=Grid[i].size()-1;
}

// VERTICAL WALL 1
for (int j= inij; j < Grid[inii].size(); j++ )
{
boundaryFile<<Grid[inii][j].x<<" "<<Grid[inii][j].y<<" "<<Grid[inii][j].u<<" "<<Grid[inii][j].v<<" "<<Grid[inii][j].w<<" "<<
}

// BOTTOM WALL 2
for (int i=inii+1; i< (int) floor(8.5 / dx)/*+1*/ ; i++)
{
boundaryFile<<Grid[i][Grid[i].size()-1].x<<" "<<Grid[i][Grid[i].size()-1].y<<" "<<Grid[i][Grid[i].size()-1].u<<" "<<Grid[i][
inii=i+1;
}
inii=Grid.size();
// OUTLET
for (int j= Grid[Grid.size()-1].size()-1 ; j >=0; j-- )
{
boundaryFile<<Grid[Grid.size()-1][j].x<<" "<<Grid[Grid.size()-1][j].y<<" "<<Grid[Grid.size()-1][j].u<<" "<<Grid[Grid.size()}

//TOP WALL
for (int i=Grid.size()-1; i>=0 ; i--)
{
boundaryFile<<Grid[i][0].x<<" "<<Grid[i][0].y<<" "<<Grid[i][0].u<<" "<<Grid[i][0].v<<" "<<Grid[i][0].w<<" "<<Grid[i][0].psi<
inii=i+1;
}

16

C. Frias

//INLET
for (int j= 0 ; j < Grid[0].size(); j++ )
{
boundaryFile<<Grid[0][j].x<<" "<<Grid[0][j].y<<" "<<Grid[0][j].u<<" "<<Grid[0][j].v<<" "<<Grid[0][j].w<<" "<<Grid[0][j].psi<
}
}

5.5

Sign.cpp

#include "LaminarBackStep.h"
double Sign (const double & Num)/*SIGN FUNCTION BY CESAR A. SIMON*/
{
double Signo;
if (Num<0) Signo=-1; else if (Num>0) Signo=1; else Signo=0;
return Signo;
}

También podría gustarte