参考:

此篇讨论基于有限差分法直观的阐述数值求解思路,对有限差分法有了解的可以直接跳过此篇。

我们有流体力学基本方程的通用形式如下

t(ρϕ)+(ρUϕ)=(Γϕ)+Sϕ\frac{\partial}{\partial t}(\rho \phi) + \nabla \cdot (\rho U\phi) = \nabla\cdot(\Gamma\nabla\phi) + S_{\phi}

方程中包含了不同的偏导项,偏导项在数值计算中怎么处理呢?

有限差分法是最直观的偏微分方程的数值求解方法。虽然目前很多的流体计算方法是基于有限体积法开发的,但是有限体积法中的离散格式也会涉及到基于有限差分的离散格式。

所以,有限差分思想很重要。我们从数值计算思路出发,了解有限差分法的基本格式,具体到偏微分方程的数值计算思路,掌握有限差分思想。

数值计算思路

对于某一类类似的物理现象,科学家总是能找出其中的物理规律,建立物理模型。然后使用数学工具分析,得到描述该物理现象的一个或者一组数学方程(常微分方程 ODE 或偏微分方程 PDE),也就是使用数学方程来描述某个物理场在空间和时间中的连续变化情况。这类方程大多过于复杂而难以直接解析求解,比如复杂的常微分方程组和偏微分方程组。

科学家提出对连续数学方程的数值求解方法,也就是建立对求解空间和时间的有限离散,也就是使用有限数量的空间节点和时间节点代替连续的物理区域和时间区间。每个离散点上都可以通过某些数学方法求得数值。当离散点无穷多的时候,计算得到各个离散点上的物理量可以近似认为是连续的,也就是得到了整个连续物理场,也就是近似求得了原数学方程的数值解。不过,离散点总归是有限的,使用有限的离散点去近似代替连续的时空物理量场总是有误差的。当误差能满足科研或者生产要求时,我们认为数值求解结果是正确的,可以指导科研和生产。

一般来说,数值方法的通用思路如下:

微分方程

(有限差分法或有限体积法等)

离散方程

(矩阵组装)

线性代数求解

数值解

怎么去离散连续的数学方程呢?下面通过有限差分法详细介绍数值计算。

差分格式

|275

如上图所示,有连续方程方程 f(x)f(x) ,该连续函数在 x+Δxx+\Delta x 处的准确值应该是点 2 处的函数值。怎么去求点 2 的函数值呢?

xx 的连续函数 f(x)f(x) 作泰勒展开,有

f(x+Δx)=f(x)+fxΔx+2fx2(Δx)22+...f(x+\Delta x)=f(x)+\frac{\partial f}{\partial x}\Delta x+\frac{\partial^2f}{\partial x^2}\frac{(\Delta x)^2}{2} + ...

我们可以对物理量 ϕ\phi 进行以下的泰勒展开

ϕi+1,j=ϕi,j+(ϕx)i,jΔx+(2ϕx2)i,j(Δx)22+(3ϕx3)i,j(Δx)36+...(1)\phi_{i+1,j} = \phi_{i,j} + (\frac{\partial\phi}{\partial x})_{i,j}\Delta x + (\frac{\partial^2\phi}{\partial x^2})_{i,j}\frac{(\Delta x)^2}{2} + (\frac{\partial^3\phi}{\partial x^3})_{i,j}\frac{(\Delta x)^3}{6}+...\tag{1}

ϕi1,j=ϕi,j(ϕx)i,jΔx+(2ϕx2)i,j(Δx)22(3ϕx3)i,j(Δx)36+...(2)\phi_{i-1,j} = \phi_{i,j} - (\frac{\partial\phi}{\partial x})_{i,j}\Delta x + (\frac{\partial^2\phi}{\partial x^2})_{i,j}\frac{(\Delta x)^2}{2} - (\frac{\partial^3\phi}{\partial x^3})_{i,j}\frac{(\Delta x)^3}{6}+...\tag{2}

注意展开式(1)和(2)都带了省略号,即两边严格相等,没有近似处理。

式(1)移项,整理得到一阶偏导数的一阶向前差分(前项 - 本项)

(ϕx)i,j=ϕi+1,jϕi,jΔx+O(Δx)(3)(\frac{\partial\phi}{\partial x})_{i,j} = \frac{\phi_{i+1,j}-\phi_{i,j}}{\Delta x} + O(\Delta x) \tag{3}

