有限体积法(13)——SIMPLE算法的一维算例

算例模型

本文将使用SIMPLE算法来计算一个简单算例,以展示SIMPLE算法的具体事实过程。计算模型是一个平面喷嘴结构,尺寸数据如下图,假设流动是稳态无粘不可压的,计算速度和压力分布。在这里插入图片描述
参数:
流体密度: 1.0 k g / m 3 1.0 kg/m^3 1.0kg/m3
喷嘴长度: 2 m 2m 2m
截面面积:入口: 0.5 m 2 0.5m^2 0.5m2,出口: 0.1 m 2 0.1m^2 0.1m2,截面面积与距入口距离是线性关系
边界条件:
入口给定滞止压力 10 P a 10Pa 10Pa,出口给定静压 0 P a 0 Pa 0Pa
精确解:
本算例可以使用伯努利方程 p 0 = p N + 1 2 ρ u N 2 p_0=p_N+\frac{1}{2}\rho u^2_N p0=pN+21ρuN2作为解析解,速度使用截面平均速度。

网格划分

采用后向交错网格,如下图,压力节点5个,速度节点4个。
在这里插入图片描述

初始流场和压力场

假设质量流量 m ˙ = 1.0 k g / s \dot m = 1.0 kg/s m˙=1.0kg/s,各截面上的速度用 u = m ˙ / ( ρ A ) u= \dot m /(\rho A) u=m˙/(ρA)来计算。压力场假设是线性分布的,根据入口和出口的边界条件,初始场数据见下表:

节点截面面积 ( m 2 ) (m^2) (m2)初始压力 ( P a ) (Pa) (Pa)初始速度 ( m / s ) (m/s) (m/s)
A0.510
10.452.222
B0.47.5
20.352.857
C0.35
30.254.000
D0.22.5
40.156.667
E0.10

计算过程分析

控制方程进行一维、稳态、无粘、不可压的简化后如下:
质量守恒:
d d x ( ρ A u ) = 0 (1-a) \frac{d}{dx}(\rho A u)=0 \tag{1-a} dxd(ρAu)=0(1-a)

动量守恒:
ρ u A d u d x = − A d p d x (1-b) \rho u A \frac{du}{dx}=-A\frac{dp}{dx} \tag{1-b} ρuAdxdu=Adxdp(1-b)

离散动量方程

对动量方程 ( 1 − b ) (1-b) (1b)进行离散,得
( ρ u A ) e u e − ( ρ u A ) w u w = Δ p Δ x Δ V (2) \begin{aligned} (\rho u A)_e u_e - (\rho u A)_w u_w = \frac{\Delta p}{\Delta x} \Delta V \end{aligned} \tag{2} (ρuA)eue(ρuA)wuw=ΔxΔpΔV(2)
其中 Δ p = p w − p e \Delta p=p_w - p_e Δp=pwpe Δ V \Delta V ΔV是控制单元的体积。

离散动量方程可写成如下标准形式
a P u P ∗ = a W u W ∗ + a E u E ∗ + S u (3) \begin{aligned} a_P u^*_P = a_W u^*_W + a_E u^*_E + S_u \end{aligned} \tag{3} aPuP=aWuW+aEuE+Su(3)

