附录F 有限体积法计算方腔流(F)
发布时间:2024-08-25
发布时间:2024-08-25
程序
附录F 二维不可压缩黏性流体方腔流动问题的
有限体积算法与计算程序
二维方腔流动问题是一个不可压缩黏性流动中典型流动。虽然目前尚不能求得它的解析解,但是它常被用来作为检验各种数值算法计算精度和可靠性的算例。文献中几乎大多数算法都对它进行过计算。在本算例中采用有限体积算法三阶迎风型QUICK离散格式对它进行数值求解。同时,为了初学者入门和练习方便,这里给出了用C语言和Fortran77语言编写的计算二维不可压缩黏性方腔流动问题计算程序,供大家学习参考。
F-1利用有限体积算法三阶迎风型QUICK离散格式求解
二维不可压缩黏性流体方腔流动问题
1.二维不可压缩黏性流体方腔流动问题
二维不可压缩黏性流体方腔流动(cavity flow):有一正方形腔室,其量纲为一的宽度为1.0,里面充满静止的不可压缩黏性流体,方腔内初始时刻压力和密度
=1.0它周围壁面(左右壁面和为p=1.0、
底面)固定不动,上壁面以量纲为一的速度1.0沿着上壁面方向自左向右运动(图F.1)。
2. 基本方程组、初始条件和边界条件
设流体是黏性流体。二维方腔流动问题在数学上可以由二维不可压缩黏性流动
N - S
图F.1二维不可压缩黏性
方腔流问题示意图
) u v x y x x
其中u为变量 在水平x方向的流速,v为 在垂直y方向的流速, 为黏度,S 为源项。源项中不仅包含压力梯度项,也包含时间导数项。
初始条件:方腔上壁面以量纲为一的速度1.0沿着上壁面方向自左向右运动。
程序
边界条件:
v均可采用无滑移边界条件,压力p采用自由输出边界条件。 流动速度u、
3.计算网格划分和控制体单元与节点定义
采用交错网格,图F.2和图F.3是计算网格、控制体单元和节点示意图。
图F.2方腔流动计算网格、 控制体单元和节点示意图
图F.3计算采用的交错网格示意图
节点P所在主控制单元如图F.2中有阴影部分所示。在x方向与节点P相邻的节点为W和E,在y方向与节点P相邻的节点为S和N,主控制单元界面分
sen。压力p和速度u、v分别在三套不同网格中如图F.3中有阴影部分别为w、、、
所示。
4.有限体积算法三阶迎风型QUICK离散格式
对方程(F.1)在图F.2所示节点P所在控制体单元内积分,有:
u dV v dV dV dV S dV(F.2) x y x x y y V V V V V由于二维不可压缩黏性流体方腔流动是二维问题,因此控制体单元体积 V仅是面积,而它的边界是长度。设 Aw Ae y,As An x,利用Gauss定理,可将方程(F.2)改写成如下有限体积算法离散格式:
程序
u A e u A w v A n v A s
(F.3)
A A A A S x y
x e x w y n y s
对上式中 、 、 采用一阶向前差分近似,则有: 、
x x y e w n y s
P W E P
,
x x x e x w
N P P S
,
y y y n y s
Fe u eAe,Fw u wAwFn v nAn,Fs v sAs
(F.4)
同时记:
(F.5)
eAe A
,Dw ww, xPE xPW
(F.6)
nAn sAs
Dn ,Ds
yPN yPS
De
则可由式(F.2)写成:
Fe e Fw w Fn n Fs s De E P Dw P W
Dn N P Ds P S S x y
(F.7)
式中 P、 E、 W、 N、 S、De、Dw、Dn、Ds都是控制体单元内节点上的已知量,如果利用差分计算得到控制体单元边界上的流通量Fe e、Fw w、Fn n、Fs s,就可以求出节点上未知量 P、 E、 W、 N、 S。
图F.4三阶迎风型QUICK离散格式示意图
程序
为了便于讨论,现对一维对流扩散方程的三阶迎风型QUICK离散格式进行分析:在三阶迎风型QUICK离散格式中,计算主控制单元界面上流动量 需要取主控制单元界面两侧3个节点处的流动量值进行插值计算得到,其中两个节点位于界面紧邻的两侧,第三个节点位于迎风一侧较远邻点,如图F.4所示。
当ue 0,uw 0时,通过WW、W和P三个节点值拟合曲线来计算主控制单元左侧界面参数 w。通过节点W、P和E三个节点值拟合曲线来计算主控制单元右侧界面参数 e。当ue 0,uw 0,则分别通过节点W、P、E和P、E、EE三个节点值计算主控制单元左、右两侧界面参数 w和 e。根据上述计算原则,可以得到界面参数 w计算公式如下:
当uw 0时,界面参数 w计算公式为:
ww wW wP wWW (F.8a)
当ue 0时,界面参数 w计算公式为:
636
e P E W (F.8b)
888
683868
对于一维无源项一维对流扩散方程三阶迎风型QUICK离散格式: 当ue 0,uw 0时,三阶迎风型QUICK离散格式为:
aP P aW W aE E aWW WW (F.9) 其中
31
aW Dw Fw Fe
883
aE De Fe
8 (F.9a) 1
aWW Fw
8
aP aW aE aWW Fe Fw
同理,若ue 0,uw 0,三阶迎风型QUICK离散格式为:
aP P aW W aE E aEE EE (F.10)
程序
其中
3
aW Dw Fw,
861
aE De Fe Fw,
88 (F.10a) 1aWW Fe
8
aP aW aE aEE Fe Fw
将两种流动方向离散方程(F.9)和(F.10)合并后,可得到统一的一维对流扩散方程三阶迎风型QUICK离散格式:
(F.11) aP P aW W aE E aEE EE aEE EE
其中
613
aW Dw wFw eFe 1 w Fw
8881
aWW wFw
8361
aE De eFe 1 e Fe 1 w Fw (F.11a)
8881
aEE 1 e Fe
8
aP aW aE aWW aEE Fe Fw
式中
当Fw 0时, w 1;
当Fw 0时, w 0;
(F.11b)
当Fe 0时, e 1;当Fe 0时, e 0。
同理,可以得到带有源项的二维对流扩散方程三阶迎风型QUICK离散格式为:
aP P aW W aE E aEE EE aEE EE
aS S aN N aSS SS aNN NN S V
其中 为有限体积算法中源项平均值。式中各个系数为:
(F.12)
程序
613
aW Dw wFw eFe 1 w Fw
8881
aWW wFw
8361
aE De eFe 1 e Fe 1 w Fw
888
1
1 e Fe8
613
aS Ds sFs nFn 1 s Fs
8881
aSS sFs
8361
aN Dn nFn 1 n Fn 1 s Fs
8881
aNN 1 n Fn
8aEE
aP aW aE aWW aEE aS aN aSS aNN Fe Fw Fn Fs (F.12a)
式中
当Fk 0时, k 1;
当Fk 0时, k 0。 (F.12b)
k w,e,s,n
源项 为:
若把 u 表示tn时刻动量, u 格式为:
n
u p
(F.13) t x
n 1
表示tn 1时刻动量,则可以得到源项 离散
V
dV
u P
n 1
u P
n
t
x y pe pw y (F.14)
最后,得到有限体积算法二维对流扩散方程三阶迎风型QUICK离散格式:
nnnnn
aPuP aWuW aEuE aSuS aNuN
u P
n 1
u P
n
t
x y p p
n
e
nw
y
(F.15)
式中系数ak为一阶迎风格式中各对应系数。
程序
5.计算结果分析
利用三阶迎风型QUICK离散格式和相应的初始条件和边界条件,求解二维不可压缩黏性流体方腔流动问题。图F.5是不同雷诺数Re条件下采用三阶迎风型QUICK离散格式得到的二维不可压缩黏性流体方腔流动的计算结果。
计算结果和文献中其他高精度算法得到的计算结果进行了比较,两者计算结果十分吻合,能把方腔下壁面两个底角附近二次小涡清晰地计算出来。这表明有限体积算法三阶迎风型QUICK离散格式具有相当高的计算精度。
Re=100 Re=1 000
图F.5不同雷诺数Re条件下采用三阶迎风型QUICK
离散格式计算二维不可压缩黏性方腔流动的计算结果
Re=5 000 Re=10 000
程序
从图F.5中可以看出:二维不可压缩黏性流体方腔流动的中心大涡并不在中心位置,方腔内流动也并不对称。这是因为,方腔上壁面以量纲为一的速度1.0沿着上壁面方向自左向右运动时,在方腔上壁面两侧的两个顶角处不再满足边界条件,这是一个带奇性的方腔流动。
计算结果表明,方腔流动和雷诺数有关,随着雷诺数Re增加,计算精度在降低。当雷诺数Re较低时,方腔下壁面的两个底角附近的二次小涡十分清晰,随着雷诺数Re的增加,二次小涡变得越来越模糊。由于三阶迎风型QUICK离散格式计算精度较高,因此三阶迎风型QUICK离散格式计算效果一般要比一阶迎风型离散格式相对来说好些。
F-2 二维不可压缩黏性方腔流动问题数值计算源程序
1. C语言源程序
// fvm_quick_cavity.cpp
/*---------------------------------------------------------------------------- !利用有限体积算法三阶迎风型QUICK离散格式和
!人工压缩算法求解方腔流动问题(C语言版本)
-------------------------------------------------------------------------------*/ #include <stdio.h> #include <stdlib.h> #include <math.h> #define MX 100 #define MY 100 #define Re 100.00 #define dt 0.0005 #define c2 2.25
Double u[MX+1][MY+2],v[MX+2][MY+1],p[MX+2][MY+2],
un[MX+1][MY+2],vn[MX+2][MY+1],pn[MX+2][MY+2];
//全局变量
程序
/*------------------------------------------------------- 定义两个要用到的函数
--------------------------------------------------------*/ double max(double a,double b) { if(a<b) return b; else return a; }
double alfa(double x) { if(x>=0) return 1.0; else return 0.0; }
/*------------------------------------------------------------------------ 初始化 入口:无;
出口:u、v、p、dx、dy,初始速度、压强和空间步长。 ---------------------------------------------------------------------------*/
void init(double u[MX+1][MY+2],double v[MX+2][MY+1],double p[MX+2][MY+2], double& dx,double& dy) {
int i,j; dx=1.0/MX; dy=1.0/MY;
for(i=0;i<=MX;i++) { for(j=0;j<=MY+1;j++) { u[i][j]=0.0; if(j==MY+1) u[i][j]=4.0/3.0; if(j==MY) u[i][j]=2.0/3.0; } } for(i=0;i<=MX+1;i++) for(j=0;j<=MY;j++) v[i][j]=0.0; for(i=0;i<=MX+1;i++)
程序
for(j=0;j<=MY+1;j++) p[i][j]=1.0; }
/*----------------------------------------------------------------------------------------------- 一阶迎风型离散格式
二维的三阶迎风型QUICK离散格式为9点格式,因此有两层边界网格需要
处理,本程序采用一阶迎风型离散格式处理内层,用物理边界条件处理外层。 入口:u、v、p、dx、dy、i、j,当前速度、压强,空间步长和网格节点编号; 出口:un,新的x方向速度。
-----------------------------------------------------------------------------------------------*/
void upwind_u(double u[MX+1][MY+2],double v[MX+2][MY+1],double p[MX+2][MY+2], double un[MX+1][MY+2],double dx,double dy,int i,int j) {
double aw,ae,as,an,df,ap,miu; miu=1.0/Re; aw=miu+max(0.5*(u[i-1][j]+u[i][j])*dy,0.0); ae=miu+max(0.0,-0.5*(u[i][j]+u[i+1][j])*dy); as=miu+max(0.5*(v[i][j-1]+v[i+1][j-1])*dx,0.0); an=miu+max(0.0,-0.5*(v[i][j]+v[i+1][j])*dx); df=0.5*(u[i+1][j]-u[i-1][j])*dy+0.5*(v[i][j]+v[i+1][j]-v[i][j-1]-v[i+1][j-1])*dx; ap=aw+ae+as+an+df;
un[i][j]=u[i][j] + dt/dx/dy*(-ap*u[i][j]+aw*u[i-1][j]+ae*u[i+1][j]+as*u[i][j-1]+an*u[i][j+1]) - dt*(p[i+1][j]-p[i][j])/dx; }
/*------------------------------------------------------------------------------------------------ 入口: u、v、p、dx、dy、i、j,当前速度、压强,空间步长和网格节点编号; 出口:vn,新的y方向速度。
-----------------------------------------------------------------------------------------------------*/
void upwind_v(double u[MX+1][MY+2],double v[MX+2][MY+1],double p[MX+2][MY+2], double vn[MX+2][MY+1],double dx,double dy,int i,int j) { double aw,ae,as,an,df,ap,miu; miu=1.0/Re;
aw=miu+max(0.5*(u[i-1][j]+u[i-1][j+1])*dy,0.0); ae=miu+max(0.0,-0.5*(u[i][j]+u[i][j+1])*dy); as=miu+max(0.5*(v[i][j-1]+v[i][j])*dx,0.0); an=miu+max(0.0,-0.5*(v[i][j]+v[i][j+1])*dx); df=0.5*(u[i][j]+u[i][j+1]-u[i-1][j]-u[i-1][j+1])*dy+0.5*(v[i][j+1]-v[i][j-1])*dx; ap=aw+ae+as+an+df; vn[i][j]=v[i][j] + dt/dx/dy*(-ap*v[i][j]+aw*v[i-1][j]+ae*v[i+1][j]+as*v[i][j-1]+an*v[i][j+1]) - dt*(p[i][j+1]-p[i][j])/dy;
程序
}
/*---------------------------------------------------------------------- 三阶迎风型QUICK离散格式
入口:u、v、p、dx、dy,当前速度、压强,空间步长; 出口:un、vn,新的速度。
-----------------------------------------------------------------------*/
void quick(double u[MX+1][MY+2],double v[MX+2][MY+1],double p[MX+2][MY+2], double un[MX+1][MY+2],double vn[MX+2][MY+1],double dx,double dy) { double miu,fw,fe,fs,fn,df,aw,ae,as,an,aww,aee,ass,ann,ap; int i,j;
miu=1.0/Re;
for(i=2;i<=MX-2;i++) { for(j=2;j<=MY-1;j++) {
fw=0.5*(u[i-1][j]+u[i][j])*dy; fe=0.5*(u[i][j]+u[i+1][j])*dy; fs=0.5*(v[i][j-1]+v[i+1][j-1])*dx; fn=0.5*(v[i][j]+v[i+1][j])*dx; df=fe-fw+fn-fs;
aw=miu+0.750*alfa(fw)*fw+0.125*alfa(fe)*fe+0.375*(1.0-alfa(fw))*fw; aww=-0.125*alfa(fw)*fw; ae=miu-0.375*alfa(fe)*fe-0.750*(1.0-alfa(fe))*fe-0.125*(1.0-alfa(fw))*fw; aee=0.125*(1.0-alfa(fe))*fe;
as=miu+0.750*alfa(fs)*fs+0.125*alfa(fn)*fn+0.375*(1.0-alfa(fs))*fs; ass=-0.125*alfa(fs)*fs; an=miu-0.375*alfa(fn)*fn-0.750*(1.0-alfa(fn))*fn-0.125*(1.0-alfa(fs))*fs; ann=0.125*(1.0-alfa(fn))*fn; ap=aw+ae+as+an+aww+aee+ass+ann+df; //aw、ae、as、an...均为有限体积算法中各项系数,详见前文三阶迎风型QUICK离散格式。 un[i][j]=u[i][j]+ dt/dx/dy*(-ap*u[i][j]+aw*u[i-1][j]+ae*u[i+1][j]+as*u[i][j-1]
+an*u[i][j+1]+aww*u[i-2][j]+aee*u[i+2][j]+ass*u[i][j-2]+ann*u[i][j+2])
-dt*(p[i+1][j]-p[i][j])/dx; } }
//------------------------------------------------------------------------------ j=1; for(i=2;i<=MX-2;i++) upwind_u(u,v,p,un,dx,dy,i,j); j=MY; for(i=2;i<=MX-2;i++)
程序
upwind_u(u,v,p,un,dx,dy,i,j); i=1; for(j=1;j<=MY;j++) upwind_u(u,v,p,un,dx,dy,i,j); i=MX-1; for(j=1;j<=MY;j++) upwind_u(u,v,p,un,dx,dy,i,j);
//内层边界由一阶迎风型离散格式得到----------------------------------------- //-------------------------------------------------------------------------------- for(i=1;i<=MX-1;i++) { un[i][0]=-un[i][1]; un[i][MY+1]=2.0-un[i][MY]; } for(j=0;j<=MY+1;j++) { un[0][j]=0.0; un[MX][j]=0.0; }
//外层边界条件按物理边界条件给出
//------------------------------------------------------------------------------- for(i=2;i<=MX-1;i++) { for(j=2;j<=MY-2;j++) { fw=0.5*(u[i-1][j]+u[i-1][j+1])*dy; fe=0.5*(u[i][j]+u[i][j+1])*dy; fs=0.5*(v[i][j-1]+v[i][j])*dx; fn=0.5*(v[i][j]+v[i][j+1])*dx; df=fe-fw+fn-fs;
aw=miu+0.750*alfa(fw)*fw+0.125*alfa(fe)*fe+0.375*(1.0-alfa(fw))*fw; aww=-0.125*alfa(fw)*fw; ae=miu-0.375*alfa(fe)*fe-0.750*(1.0-alfa(fe))*fe-0.125*(1.0-alfa(fw))*fw; aee=0.125*(1.0-alfa(fe))*fe;
as=miu+0.750*alfa(fs)*fs+0.125*alfa(fn)*fn+0.375*(1.0-alfa(fs))*fs; ass=-0.125*alfa(fs)*fs; an=miu-0.375*alfa(fn)*fn-0.750*(1.0-alfa(fn))*fn-0.125*(1.0-alfa(fs))*fs; ann=0.125*(1.0-alfa(fn))*fn; ap=aw+ae+as+an+aww+aee+ass+ann+df; vn[i][j]=v[i][j] + dt/dx/dy*(-ap*v[i][j]+aw*v[i-1][j]+ae*v[i+1][j]+as*v[i][j-1]
+an*v[i][j+1]+aww*v[i-2][j]+aee*v[i+2][j]+ass*v[i][j-2]+ann*v[i][j+2])
- dt*(p[i][j+1]-p[i][j])/dy; } }
程序
//----------------------------------------------------------------------------- j=1;
for(i=2;i<=MX-1;i++) upwind_v(u,v,p,vn,dx,dy,i,j); j=MY-1; for(i=2;i<=MX-1;i++) upwind_v(u,v,p,vn,dx,dy,i,j); i=1; for(j=1;j<=MY-1;j++) upwind_v(u,v,p,vn,dx,dy,i,j); i=MX; for(j=1;j<=MY-1;j++) upwind_v(u,v,p,vn,dx,dy,i,j);
//---------------------------------------------------------------------------- for(i=1;i<=MX;i++) { vn[i][0]=0.0; vn[i][MY]=0.0; } for(j=0;j<=MY;j++) { vn[0][j]=-vn[1][j]; vn[MX+1][j]=-vn[MX][j]; } }
//----------------------------------------------------------------------------
/*---------------------------------------------------------------------------- 更新压强
入口: un、vn、p、dx、dy,新的速度,当前压强,空间步长; 出口: pn,新的压强。
-----------------------------------------------------------------------------*/
void getp(double un[MX+1][MY+2],double vn[MX+2][MY+1],double p[MX+2][MY+2], double pn[MX+2][MY+2],double dx,double dy) { int i,j; for(i=1;i<=MX;i++) for(j=1;j<=MY;j++) pn[i][j]=p[i][j]-dt*c2/dx*(un[i][j]-un[i-1][j]+vn[i][j]-vn[i][j-1]); for(i=1;i<=MX;i++) { pn[i][0]=pn[i][1]; pn[i][MY+1]=pn[i][MY];
程序
} for(j=0;j<=MY+1;j++) { pn[0][j]=pn[1][j]; pn[MX+1][j]=pn[MX][j]; } }
/*------------------------------------------------------ 主程序
-------------------------------------------------------*/ void main() { double dx,dy,err,value,uo,vo,po; int i,j,step; init(u,v,p,dx,dy); err=100.0; step=0; while(err>1e-4 && step<1e6) //err<1e-5,定常解判据;step,限制迭代次数 { printf("step=%d\n",step); step++; err=0.0; quick(u,v,p,un,vn,dx,dy); getp(un,vn,p,pn,dx,dy);
//------------------------------------------------------- for(i=0;i<=MX;i++) { for(j=0;j<=MY+1;j++) { value=fabs(un[i][j]-u[i][j])/dt; if(value>err) err=value; u[i][j]=un[i][j]; } } for(i=0;i<=MX+1;i++) { for(j=0;j<=MY;j++) { value=fabs(vn[i][j]-v[i][j])/dt; if(value>err) err=value; v[i][j]=vn[i][j]; } }
程序
for(i=0;i<=MX+1;i++) { for(j=0;j<=MY+1;j++) { value=fabs(pn[i][j]-p[i][j])/c2/dt; if(value>err) err=value; p[i][j]=pn[i][j]; } } printf("err=%le\n",err);
//-------------------------------------------------------- } //输出结果,用Tecplot数据格式画图
FILE *fp;
fp=fopen("Result.plt","w");
fprintf(fp,"variables=x,y,u,v,p\n zone i=%d,j=%d,f=point\n",MX+1,MY+1); for(i=0;i<=MX;i++) { for(j=0;j<=MY;j++) { uo=0.5*(u[i][j]+u[i][j+1]); vo=0.5*(v[i][j]+v[i+1][j]);
po=0.25*(p[i][j]+p[i+1][j]+p[i][j+1]+p[i+1][j+1]); fprintf(fp,"%20.10e %20.10e %20.10e %20.10e %20.10e\n",i*dx,j*dy,uo,vo,po); } }
fclose(fp);
----------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------
2. Fortran77语言源程序
!———————————————————————————————————— !利用有限体积算法三阶迎风型QUICK离散格式和
!人工压缩算法求解方腔流动问题(Fortran77语言版本)
!———————————————————————————————————— program QUICK_cavity parameter(mx=101,my=101)
程序
implicit double precision(a-h,o-z)
dimension u(mx,my+1),v(mx+1,my),p(mx+1,my+1) dimension un(mx,my+1),vn(mx+1,my),pn(mx+1,my+1) common /ini/u,v,p c2=2.25 re=100.0 dt=0.0005
dx=1.0/float(mx-1) dy=1.0/float(my-1)
!---------------------------------------------------------------------------------------- ! u、v、p为t时刻值,un、vn、pn为t+1时刻值,
! mx、my为最大网格数,c2为虚拟压缩系数的平方,re为雷诺数。 !----------------------------------------------------------------------------------------- num=0 err=100.00
!nun,计数器;err,判断人工压缩法求解收敛的标准 call initial
!调入初始条件,以下为人工压缩算法求解 do while(err.gt.1e-4.and.num.lt.1e6) err=0.0 call quick(u,v,p,un,vn,mx,my,dx,dy,dt,re) !QUICK离散格式求解动量方程,得到un、vn call calp(p,un,vn,pn,mx,my,dx,dy,dt,c2) !求压强pn
call check(u,v,p,un,vn,pn,mx,my,dx,dy,dt,c2,err) !校验流场信息,判断是否收敛,同时更新u、v、p write(*,*) 'error=',err num=num+1 write(*,*) num !屏幕跟踪输出 enddo
call output(u,v,p,mx,my,dx,dy) !输出结果文件 End ! !
subroutine initial !初始化流场 parameter(mx=101,my=101) double precision u(mx,my+1),v(mx+1,my),p(mx+1,my+1) common /ini/u,v,p do i=1,mx+1 do j=1,my+1 p(i,j)=1.0