式(2)移项,整理得到一阶偏导数的一阶向后差分(本项 - 后项)

(ϕx)i,j=ϕi,jϕi1,jΔx+O(Δx)(4)(\frac{\partial\phi}{\partial x})_{i,j} = \frac{\phi_{i,j}-\phi_{i-1,j}}{\Delta x} + O(\Delta x) \tag{4}

式(1)减去式(2)得到一阶偏导数的二阶中心差分

(ϕx)i,j=ϕi+1,jϕi1,j2Δx+O(Δx)2(5)(\frac{\partial\phi}{\partial x})_{i,j} =\frac{\phi_{i+1,j}-\phi_{i-1,j}}{2\Delta x} + O(\Delta x)^2 \tag{5}

式(1)加上式(2)得到二阶偏导数的二阶中心差分

(2ϕx2)i,j=ϕi+1,j2ϕi,j+ϕi1,j2Δx+O(Δx)2(6)(\frac{\partial^2\phi}{\partial x^2})_{i,j} = \frac{\phi_{i+1,j}-2\phi_{i,j} + \phi_{i-1,j}}{2\Delta x} + O(\Delta x)^2 \tag{6}

式(3)(4)(5)(6)带有高阶项,所以两边也是严格相等,没有近似处理。

对于混合偏导数,可以对一阶偏微分作以下的泰勒展开

(ϕy)i+1,j=(ϕy)i,j+(2ϕxy)i,jΔx+(3ϕx2y)i,j(Δx)22+(4ϕx3y)i,j(Δx)36+...(\frac{\partial\phi}{\partial y})_{i+1,j} = (\frac{\partial\phi}{\partial y})_{i,j} + (\frac{\partial^2\phi}{\partial x\partial y})_{i,j}\Delta x + (\frac{\partial^3\phi}{\partial x^2\partial y})_{i,j}\frac{(\Delta x)^2}{2} + (\frac{\partial^4\phi}{\partial x^3\partial y})_{i,j}\frac{(\Delta x)^3}{6} + ...

(ϕy)i1,j=(ϕy)i,j(2ϕxy)i,jΔx+(3ϕx2y)i,j(Δx)22+(4ϕx3y)i,j(Δx)36+...(\frac{\partial\phi}{\partial y})_{i-1,j} = (\frac{\partial\phi}{\partial y})_{i,j} - (\frac{\partial^2\phi}{\partial x\partial y})_{i,j}\Delta x + (\frac{\partial^3\phi}{\partial x^2\partial y})_{i,j}\frac{(\Delta x)^2}{2} + (\frac{\partial^4\phi}{\partial x^3\partial y})_{i,j}\frac{(\Delta x)^3}{6} + ...

上面第一式减去第二式得到

(2ϕxy)i,j=(ϕy)i+1,j(ϕy)i1,j2Δx+(4ϕx3y)i,j(Δx)212+...(\frac{\partial^2\phi}{\partial x\partial y})_{i,j} = \frac{(\frac{\partial\phi}{\partial y})_{i+1,j}-(\frac{\partial\phi}{\partial y})_{i-1,j}}{2\Delta x} + (\frac{\partial^4\phi}{\partial x^3\partial y})_{i,j}\frac{(\Delta x)^2}{12} +...

偏导项替换为下面的一阶偏微分的二阶中心差分格式(保持精度一致)(仅对 y 方向)

(ϕy)i+1,j=ϕi+1,j+1ϕi+1,j12Δy+O(Δy)2(\frac{\partial\phi}{\partial y})_{i+1,j} = \frac{\phi_{i+1,j+1}-\phi_{i+1,j-1}}{2\Delta y} + O(\Delta y)^2

(ϕy)i1,j=ϕi1,j+1ϕi1,j12Δy+O(Δy)2(\frac{\partial\phi}{\partial y})_{i-1,j} =\frac{\phi_{i-1,j+1}-\phi_{i-1,j-1}}{2\Delta y} + O(\Delta y)^2

(2ϕxy)i,j=ϕi+1,j+1ϕi+1,j1ϕi1,j+1+ϕi1,j14ΔxΔy+O[(Δx)2,(Δy)2](7)(\frac{\partial^2\phi}{\partial x\partial y})_{i,j} =\frac{\phi_{i+1,j+1}-\phi_{i+1,j-1}-\phi_{i-1,j+1}+\phi_{i-1,j-1}}{4\Delta x\Delta y} + O[(\Delta x)^2,(\Delta y)^2] \tag{7}

