Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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
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
u = 6Umean
(y e)(y c)
(e c)2
(5)
(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
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.
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.
Conclusions
Although the program could not reproduce the physics of the problem we can make
some conclusions about the behaviour of the code flaws.
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;//
};
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++)
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
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);
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
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
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;
15
// 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;
}