如果对流项采用一阶迎风格式,则系数为
{ a W = D w + m a x ( F w , 0 ) a E = D e + m a x ( 0 , − F e ) a P = a W + a E + ( F e − F w ) (4) \left \{ \begin{aligned} a_W &= D_w + max(F_w, 0)\\ a_E &= D_e + max(0, -F_e)\\ a_P &= a_W + a_E + (F_e-F_w) \end{aligned} \right. \tag{4} aWaEaP=Dw+max(Fw,0)=De+max(0,Fe)=aW+aE+(FeFw)(4)

因为流动是无粘的,所以 D w = D e = 0 D_w = D_e = 0 Dw=De=0 F e F_e Fe F w F_w Fw是通过边界的质量通量,使用边界上的平均速度计算。源项 S u S_u Su只包含压力梯度项,根据几何关系有
S u = Δ p Δ x × Δ V = Δ p Δ x × A a v Δ x = Δ p × 1 2 ( A w + A e ) (5) \begin{aligned} S_u=\frac{\Delta p}{\Delta x} \times \Delta V = \frac{\Delta p}{\Delta x}\times A_{av} \Delta x = \Delta p \times \frac{1}{2} (A_w + A_e) \end{aligned} \tag{5} Su=ΔxΔp×ΔV=ΔxΔp×AavΔx=Δp×21(Aw+Ae)(5)

则离散方程的系数可以简化如下计算:
{ F w = ρ A w u w , F e = ρ A e u e a W = F w a E = 0 a P = a W + a E + ( F e − F w ) S u = Δ p + 1 2 ( A w + A e ) = Δ p × A P (6) \left \{ \begin{aligned} F_w &=\rho A_w u_w, F_e = \rho A_e u_e\\ a_W &=F_w\\ a_E &=0\\ a_P &=a_W + a_E + (F_e -F_w)\\ S_u &= \Delta p + \frac{1}{2}(A_w + A_e)=\Delta p \times A_P \end{aligned} \right. \tag{6} FwaWaEaPSu=ρAwuw,Fe=ρAeue=Fw=0=aW+aE+(FeFw)=Δp+21(Aw+Ae)=Δp×AP(6)

压力修正方程中的系数
d = A a v a P = ( A w + A e ) 2 a P (7) d=\frac{A_{av}}{a_P}= \frac{(A_w+A_e)}{2 a_P} \tag{7} d=aPAav=2aP(Aw+Ae)(7)

压力修正方程

连续性方程 ( 1 − a ) (1-a) (1a)离散后为
( ρ u A ) e − ( ρ u A ) w = 0 (8) \begin{aligned} (\rho u A)_e - (\rho u A)_w = 0 \end{aligned} \tag{8} (ρuA)e(ρuA)w=0(8)
对应的压力修正方程为
a P p P ′ = a W p W ′ + a E p E ′ + b ′ (9) \begin{aligned} a_P p^\prime _P = a_W p^\prime _W + a_E p^\prime _E + b^\prime \end{aligned} \tag{9} aPpP=aWpW+aEpE+b(9)
系数为
{ a W = ( ρ d A ) w a E = ( ρ d A ) e a P = a W + a E b ′ = ( F w ∗ − F e ∗ ) (10) \left \{ \begin{aligned} a_W&=(\rho d A)_w\\ a_E &= (\rho d A)_e\\ a_P &= a_W + a_E\\ b^\prime &=(F^*_w - F^*_e) \end{aligned} \right. \tag{10} aWaEaPb=(ρdA)w=(ρdA)e=aW+aE=(FwFe)(10)

其中参数 d d d即公式 ( 7 ) (7) (7) d d d

速度和压力的修正

得到压力修正量 p ′ p^\prime p后,速度修正量 u ′ u^\prime u以及压力场和速度场的修正用如下公式计算:
{ u ′ = d ( p I ′ − p I + 1 ′ ) p = p ∗ + p ′ u = u ∗ + u ′ (11) \left \{ \begin{aligned} u^\prime &=d(p^\prime _I - p^\prime _{I+1})\\ p &=p^* + p^\prime\\ u &=u^*+u^\prime \end{aligned} \right. \tag{11} upu=d(pIpI+1)=p+p=u+u(11)

边界节点的处理

入口:速度节点1

入口给定的滞止压强 p 0 = 10 P a p_0=10Pa p0=10Pa,可以认为是入口A上游压力室的压强,它等于流体流速为0时的静压值,但A处的实际速度不是0,流动控制方程中的压力指的是静压,因此需要先确定入口A处的静压。这里我们使用伯努利方程来计算:
p A = p 0 − 1 2 ( ρ u A 2 ) (12) \begin{aligned} p_A = p_0 - \frac{1}{2}(\rho u^2_A) \end{aligned} \tag{12} pA=p021(ρuA2)(12)
其中 u A u_A uA 是入口A处的速度值,也是未知量。根据质量守恒,入口速度 u A u_A uA可以按如下方式计算
u A = u 1 A 1 / A A (13) \begin{aligned} u_A = u_1 A_1/A_A \end{aligned} \tag{13} uA=u1A1/AA(13)
将公式 ( 13 ) (13) (13)代入公式 ( 12 ) (12) (12)
p A = p 0 − 1 2 ρ u 1 2 ( A 1 A A ) 2 (14) \begin{aligned} p_A = p_0 - \frac{1}{2} \rho u^2_1 \left( \frac{A_1}{A_A} \right)^2 \end{aligned} \tag{14} pA=p021ρu12(AAA1)2(14)
那么节点1的离散动量方程为
F e u 1 − F w u A = ( p A − p B ) × A 1 (15) \begin{aligned} F_e u_1 - F_w u_A = (p_A - p_B) \times A_1 \end{aligned} \tag{15} Feu1FwuA=(pApB)×A1(15)
根据公式 ( 13 ) (13) (13) F w = ρ u A A A = ρ u 1 A 1 F_w=\rho u_A A_A=\rho u_1 A_1 Fw=ρuAAA=ρu1A1,把公式 ( 13 ) 、 ( 14 ) (13)、(14) (13)(14)代入到公式 ( 15 ) (15) (15)
F e u 1 − F w u 1 A 1 / A A = [ ( p 0 − 1 2 ρ u 1 2 ( A 1 / A A ) 2 ) − p B ] × A 1 (16) \begin{aligned} F_e u_1 - F_w u_1 A_1 / A_A = [(p_0 - \frac{1}{2} \rho u_1^2(A_1/A_A)^2) - p_B] \times A_1 \end{aligned} \tag{16} Feu1Fwu1A1/AA=[(p021ρu12(A1/AA)2)pB]×A1(16)

重新整理一下顺序,得
[ F e − F w A 1 / A A + F w × 1 2 ( A 1 / A A ) 2 ] u 1 = ( p 0 − p B ) A 1 (17) \begin{aligned} [F_e - F_w A_1/A_A + F_w \times \frac{1}{2} (A_1/A_A)^2] u_1 = (p_0 - p_B)A_1 \end{aligned} \tag{17} [FeFwA1/AA+Fw×21(A1/AA)2]u1=(p0pB)A1(17)


这个整理过程可能有点儿绕,感觉需要解释一下,从公式 ( 16 ) (16) (16)到公式 ( 17 ) (17) (17)的推导步骤如下:

  1. 把等号右边方括号中的第二项独立出来,即 − 1 2 ρ u 1 2 ( A 1 / A A ) 2 × A 1 -\frac{1}{2} \rho u_1^2 (A_1/A_A)^2 \times A_1 21ρu12(A1/AA)2×A1;
  2. 把这一项换个造型,就成了 − 1 2 × ρ u 1 A 1 × u 1 ( A 1 / A A ) 2 -\frac{1}{2} \times \rho u_1A_1 \times u_1(A_1/A_A)^2 21×ρu1A1×u1(A1/AA)2;
  3. 利用 F w = ρ u 1 A 1 F_w = \rho u_1 A_1 Fw=ρu1A1,代入这一项中并放到等号右边,就是 F w × 1 2 ( A 1 / A A ) 2 u 1 F_w \times \frac{1}{2}(A_1/A_A)^2 u_1 Fw×21(A1/AA)2u1

这里将 F w F_w Fw看作为系数,就像离散方程中的 a a a一样,虽然它的公式里也包含了 u u u,在离散方程的求解过程中将使用初始速度值或上一步的迭代值来计算系数的值。


因此,节点1的主系数 a P a_P aP
a P = F e − F w A 1 / A A + F w × 1 2 ( A 1 / A A ) 2 (18) \begin{aligned} a_P = F_e - F_w A_1/A_A + F_w \times \frac{1}{2} (A_1/A_A)^2 \end{aligned} \tag{18} aP=FeFwA1/AA+Fw×21(A1/AA)2(18)

上式中等号右边的前两项来自动量方程的对流项,第三项是因在计算压力梯度项时使用了 ( w ) (w) (w)边界上的滞止压力而导致的额外项。在计算内部节点时可以直接使用静压,这一项是不存在的。

公式 ( 17 ) (17) (17)的形式可以直接用于计算,但更好的选择是将 a P a_P aP中的负项拿到右边的源项中,即
[ F e + F w × 1 2 ( A 1 / A A ) 2 ] u 1 = ( p 0 − p B ) A 1 + F w A 1 / A A × u 1 o l d (19) \begin{aligned} [F_e + F_w \times \frac{1}{2}(A_1/A_A)^2]u_1 = (p_0 - p_B)A_1 + F_w A_1/A_A \times u_1^{old} \end{aligned} \tag{19} [Fe+Fw×21(A1/AA)2]u1=(p0pB)A1+FwA1/AA×u1old(19)

这种操作叫做延迟修正法(deferred correction approach),可以提高计算的稳定性。

出口:速度节点4

出口是压力边界,边界条件给的就是静压值,可以直接使用,因此只需要解决出口通量计算问题就OK了。和入口一样,这里也是利用质量守恒关系,
F e = ( ρ u A ) 4 (20) \begin{aligned} F_e = (\rho u A)_4 \end{aligned} \tag{20} Fe=(ρuA)4(20)

计算结果

通过计算发现,网格数太少会导致结果精度不够,数值解和理论解相差较大。增加网格数量就可以明显改善这个问题,但增加网格数后需要适当降低松弛因子,否则计算可能会发散,具体计算结果见下图。

网格数:5

在这里插入图片描述
在这里插入图片描述

网格数:15

在这里插入图片描述
在这里插入图片描述

网格数:25

在这里插入图片描述
在这里插入图片描述

计算程序

import numpy as np
import matplotlib.pyplot as plt
import math
import sys

#== parameters ===
u_nodes_num = p_nodes_num =  5  # number of mesh cells or nodes
alpha = 0.8  # under-relaxation factor
nmax = 2000  # max number of iteration
residual_criteria = 1e-6

length = 2
density = 1
area_A = 0.5
area_E = 0.1
p_0 = 10  # inlet pressure
p_e = 0   # outlet pressure
#===================
# ==== creating mesh ======
xp_grid = np.linspace(0,length,p_nodes_num, endpoint=True) # pressure mesh
print('xp_grid = ',xp_grid)

xu_grid = np.zeros(u_nodes_num) # velocity mesh
for i in range(1,u_nodes_num):
    xu_grid[i] = (xp_grid[i] + xp_grid[i-1])/2
print('xu_grid = ',xu_grid)
#===== preparing constant values ======
area_I = np.linspace(area_A, area_E, p_nodes_num, endpoint=True) 
# area of sections A,B,C,D,E  ( Pressure nodes )

area_i = np.zeros(u_nodes_num) 
for i in range(1,u_nodes_num):
    area_i[i] = (area_I[i] + area_I[i-1])/2
# area of sections of 1,2,3,4 ( Velocity nodes )

# === coefficients =====
au = np.zeros(u_nodes_num)
dd = np.zeros(u_nodes_num)
bb = np.zeros(p_nodes_num)
Aap = np.zeros((p_nodes_num, p_nodes_num))
Bbp = np.zeros(p_nodes_num)


'''
# === display area  ===
plt.xlabel('Distance (m)')
plt.ylabel('A')
plt.plot(xu_grid[1:], area_i[1:] ,'bs', label='area_i')
plt.plot(xp_grid, area_I,'go-', label='area_I')
#plt.title('')
plt.legend()
plt.show()
sys.exit()
'''


#== initialization ==
guessedMassFlowRate = 1  # mass flow rate

uu = np.zeros(u_nodes_num)   # velocity , the index starts with 1
uu[1:] = guessedMassFlowRate/density/area_i[1:]   # initial velocity

uu0 = uu.copy()  # 
uu_residual = np.zeros(u_nodes_num) # residual of velcity

pp = np.linspace(p_0, p_e, p_nodes_num, endpoint=True) # initial pressure

print('initial u = ',uu)
print('initial p = ',pp)
# ==================

#== SIMPLE ALGORITHM ==

for j in range(nmax):
    ##== STEP 1 : solving momentum equations ==
    #== inlet ==
    i = 1
    fw = density * uu[i] * area_i[i]  
    fe = density * area_I[i] * (uu[i] + uu[i+1])/2
    ai = fe + 0.5*fw*(area_i[i]/area_A)**2          #ap
    su = (p_0 - pp[i])*area_i[i] + fw * area_i[i]/area_A * uu[i]  # source term
    uu_residual[i] = abs(ai*uu[i] - su)
    uu[i] = su / ai
    dd[i] = area_i[i]/ai
    #print(uu[i], uu0[i])

    #== internal nodes ==
    for i in range(2,u_nodes_num):
        aw = density * area_I[i-1] * (uu[i]+uu0[i-1])/2   # aw = Fw = (rho * u * A)_w
                                                          # ae = 0
        if i == u_nodes_num-1:
            ai = density * area_i[i] * uu[i]  # outlet
        else:
            ai = density * area_I[i] * (uu[i]+uu[i+1])/2   # ap = aw + ae + (Fe - Fw) 
                                                           #    = Fw + Fe - Fw 
                                                           #    = Fe
                                                           #    = (rho * u * A)_e 

        dd[i] = area_i[i]/ai  # d = a_av / ap
        uu_residual[i] = abs(ai*uu[i] - aw*uu[i-1] - area_i[i]*(pp[i-1]-pp[i]) )
            # according to formula (3), assume ap * up = aw * uw + ae * ue + su + residual. 
            # so, residual = ap * up - aw * uw - ae * ue - su 

        uu[i] = aw/ai * uu[i-1] + dd[i] * (pp[i-1]-pp[i])  # up = aw/ap * uw + su/ap
                                                           #    = aw/ap * uw + d * Delta p

    #print(uu[1:])

    ##== STEP 2: solving pressure correction equation ==
    for I in range(1,p_nodes_num-1):
        Aap[I,I-1] = -density * dd[I] * area_i[I]
        Aap[I,I+1] = -density * dd[I+1] * area_i[I+1]
        bb[I] = density * (area_i[I]*uu[I] - area_i[I+1]*uu[I+1])
        Aap[I,I] = -(Aap[I,I-1] + Aap[I,I+1])

    for i in [0, p_nodes_num-1]:  # inlet and outlet
        Aap[i,i] = 1
        bb[i] = 0

    pp_correction = np.linalg.solve(Aap, bb)  # solve pressure correction equations
    #print(pp_correction)

    ##== STEP 3: correct presure and velocity ==
    for i in range(1,u_nodes_num):
        uu[i] = uu[i] + alpha *dd[i]*(pp_correction[i-1] - pp_correction[i]) 

    pp = pp + alpha *pp_correction
    pp[0] = p_0 - 0.5*density*uu[1]**2 * (area_i[1]/area_A)

    uu0 = uu.copy()
    if j%100==0:
        print('i = ',j, '   u_residul = ', uu_residual.sum())

    if uu_residual.sum() < residual_criteria:
        print('i = ',j, '   u_residul = ', uu_residual.sum())
        break
    if uu_residual.sum() > 1e10:
        print('\ni = ',j, '   u_residul = ', uu_residual.sum(),' @(&_&)@  !!!!!!!!')
        print('Please reduce the under-relaxation factor (alpha) !\n')
        sys.exit()
        

print('mass flow rate = ', density*uu[-1]*area_i[-1])

##== exact solution ==
nodes_excat = 50
area_exact = np.linspace(area_A, area_E, nodes_excat, endpoint=True)
xe_grid = np.linspace(0, length, nodes_excat, endpoint=True)
pp_exact = np.zeros(nodes_excat)
uu_exact = np.zeros(nodes_excat)
for i in range(nodes_excat):
    pp_exact[i] = p_0 - 0.5 * 0.44721**2 /density / area_exact[i]**2
    uu_exact[i] = math.sqrt((p_0 - pp_exact[i])*2/density)


plt.xlabel('Distance (m)')
plt.ylabel('Velocity (m/s)')
plt.plot(xu_grid[1:], uu[1:] ,'bs--', label='Numerical')
plt.plot(xe_grid, uu_exact,'k', label='Exact')
plt.title('velocity')
plt.legend()


plt.figure(2)
plt.xlabel('Distance (m)')
plt.ylabel('Pressure (Pa)')
plt.plot(xp_grid, pp ,'bs--', label='Numerical')
plt.plot(xe_grid, pp_exact,'k', label='Exact')
plt.title('Pressure')
plt.legend()

plt.show()

参考资料

  1. Versteeg H K , Malalasekera W . An introduction to computational fluid dynamics : the finite volume method = 计算流体动力学导论[M]. 世界图书出版公司, 2010.
  • 18
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 有限体积(FVM)是CFD中常用的数值解之一,它基于物理守恒定律和连续性方程,通过将物理空间离散为有限体积单元,对体积单元内的物理量(如质量、动量、能量等)进行积分平均,进而得到时间上的耦合差分方程。 cfdferziger算例代码是FVM方的一种实现方式,是由CFD领域知名专家Ferziger和Perić所编写。该代码实现了多种边界条件和流体模型,包括Incompressible NS方程、RANS方程、LES模型等,适用于单相、多相和复杂流动等不同模型下的应用。 cfdferziger算例代码可以在不同的平台上进行编译和运行,支持串并行计算,同时还提供了多种输出格式和可视化工具,方便用户对计算结果进行分析和解释。 总的来说,cfdferziger算例代码是一个成熟的、可靠的、多功能的CFD计算工具,为从事流体力学、数值计算和工程设计等领域的研究人员和工程师提供了很好的支持和帮助。 ### 回答2: 有限体积(Finite Volume Method,FVM)是一种流体力学数值模拟方,其核心思想是将物理空间分割成一个个控制体,根据物理守恒定律,在每个控制体上进行平衡方程的离散化处理,最终求解控制体边界上的通量,从而得到整个流场的物理量分布。 cfdferziger 是一位德国学者,他编写了一个基于有限体积流体力学求解器,可用于求解不可压缩流动和其他热流问题。该求解器的源代码被公开发布,成为了一种广泛应用的计算流体力学(Computational Fluid Dynamics,CFD)开源代码,有许多研究者在此基础上开发了各种流动模拟软件。 cfdferziger 的算例代码是一套已经编写好的流动模拟程序,可以用来模拟各种流动场景,例如湍流流动、圆柱绕流、颗粒运动等等。用户可以根据需要调整代码中的参数,进行自己感兴趣的模拟。 有限体积求解器和算例代码的应用范围很广,常见的应用包括:工业流体力学、环境保护、医疗设备设计等领域。通过模拟不同场景下的流动、温度、浓度等参数分布,可以帮助工程设计师优化设计方案、改进生产工艺,同时也有助于环境监测与预测等工作。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值