当然,我们还可以构造推导出更多形式更高精度的差分格式。对于常见的大多数的 CFD 计算,偏导处理到二阶精度已经足够。在实际的数值计算中,我们可以省略高阶项,将偏导项替换成线性代数项,从而进行后续计算。

多项式构造差分

我们通过边界的处理,来简单介绍一些差分格式的多项式构造方法。

|225

对于上图这种情况,边界点 1 上可以构造一阶精度的差分格式

(ϕy)1=ϕ2ϕ1Δy+O(Δy)(\frac{\partial \phi}{\partial y})_1 = \frac{\phi_2-\phi_1}{\Delta y} + O(\Delta y)

但是想构造二阶精度差分格式就比较困难,因为边界上缺失一侧的构造点。

例如

(ϕy)1=ϕ2ϕ22Δy+O(Δy)2\cancel{(\frac{\partial \phi}{\partial y})_1 = \frac{\phi_2 - \phi_2^{'}}{2\Delta y} + O(\Delta y)^2}

我们在边界上可以通过多项式构造高精度的差分格式

假设物理量 ϕ\phi 在这么一段微小离散尺度上是连续的,那么可以用多项式描述

ϕ=a+by+cy2(8)\phi = a + by + cy^2 \tag{8}

那么,在图上 1 点,有 y=0y = 0

ϕ1=a\phi_1 = a

在图上 2 点,y=Δyy = \Delta y

ϕ2=a+bΔy+c(Δy)2\phi_2 = a + b\Delta y + c(\Delta y)^2

在图上 3 点,y=2Δyy = 2\Delta y

ϕ2=a+b(2Δy)+c(2Δy)2\phi_2 = a + b(2\Delta y) + c(2\Delta y)^2

由这三点可以求解得到 bb

b=3ϕ1+4ϕ2ϕ32Δyb = \frac{-3\phi_1 + 4\phi_2-\phi_3}{2\Delta y}

在对式(8)求 y 偏导

ϕy=b+2cy\frac{\partial\phi}{\partial y}=b + 2cy

在边界处,y=0y = 0

(ϕy)1=b(\frac{\partial\phi}{\partial y})_1=b

得到单侧差分格式(和泰勒展开的项进行对比,可以知道此表达式的精度为二阶精度)

(ϕy)1=3ϕ1+4ϕ2ϕ32Δy+O(Δy)2(\frac{\partial\phi}{\partial y})_1=\frac{-3\phi_1 + 4\phi_2-\phi_3}{2\Delta y}+O(\Delta y)^2

类似的,我们可以使用多项式方法构造使用更多点信息的更高精度差分格式,以保证边界上计算准确。

差分格式具体怎么用在偏微分方程的求解上呢?

我们通过简单的问题举例说明。

差分方程的构造

以一维非稳态热传导方程为例(材料总长 L

Tt=α2Tx2\frac{\partial T}{\partial t}=\alpha\frac{\partial^2T}{\partial x^2}

左侧为时间项,右侧为扩散项,该方程没有对流项和源项

如果是 Dirichlet 边界条件

{T(0,t)=TrT(L,t)=Tl\begin{cases} T(0,t) &= Tr \\ T(L,t) &= Tl \end{cases}

如果是 Neumann 边界条件

{Tx(0,t)=Tr(t)Tx(L,t)=Tl(t)\begin{cases} \frac{\partial T}{\partial x}(0,t) = T^{'}_r(t) \\ \frac{\partial T}{\partial x}(L,t) = T^{'}_l(t) \end{cases}

初始条件

T(x,0)=T0(x)T(x,0) = T_0(x)

离散

将计算域划分成 nxnx 个单元,时间步长 dtdt ,计算时间步 ntnt 步,所以

每个单元的长度为

dx=L/nxdx = L / nx

总计算时间为

tt=dtnttt = dt * nt

我们采用 C++ 的序号约定,即从 0 开始。

右边界节点 T0T_0

中间节点从右向左依次是

T1,T2,T3,...,Tnx1T_1,T_2,T_3,...,T_{nx-1}

左边界节点 TnxT_{nx}

如果使用上面的 Dirichlet 边界条件,则

{T0=TrTnx=Tl\begin{cases} T_0 = T_r \\ T_{nx} = T_l \end{cases}

如果使用上面的 Neumann 边界条件,则

显式构造

利用差分格式得到差分方程为

Tin+1TinΔt=αTi+1n2Tin+Ti1n(Δx)2\frac{T^{n+1}_i-T^{n}_i}{\Delta t}=\alpha\frac{T^{n}_{i+1}-2T^{n}_{i}+T^{n}_{i-1}}{(\Delta x)^2}

  • 上标 nn 为当前时间步,已知量
  • 上标 n+1n+1 为下一时间步,待求未知量
  • 下标 ii 为当前点,i1i-1 为上一点, i+1i+1 为下一点

整理后可得

Tin+1=Tin+αΔt(Δx)2(Ti+1n2Tin+Ti1n)T^{n+1}_i=T^{n}_i+\alpha\frac{\Delta t}{(\Delta x)^2}(T^{n}_{i+1}-2T^{n}_{i}+T^{n}_{i-1})

方程左边为待求未知量,右侧为已知量。

这种类型的表达式可以直接迭代求解。即显式的按时间推进求解,通过每一个时间步的旧值可以算出下一个时间步的新值。

隐式构造

如果我们处理差分方程得到如下形式

Tin+1TinΔt=αTi+1n+1+Ti+1n22(Tin+1+Tin2)+Ti1n+1+Ti1n2(Δx)2\frac{T^{n+1}_i-T^{n}_i}{\Delta t}=\alpha\frac{\frac{T^{n+1}_{i+1}+T^{n}_{i+1}}{2}-2(\frac{T^{n+1}_{i}+T^{n}_{i}}{2})+\frac{T^{n+1}_{i-1}+T^{n}_{i-1}}{2}}{(\Delta x)^2}

这种引入新时间步与旧时间步之间平均值的格式被称为克兰克 - 尼科尔森格式。这种格式下,新时间步的未知量不止是 Tin+1T^{n+1}_i ,而且还有 Ti+1n+1T^{n+1}_{i+1}Ti1n+1T^{n+1}_{i-1}

整理上式有

αΔt2(Δx)2Ti1n+1[1+αΔt(Δx)2]Tin+1+αΔt2(Δx)2Ti+1n+1=TinαΔt2(Δx)2(Ti+1n2Tin+Ti1n)\begin{aligned} \frac{\alpha\Delta t}{2(\Delta x)^2}T^{n+1}_{i-1} &- \bigg[1 + \frac{\alpha\Delta t}{(\Delta x)^2}\bigg]T_i^{n+1} + \frac{\alpha\Delta t}{2(\Delta x)^2}T_{i+1}^{n+1} \\ &= -T_i^n - \frac{\alpha\Delta t}{2(\Delta x)^2}(T_{i+1}^{n} - 2T_i^n + T_{i-1}^n) \end{aligned}

方程的左侧的三项都是待求未知量,右侧是已知量。

这种格式不能再按时间推进求解,而必须列出完整代数方程组,即构建 Ax=bAx = b, 同时求出所有的未知量。这种方法就是隐式求解。

比较

显式构造看起来更加直观,算法和编程实现也更加方便。但是时间步长和空间步长必须要取很小才能保持计算稳定

回忆数值计算课程中的误差分析部分。
稳定性也是计算流体力学中一个重点,这里暂不深究。

隐式构造有点在于使用大得多的时间步长也能保持计算稳定。但是算法和编程实现更复杂,因为时间步长取的较大,也会导致时间上不够精确(对于一些求定常发展状态的流动,时间精确其实无所谓)。

求解一维传热方程

我们通过一个完整的问题来进一步讨论有限差分法的应用。

对于一维传热问题(热扩散问题),控制方程如下

Tt=α2Tx2\frac{\partial T}{\partial t}=\alpha\frac{\partial^2T}{\partial x^2}

边界条件如下:

{TL=1.0TR=1.0\begin{cases} T_L = -1.0 \\ T_R = 1.0 \end{cases}

我们对该方程分别进行显式和隐式数值计算

显式计算

算法

离散方程为

Tin+1TinΔt=αTi+1n2Tin+Ti1n(Δx)2\frac{T^{n+1}_i-T^{n}_i}{\Delta t}=\alpha\frac{T^{n}_{i+1}-2T^{n}_{i}+T^{n}_{i-1}}{(\Delta x)^2}

整理后为

Tin+1=Tin+αΔt(Δx)2(Ti+1n2Tin+Ti1n)T^{n+1}_i=T^{n}_i+\alpha\frac{\Delta t}{(\Delta x)^2}(T^{n}_{i+1}-2T^{n}_{i}+T^{n}_{i-1})

实现

#todo