二、SWE 的运动机制
SWE 的运动机制可以理解成:水面坡度改变流速,流动的汇聚和发散改变水深。
假设你在平静水面中央制造一个隆起:
- 中央与周围出现水面高度差。
- 高度差产生水平压力梯度,使水向周围加速。
- 中央流出的水多,水面下降;周围得到水,水面上升。
- 当水面暂时变平时,水仍然具有速度。
- 水继续运动,产生新的凹陷和隆起,扰动由此向外传播。
所以,SWE 需要同时保存"水有多少"和"水如何运动"。
这也解释了为什么:仅根据当前高度图,通常不能唯一决定下一时刻的水面。 两片形状完全相同的水面,可能一个正在向外流动,另一个正在向内汇聚,它们下一刻的变化会不同。
1、质量守恒
对于密度恒定的水,质量守恒等价于体积守恒。
不可压缩流体的三维连续性方程(散度形式):
∂u∂x+∂w∂y+∂v∂z=0 \frac{\partial u}{\partial x} + \frac{\partial w}{\partial y} + \frac{\partial v}{\partial z} = 0 ∂x∂u+∂y∂w+∂z∂v=0
考虑水平面积为 A 的一个网格单元,内部水的体积为:
V=Ah V = Ah V=Ah
若流入、流出的体积流量分别为 Qin、Qout,那么:
dVdt=Qin−Qout \frac{dV}{dt} = Q_{in} - Q_{out} dtdV=Qin−Qout
因此:
dhdt=Qin−QoutA \frac{dh}{dt} = \frac{Q_{in} - Q_{out}}{A} dtdh=AQin−Qout
例如,面积为1m^2的单元,每秒流入 0.03m^3、流出 0.01m^3,水深就每秒增加 0.02m。
把这个关系写成连续空间中的方程:
∂h∂t+∂(hu)∂x+∂(hv)∂z=0 \frac{\partial h}{\partial t} + \frac{\partial(hu)}{\partial x} + \frac{\partial(hv)}{\partial z} = 0 ∂t∂h+∂x∂(hu)+∂z∂(hv)=0
其中:
- hu:沿 x 方向的单位宽度体积流量;
- hv:沿 z 方向的单位宽度体积流量;
- 后两项之和:一个位置附近净流出的程度。
净流出为正,水深下降;净流入为正,水深上升。这就是没有外部水源时的连续性方程。
展开可以得到:
∂h∂t+u∂h∂x+v∂h∂z=−h(∂u∂x+∂v∂z) \frac{\partial h}{\partial t} + u\frac{\partial h}{\partial x} + v\frac{\partial h}{\partial z} = -h\left( \frac{\partial u}{\partial x} + \frac{\partial v}{\partial z} \right) ∂t∂h+u∂x∂h+v∂z∂h=−h(∂x∂u+∂z∂v)
右侧括号内是水平速度的散度:
∇⋅u=∂u∂x+∂v∂z \nabla\cdot\boldsymbol{u} = \frac{\partial u}{\partial x} + \frac{\partial v}{\partial z} ∇⋅u=∂x∂u+∂z∂v
跟随水流观察时:
- 速度场向外发散,水柱被摊开,水深减小;
- 速度场向内汇聚,水被堆积,水深增大。
水本身没有被压缩,改变的是水柱的形状。
2、水平动量方程
另外两条核心方程是水平动量方程,它们决定流速怎样变化。
先考虑固定底床,并忽略摩擦、风力和地球自转:
∂u∂t+u∂u∂x+v∂u∂z=−g∂η∂x \frac{\partial u}{\partial t} + u\frac{\partial u}{\partial x} + v\frac{\partial u}{\partial z} = -g\frac{\partial\eta}{\partial x} ∂t∂u+u∂x∂u+v∂z∂u=−g∂x∂η
∂v∂t+u∂v∂x+v∂v∂z=−g∂η∂x \frac{\partial v}{\partial t} + u\frac{\partial v}{\partial x} + v\frac{\partial v}{\partial z} = -g\frac{\partial\eta}{\partial x} ∂t∂v+u∂x∂v+v∂z∂v=−g∂x∂η
这两条式子结构相同,只是分别描述两个水平方向。
∂u∂t⏟固定位置的流速变化+u∂u∂x+v∂u∂z⏟流动带来的对流加速度=−g∂η∂x⏟水面坡度引起的加速度 \underbrace{\frac{\partial u}{\partial t}}{\text{固定位置的流速变化}} + \underbrace{ u\frac{\partial u}{\partial x} + v\frac{\partial u}{\partial z} }{\text{流动带来的对流加速度}} = \underbrace{ -g\frac{\partial\eta}{\partial x} }_{\text{水面坡度引起的加速度}} 固定位置的流速变化 ∂t∂u+流动带来的对流加速度 u∂x∂u+v∂z∂u=水面坡度引起的加速度 −g∂x∂η
"对流加速度"可以这样理解:水流到了另一个速度不同的位置,跟随这团水观察,它的速度就会发生变化。
右边的负号表示,重力所产生的压力作用会使水沿水面降低的方向加速。水面坡度决定的是加速度,而不是直接决定速度。 因此,水面刚变平时,水仍然可能继续流动。
压力项的来源也很直观。静水压力近似为:
p=ρg(η−Y) p=\rho g(\eta-Y) p=ρg(η−Y)
这里使用相对于大气压的压力。在相同竖直高度 Y 上,水面越高,上方压着的水越多,压力越大:
−1ρ∂p∂x=−g∂η∂x -\frac{1}{\rho}\frac{\partial p}{\partial x} = -g\frac{\partial\eta}{\partial x} −ρ1∂x∂p=−g∂x∂η
这就得到了动量方程中的驱动力。
2.1 动量
动量(Momentum):是流体带有的"运动的力量"。
p=mv p = mv p=mv
2.2 动量通量
通量(Flux):单位时间内,垂直穿过单位面积的某种物理量。
动量通量(Momentum Flux)就是指:单位时间内,通过单位面积的动量。
动量通量=ρu⊗u 动量通量 = \rho u ⊗ u 动量通量=ρu⊗u
其中 ρ 是密度,u 是速度矢量,⊗ 是张量积。
如果把它展开,在二维(x, z 平面)的浅水方程中,动量通量张量大概长这样:
ρu2ρuwρwuρw2\] \\begin{bmatrix} \\rho u\^2 \& \\rho uw \\\\ \\rho wu \& \\rho w\^2 \\end{bmatrix} \[ρu2ρwuρuwρw2
- 对角线上的 ρu² 和 ρw² 叫做正应力(相当于水流动带来的动压)。
- 非对角线上的 ρuw 叫做剪应力(不同方向水流交错摩擦、拉扯带来的力)。
2.3 三维 N-S 方程
对于不可压缩、无粘性的流体,三维 N-S 方程在 xx 方向的动量方程为:
∂u∂t+u∂u∂x+v∂u∂y+w∂u∂z=−1ρ∂p∂x+fx \frac{\partial u}{\partial t} + u\frac{\partial u}{\partial x} + v\frac{\partial u}{\partial y} + w\frac{\partial u}{\partial z} = -\frac{1}{\rho}\frac{\partial p}{\partial x} + f\mathrm{x} ∂t∂u+u∂x∂u+v∂y∂u+w∂z∂u=−ρ1∂x∂p+fx
其中 u, v, w 分别是 x, y, z 方向的速度, y 是竖直方向,p 是压强, fx 是外力。
2.4 x 方向动量守恒方程。
2.4.1 从三维N-S方程出发(x方向)
利用连续性方程(质量守恒的散度形式),我们可以将左边的对流项(非线性项)改写为守恒形式(Flux form,把所有东西都塞进偏导数里面的形式):
∂u∂x+∂v∂y+∂w∂z=0 \frac{\partial u}{\partial x} + \frac{\partial v}{\partial y} + \frac{\partial w}{\partial z} = 0 ∂x∂u+∂y∂v+∂z∂w=0
代入 N-S 方程:
∂u∂t+u∂u∂x+v∂u∂y+w∂u∂z+u(∂u∂x+∂v∂y+∂w∂z)=−1ρ∂p∂x+fx \frac{\partial u}{\partial t} + u\frac{\partial u}{\partial x} + v\frac{\partial u}{\partial y} + w\frac{\partial u}{\partial z} + u(\frac{\partial u}{\partial x} + \frac{\partial v}{\partial y} + \frac{\partial w}{\partial z}) = -\frac{1}{\rho}\frac{\partial p}{\partial x} + f\mathrm{x} ∂t∂u+u∂x∂u+v∂y∂u+w∂z∂u+u(∂x∂u+∂y∂v+∂z∂w)=−ρ1∂x∂p+fx
∂u∂t+2u∂u∂x+(v∂u∂y+u∂v∂y)+(w∂u∂z+u∂w∂z)=−1ρ∂p∂x+fx \frac{\partial u}{\partial t} + 2u\frac{\partial u}{\partial x} + (v\frac{\partial u}{\partial y} + u\frac{\partial v}{\partial y}) + (w\frac{\partial u}{\partial z} + u\frac{\partial w}{\partial z}) = -\frac{1}{\rho}\frac{\partial p}{\partial x} + f\mathrm{x} ∂t∂u+2u∂x∂u+(v∂y∂u+u∂y∂v)+(w∂z∂u+u∂z∂w)=−ρ1∂x∂p+fx
整理得:
∂u∂t+∂u2∂x+∂uv∂y+∂uw∂z=−1ρ∂p∂x+fx \frac{\partial u}{\partial t} + \frac{\partial u^2}{\partial x} + \frac{\partial uv}{\partial y} + \frac{\partial uw}{\partial z} = -\frac{1}{\rho}\frac{\partial p}{\partial x} + f\mathrm{x} ∂t∂u+∂x∂u2+∂y∂uv+∂z∂uw=−ρ1∂x∂p+fx
2.4.2 沿水深 y 方向积分
由于浅水方程得核心假设是:水平尺度远大于垂直尺度,那么我们假设垂直方向的加速度可以忽略不记,那么有:
v∂u∂y≈u∂v∂y≈0 v\frac{\partial u}{\partial y} \approx u\frac{\partial v}{\partial y} \approx0 v∂y∂u≈u∂y∂v≈0
将上述方程从水底 b(x, z)积分到水面 η(x,z,t):
∫bη∂u∂tdy=∂∂t∫bηudy=∂hu∂t \int_{b}^{\eta} \frac{\partial u}{\partial t} dy = \frac{\partial}{\partial t} \int_{b}^{\eta} udy = \frac{\partial hu}{\partial t} ∫bη∂t∂udy=∂t∂∫bηudy=∂t∂hu
∫bη∂(u2)∂xdy=∂∂x∫bηu2dy=∂(hu2)∂x \int_{b}^{\eta} \frac{\partial (u^2)}{\partial x} dy = \frac{\partial}{\partial x}\int_{b}^{\eta} u^2dy = \frac{\partial (hu^2)}{\partial x} ∫bη∂x∂(u2)dy=∂x∂∫bηu2dy=∂x∂(hu2)
∫bη∂(uw)∂zdy=∂∂z∫bηuwdy=∂(huw)∂z \int_{b}^{\eta} \frac{\partial (uw)}{\partial z} dy = \frac{\partial}{\partial z}\int_{b}^{\eta} uwdy = \frac{\partial (huw)}{\partial z} ∫bη∂z∂(uw)dy=∂z∂∫bηuwdy=∂z∂(huw)
将 w 改为 v,表示 z 方向上的水流速度。
2.4.3 处理压强梯度项
根据静水压强假设,任意深度 yy 处的压强由上方水柱的重量产生:
p(y)=ρg(η−y) p(y) = ρg(η−y) p(y)=ρg(η−y)
(其中 η 是水面高度,ρ 是密度,g 是重力加速度)
将其代入积分(利用莱布尼茨积分法则,并考虑到水面 ηη 和水底 bb 随 xx 的变化):
−1ρ∫bη∂p∂xdy=−g∫bη∂(η−y)∂xdy=−gh∂η∂x -\frac{1}{\rho}\int_{b}^{\eta} \frac{\partial p}{\partial x}dy = - g\int_{b}^{\eta} \frac{\partial (\eta - y)}{\partial x}dy = - gh\frac{\partial \eta}{\partial x} −ρ1∫bη∂x∂pdy=−g∫bη∂x∂(η−y)dy=−gh∂x∂η
2.4.4 处理底坡/外力项
方程右边还有一个重力在底坡上的分量 fx,重力沿坡面的分力为:
fx=−g∂b∂x f\mathrm{x} = -g\frac{\partial b}{\partial x} fx=−g∂x∂b
积分后(考虑到 hh 的厚度):
∫bηfxdy=−gh∂b∂x \int_{b}^{\eta} f\mathrm{x} dy = -gh\frac{\partial b}{\partial x} ∫bηfxdy=−gh∂x∂b
2.4.5 合并与化简
最终得到:
∂(hu)∂t+∂∂x(hu2+12gh2)+∂(huv)∂z=−gh∂b∂x \frac{\partial (hu)}{\partial t} + \frac{\partial}{\partial x}(hu^2 + \frac{1}{2}gh^2) + \frac{\partial (huv)}{\partial z} = -gh\frac{\partial b}{\partial x} ∂t∂(hu)+∂x∂(hu2+21gh2)+∂z∂(huv)=−gh∂x∂b
如上我们就得到了包含固定底床起伏的二维非线性 SWE 方程组:
①∂h∂t+∂(hu)∂x+∂(hv)∂z=0 ①\frac{\partial h}{\partial t} + \frac{\partial(hu)}{\partial x} + \frac{\partial(hv)}{\partial z} = 0 ①∂t∂h+∂x∂(hu)+∂z∂(hv)=0
②∂(hu)∂t+∂∂x(hu2+12gh2)+∂(huv)∂z=−gh∂b∂x ②\frac{\partial (hu)}{\partial t} + \frac{\partial}{\partial x}(hu^2 + \frac{1}{2}gh^2) + \frac{\partial (huv)}{\partial z} = -gh\frac{\partial b}{\partial x} ②∂t∂(hu)+∂x∂(hu2+21gh2)+∂z∂(huv)=−gh∂x∂b
③∂(hv)∂t+∂(huv)∂x+∂∂z(hu2+12gh2)=−gh∂b∂z ③\frac{\partial (hv)}{\partial t} + \frac{\partial (huv)}{\partial x} + \frac{\partial}{\partial z}(hu^2 + \frac{1}{2}gh^2) = -gh\frac{\partial b}{\partial z} ③∂t∂(hv)+∂x∂(huv)+∂z∂(hu2+21gh2)=−gh∂z∂b
3、初始化项
有地形时,一个关键性质是:水深不同,也可以完全静止。
静水平衡满足:
u=v=0,η=常数 u = v = 0, \eta = 常数 u=v=0,η=常数
由于:
h=η−b h = \eta - b h=η−b
底床起伏会使水深变化,但水平水面不会因此产生水平加速度。
在守恒方程中,这种静止依靠两部分相互抵消:
∂∂x(12gh2)=−gh∂b∂x \frac{\partial}{\partial x} \left(\frac12gh^2\right) = -gh\frac{\partial b}{\partial x} ∂x∂(21gh2)=−gh∂x∂b
如果程序分别近似压力通量和底床源项,却没有让它们正确平衡,就可能出现"没有施加扰动,水也自己流动"的假象。
能够在离散计算中保持这类平衡的数值方法称为 well-balanced,良平衡方法。静水重构是实现这一性质的一类经典方法。
因此,做 Unity 地形水体时,静水初始化通常应当是:
h(x,z,0)=max(η_0−b(x,z),0) h(x,z,0)=\max\big(\eta\_0-b(x,z),0\big) h(x,z,0)=max(η_0−b(x,z),0)
4、SWE 波速
4.1 连续性方程
考虑平底、静止背景水体,平均水深为常数 H。令:
h=H+ζ h = H + \zeta h=H+ζ
为了推导方便,我们现在只看一维(x 方向),忽略 z 方向的流动(或者假设流动在 z 方向均匀),方程变成:
∂h∂t+∂(hu)∂x=0 \frac{\partial h}{\partial t} + \frac{\partial (hu)}{\partial x} = 0 ∂t∂h+∂x∂(hu)=0
利用乘积求导法则展开第二项:
∂h∂t+h∂u∂x+u∂h∂x=0 \frac{\partial h}{\partial t} + h\frac{\partial u}{\partial x} + u \frac{\partial h}{\partial x}= 0 ∂t∂h+h∂x∂u+u∂x∂h=0
引入"微小扰动(小振幅波)"假设,假设水面本来平静(静止水深为 H),你往水里丢了一颗小石子。水面产生了一个非常微小的波澜(高度为 ζ)。
此时:总水深 h(x,t)=H+ζ(x,t) ,并且水流速度 u(x,t) 也非常小。
把 h=H+ζ 代入刚才的一维方程:
∂(H+ζ)∂t+(H+ζ)∂u∂x+u∂(H+ζ)∂x=0 \frac{\partial (H+\zeta)}{\partial t} + (H + \zeta)\frac{\partial u}{\partial x} + u\frac{\partial (H+\zeta)}{\partial x} = 0 ∂t∂(H+ζ)+(H+ζ)∂x∂u+u∂x∂(H+ζ)=0
由于H 是不随时间变化的常数,则有:
∂H∂t=∂H∂x=0 \frac{\partial H}{\partial t} = \frac{\partial H}{\partial x} = 0 ∂t∂H=∂x∂H=0
又因为 ζ 和 u 都是微小量,可以忽略,也有:
ζ≈0,u≈0 \zeta \approx 0, u \approx 0 ζ≈0,u≈0
所以原式等于:
∂ζ∂t+H∂u∂x=0 \frac{\partial \zeta}{\partial t} + H\frac{\partial u}{\partial x} = 0 ∂t∂ζ+H∂x∂u=0
4.2 动量方程
在只考虑一维(x方向)且忽略底部摩擦的情况下,浅水方程的标准动量方程是:
∂u∂t+u∂u∂x=−g∂η∂x \frac{\partial u}{\partial t} + u\frac{\partial u}{\partial x} = -g\frac{\partial \eta}{\partial x} ∂t∂u+u∂x∂u=−g∂x∂η
- 左边 :速度随时间的变化率 + 对流加速度(你之前问过的,流体跑到了流速不同的地方产生的加速度)。
- 右边:由水面高度差(压力梯度)产生的加速度(水往低处流)。
现在,假设水面非常平静,轻轻吹了一口气,产生了一个极小的涟漪。
- 水流速度 u 非常非常小(趋近于 0)。
- 水面高度的变化量 ζ 也非常非常小。
则有:
u∂u∂x≈0 u\frac{\partial u}{\partial x} \approx 0 u∂x∂u≈0
那么原式就变为:
∂u∂t+g∂η∂x=0 \frac{\partial u}{\partial t} + g\frac{\partial \eta}{\partial x} = 0 ∂t∂u+g∂x∂η=0
4.3 计算波速
对连续性方程两边求 t 的偏导:
∂2ζ∂t2+H∂2u∂x∂t=0 \frac{\partial^2 \zeta}{\partial t^2} + H\frac{\partial^2 u}{\partial x \partial t} = 0 ∂t2∂2ζ+H∂x∂t∂2u=0
对动量方程两边求 x 的偏导:
∂2u∂x∂t+g∂η∂2x=0 \frac{\partial^2 u}{\partial x \partial t} + g\frac{\partial \eta}{\partial^2 x} = 0 ∂x∂t∂2u+g∂2x∂η=0
联立得到:
∂2ζ∂t2=Hg∂2η∂x2 \frac{\partial^2 \zeta}{\partial t^2} = Hg\frac{\partial^2 \eta}{\partial x^2} ∂t2∂2ζ=Hg∂x2∂2η
又因为:
η=ζ+H \eta = \zeta + H η=ζ+H
则有:
∂2η∂t2=Hg∂2η∂x2 \frac{\partial^2 \eta}{\partial t^2} = Hg\frac{\partial^2 \eta}{\partial x^2} ∂t2∂2η=Hg∂x2∂2η
波动方程标准形式为:
∂2η∂t2=c2∂2η∂x2 \frac{\partial^2 \eta}{\partial t^2} = c^2\frac{\partial^2 \eta}{\partial x^2} ∂t2∂2η=c2∂x2∂2η
所以得到物理波速公式:
c=gH c = \sqrt{gH} c=gH
- g 是重力加速度(约 9.81 m/s29.81m/s2)
- HH 是静水深(或者当地实际水深 hh)
这个公式非常直观:
- 水越深,波传得越快(太平洋里的海啸速度接近飞机)。
- 水越浅,波传得越慢(冲上海滩的波浪会减速)。
三、数值离散方法
从方程到程序,需要选择数值离散方法。SWE 本身并不是某一种固定算法。
常见的层次关系是:
| 层次 | 解决的问题 | 示例 |
|---|---|---|
| 物理模型 | 水遵循什么规律 | 非线性 SWE、线性 SWE |
| 空间离散 | 怎样表示空间变化 | 有限差分、有限体积、有限元 |
| 界面通量 | 相邻单元之间交换多少量 | Rusanov、HLL、Roe |
| 时间推进 | 怎样从当前状态推进到下一时刻 | 显式 Euler、Runge--Kutta |
3.1 物理模型
3.1.1 选择物理模型的目的
真实水体包含大量现象:
- 水平流动、竖直运动;
- 压力变化;
- 黏性、摩擦和湍流;
- 波浪传播、破碎、飞溅;
- 不同波长的波以不同速度传播。
如果完整保留这些现象,求解成本会非常高。因此,需要选择一个适合研究目标的简化模型。
SWE 的主要简化是:沿水深方向进行平均,用水深和深度平均水平速度描述水体,并采用静水压力近似。它适用于水深相对水平运动尺度较小的情况。
选择物理模型,本质上是在决定:哪些现象需要计算,哪些现象可以近似或忽略。
3.1.2 一维非线性 SWE
对于平底、没有摩擦和外力的一维水流,非线性 SWE 为:
∂h∂t+∂(hu)∂x=0 \frac{\partial h}{\partial t} + \frac{\partial (hu)}{\partial x} = 0 ∂t∂h+∂x∂(hu)=0
∂(hu)∂x+∂∂x(hu2+12gh2)=0 \frac{\partial (hu)}{\partial x} + \frac{\partial }{\partial x}(hu^2 + \frac{1}{2}gh^2) = 0 ∂x∂(hu)+∂x∂(hu2+21gh2)=0
第一条描述质量守恒,第二条描述水平动量守恒。
定义状态向量:
U=hm,m=hu U = \begin{bmatrix} h \\ m \end{bmatrix}, m = hu U=hm,m=hu
其中,m 是省略常数密度因子的动量变量。
再定义物理通量:
F(U)=mm2h+12gh2 F(U) = \begin{bmatrix} m \\ \frac{m^2}{h} + \frac{1}{2}gh^2 \end{bmatrix} F(U)=mhm2+21gh2
于是,两条方程可以统一写成:
∂U∂t+∂F(U)∂x=0 \frac{\partial U}{\partial t} + \frac{\partial F(U)}{\partial x} = 0 ∂t∂U+∂x∂F(U)=0
这里的"非线性",意味着状态量之间存在乘积、平方等关系。例如:
hu,hu2,h2 hu,hu^2,h^2 hu,hu2,h2
水深和速度会相互影响,波的传播速度也依赖当前状态:
u−gh,u+gh u - \sqrt{gh},u+\sqrt{gh} u−gh ,u+gh
因此,波浪的不同部分可能具有不同传播速度,逐渐形成陡峭波面,甚至出现水跃等间断结构。
3.1.3 一维线性 SWEH
假设水体最初静止,平均水深为常数 H,扰动为 ζ:
h=H+ζ h = H + \zeta h=H+ζ
线性化时忽略扰动量之间的高阶乘积,化简连续性方程得到:
∂ζ∂t+H∂u∂x=0 \frac{\partial \zeta}{\partial t} + H\frac{\partial u}{\partial x} = 0 ∂t∂ζ+H∂x∂u=0
动量方程相应简化为:
∂u∂t+g∂ζ∂x=0 \frac{\partial u}{\partial t} + g\frac{\partial \zeta}{\partial x} = 0 ∂t∂u+g∂x∂ζ=0
它们描述围绕静止背景的小扰动传播,波速为:
c=gH c = \sqrt{gH} c=gH
3.1.4 两种物理模型的区别
| 比较内容 | 线性 SWE | 非线性 SWE |
|---|---|---|
| 主要描述对象 | 背景状态附近的小扰动 | 较一般的浅水流动 |
| 状态之间的相互作用 | 经过线性化简化 | 保留非线性耦合 |
| 静止、常水深背景的波速 | 固定为\(\sqrt{gH}\) | 随局部水深、流速变化 |
| 水跃、明显的波面陡化 | 不能完整描述 | 可以描述,需合适的数值格式 |
| 典型用途 | 小波动分析、简化波纹模拟 | 浅水流动、溃坝、交互水体等 |
把网格加密,不能补回物理模型已经忽略的现象。
例如,线性 SWE 即使用很细的网格,也不会自动变成非线性 SWE;基础 SWE 即使求解得非常精确,也不会自动产生真实水滴和翻卷浪头。
此外,物理问题还需要配套的初始条件、边界条件和外部作用。例如:最初的水深、墙壁位置、入口流量,以及物体怎样向水体施加扰动。
3.2 空间离散
3.2.1 空间离散的含义
连续模型中的:
h(x,t),u(x,t) h(x, t),u(x, t) h(x,t),u(x,t)
在任意位置都具有值。计算机无法保存无限多个位置,因此需要用有限个数据近似整个空间。
例如,将一条水槽划分为 N 个区域:
Δx=LN \Delta x = \frac{L}{N} Δx=NL
但"划分网格"只是开始,还需要明确:
- 每个位置保存什么;
- 一个区域内部的状态怎样表示;
- 空间导数或区域积分怎样近似。
有限差分、有限体积和有限元,在这些问题上采用不同思路。下面通过一维网格来介绍这些方法。
3.2.2 有限差分法
有限差分法通常保存若干位置上的函数值:
hi(t)≈h(xi,t) h_i(t)\approx h(x_i,t) hi(t)≈h(xi,t)
例如,用中心差分近似水面坡度:
∂η∂x∣xi≈ηi+1−ηi−12Δx \left. \frac{\partial \eta}{\partial x} \right |{x_i} \approx \frac{\eta{i+1}-\eta_{i-1}}{2\Delta x} ∂x∂η xi≈2Δxηi+1−ηi−1
如果采用线性 SWE:
∂u∂t=−g∂ζ∂x \frac{\partial u}{\partial t} = -g\frac{\partial \zeta}{\partial x} ∂t∂u=−g∂x∂ζ
空间离散后就得到:
duidt≈−gζi+1−ζi−12Δx \frac{du_i}{dt} \approx -g\frac{\zeta_{i+1}-\zeta_{i-1}}{2\Delta x} dtdui≈−g2Δxζi+1−ζi−1
原本连续的空间导数,变成了相邻数据之间的运算。注意,此时只完成了空间离散,还没有决定如何推进时间。
有限差分法的直观特点是:
- 对规则网格很容易实现;
- 相邻采样和纹理操作比较自然;
- 可以构造高阶导数近似;
- 稳定性和守恒性取决于具体格式。
空间离散(算空间导数)和时间离散(算时间推进)必须满足稳定性条件(CFL 条件),且不同组合的稳定性完全不同。 不要以为随便用什么方法(比如中心差分 + 显示时间推进)都能算出正确结果。
3.2.3 有限体积法
有限体积法把每个网格视为一个有大小的控制体。
1、有限体积法区域内存量变化计算
一维情况下,单元 i 的左右边界为:
xi−12,xi+12 x_{i - \frac{1}{2}},x_{i + \frac{1}{2}} xi−21,xi+21
这里:
- 整数下标 i:单元;
- 半整数下标 i+1/2:两个单元之间的界面。
保存的状态是单元平均值:
Ui‾=1Δx∫xi−12xi+12U(x,t) dx \overline{U_i} = \frac{1}{\Delta x}\int_{x_{i-\frac{1}{2}}}^{x_{i+\frac{1}{2}}} U(x, t)\,dx Ui=Δx1∫xi−21xi+21U(x,t)dx
公式两边同时对时间 t 求导数:
Ui‾=ddt(1Δx∫xi−12xi+12U(x,t) dx) \overline{U_i} = \frac{d}{dt} \left ( \frac{1}{\Delta x}\int_{x_{i-\frac{1}{2}}}^{x_{i+\frac{1}{2}}} U(x, t)\,dx \right ) Ui=dtd Δx1∫xi−21xi+21U(x,t)dx
积分区间固定,可以由莱布尼茨积分法则把时间导数直接移到积分括号里面:
Ui‾=1Δx∫xi−12xi+12∂U(x,t)∂t dx \overline{U_i} = \frac{1}{\Delta x}\int_{x_{i-\frac{1}{2}}}^{x_{i+\frac{1}{2}}} \frac{\partial U(x, t)}{\partial t}\,dx Ui=Δx1∫xi−21xi+21∂t∂U(x,t)dx
由一维浅水方程核心部分:
∂U∂t+∂F∂x=0 \frac{\partial U}{\partial t} + \frac{\partial F}{\partial x} = 0 ∂t∂U+∂x∂F=0
其中 U=h,huT,F=hu,hu2+12gh2T 其中\,U=h, hu^T,F = hu, hu\^2+\\frac{1}{2}gh\^2^T 其中U=h,huT,F=hu,hu2+21gh2T
将其带入刚才的积分中:
dUi‾dt=1Δx∫xi−12xi+12(−∂F(x,t)∂x)dx \frac{d\overline{U_i}}{dt} = \frac{1}{\Delta x}\int_{x_{i-\frac{1}{2}}}^{x_{i+\frac{1}{2}}} \left ( -\frac{\partial F(x, t)}{\partial x}\right )dx dtdUi=Δx1∫xi−21xi+21(−∂x∂F(x,t))dx
最终得到:
dUi‾dt=−F(xi+12)−F(xi−12)Δx \frac{d\overline{U_i}}{dt} = -\frac{F(x_{i+\frac{1}{2}}) - F(x_{i-\frac{1}{2}})}{\Delta x} dtdUi=−ΔxF(xi+21)−F(xi−21)
实际计算时,再用数值通量近似界面通量:
dUi‾dt=−F^(xi+12)−F^(xi−12)Δx \frac{d\overline{U_i}}{dt} = -\frac{\widehat{F}(x_{i+\frac{1}{2}})- \widehat{F}(x_{i-\frac{1}{2}})}{\Delta x} dtdUi=−ΔxF (xi+21)−F (xi−21)
上式表达的是:单元内部存量的变化。由左右两侧的净流入决定。
2、有限体积元的内部守恒变量的处理
① 常数
有限体积法并不意味着每个单元内部永远只能是一个常数。最简单的做法是分片常数,即整个单元都使用同一个状态。这通常对应基础的一阶空间近似。即:
U(x)≈U‾i U(x) \approx \overline{U}_i U(x)≈Ui
② 线性重构
使用分片线性重构:
Ui(x)≈U‾i+σi(x−xi) U_i(x) \approx \overline{U}_i + \sigma_i(x - x_i) Ui(x)≈Ui+σi(x−xi)
其中 σi 是单元内的斜率。
这样可以更好地表示平滑波形。但在陡峭波面附近,直接使用较大的斜率可能产生过冲,例如计算出不合理的负水深。因此,通常需要限制器;对于 SWE,还可能需要额外的正水深约束与静水平衡处理。
3.2.4 有限元法
有限元法的基本形式是:
Uh(x,t)=∑jaj(t)ϕj(x) U_h(x, t) = \sum_{j}a_j(t) \phi_j(x) Uh(x,t)=j∑aj(t)ϕj(x)
其中:
- ϕj(x)ϕj(x):预先选定的基函数;
- aj(t)aj(t):需要求解的系数;
- UhUh:对真实状态的近似。
例如,最简单的线性单元,可以通过端点值在单元内部进行线性插值。
随后,将微分方程乘以测试函数并进行积分,使方程在这种积分意义下成立。这称为弱形式。
有限元也有不同类型。连续 Galerkin 有限元通常要求相邻单元的解满足相应连续性;间断 Galerkin(DG)允许单元之间出现状态跳跃,因此同样需要数值界面通量来连接相邻单元。
3.2.5 三种离散方法的区别
| 方法 | 常见未知量表示 | 对当前项目的主要考虑 |
|---|---|---|
| 有限差分 | 网格点上的状态值 | 规则网格实现直接,适合先理解导数和波动 |
| 有限体积 | 单元平均状态 | 便于明确跟踪水量、动量以及区域之间的交换 |
| 有限元 | 基函数系数 | 适合复杂几何、高阶近似等需求,入门实现更复杂 |
3.3 界面通量
3.3.1 物理通量和数值通量的关系
物理模型给出了:
F(U)=huhu2+12gh2 F(U) = \begin{bmatrix} hu \\ hu^2 + \frac{1}{2}gh^2 \end{bmatrix} F(U)=huhu2+21gh2
但在离散网格中,同一个界面有两个来源不同的状态:
UL,UR U_L,U_R UL,UR
它们分别来自:
- 左单元的右边界;
- 右单元的左边界。
两侧水深、速度可能不同,因此:
F(UL)≠F(UR) F(U_L) \neq F(U_R) F(UL)=F(UR)
而一个共享界面需要有统一的交换量,因此要根据左右两侧状态计算:
F‾=F(UL,UR) \overline{F} = \mathcal F(U_L, U_R) F=F(UL,UR)
这里:
- F:由物理模型规定的物理通量;
- \mathcal F:选择的数值通量算法;
- \overline F:实际用于网格更新的界面通量。
3.3.2 局部 Riemann 问题
可以把两个单元之间的界面暂时看成一道隔板:
- 左侧具有状态 UL;
- 右侧具有状态 UR;
- 在某一时刻移除隔板。
随后会产生波,并在界面附近形成新的流动状态。
这种左右初始状态各自为常数的问题,称为 Riemann 问题。
精确求解它可以得到界面处的状态和通量。但在大量网格、每个时间步都要计算的情况下,通常会采用近似求解器。
3.3.3 Rusanov:平均物理通量,加上数值耗散
Rusanov 通量也称局部 Lax-Friderichs 通量:
F^Rus=FL+FR2−a2(UR−UL) \widehat F _{Rus} = \frac{F_L + F_R}{2}-\frac{a}{2}(U_R-U_L) F Rus=2FL+FR−2a(UR−UL)
其中:
FL=F(UL),FR=F(UR) F_L = F(U_L),F_R = F(U_R) FL=F(UL),FR=F(UR)
对全湿 SWE,一种常见的局部速度估计为:
a=max(∣uL∣+ghL,∣uR∣+ghR) a = max \left ( |u_L| + \sqrt{gh_L},|u_R| + \sqrt{gh_R} \right ) a=max(∣uL∣+ghL ,∣uR∣+ghR )
公式分为两部分:
FL+FR2 \frac{F_L + F_R}{2} 2FL+FR
取两侧物理通量的平均值;
−a2(UR−UL) -\frac{a}{2}(U_R-U_L) −2a(UR−UL)
根据状态差异加入数值耗散。
这种耗散有助于抑制振荡,但也可能把陡峭变化和细小波纹抹平。因此,Rusanov 实现简单,但计算出的波浪细节也与网格大小、重构阶数有关。
例如,设:
hL=2,hR=1uL=uR=0,g=9.81 h_L = 2,h_R = 1 \\ u_L = u_R = 0,g = 9.81 hL=2,hR=1uL=uR=0,g=9.81
则:
UL=20,UR=10 U_L = \begin{bmatrix} 2 \\ 0 \end{bmatrix},U_R = \begin{bmatrix} 1 \\ 0 \end{bmatrix} UL=20,UR=10
物理通量为:
FL=019.62,FR=04.905 F_L = \begin{bmatrix} 0 \\ 19.62 \end{bmatrix},F_R = \begin{bmatrix} 0 \\ 4.905 \end{bmatrix} FL=019.62,FR=04.905
最大速度估计:
a=9.81×2≈4.429 a = \sqrt{9.81 \times 2} \approx 4.429 a=9.81×2 ≈4.429
最终:
F^Rus≈2.21512.263 \widehat F_{Rus} \approx \begin{bmatrix} 2.215 \\ 12.263 \end{bmatrix} F Rus≈2.21512.263
第一项是单位宽度体积流量,正号表示向右输水。
尽管两侧初始速度都是零,水深差引起的压力不平衡仍会产生流动。 数值通量是在近似界面问题随即发生的演化。
3.3.4 HLL:分别估计向左和向右的波速
HLL 使用两个波速:
SL,SR S_L,S_R SL,SR
分别表示最左侧和最右侧传播信号的速度估计。
对全湿 SWE,一种基础估计是:
SL=min(uL−ghL,uR−ghR)SL=max(uL+ghL,uR+ghR) S_L = min\left ( u_L - \sqrt{gh_L},u_R - \sqrt{gh_R} \right ) \\ S_L = max\left ( u_L + \sqrt{gh_L},u_R + \sqrt{gh_R} \right ) SL=min(uL−ghL ,uR−ghR )SL=max(uL+ghL ,uR+ghR )
具体求解器也可能采用更稳健的速度估计,干床情况尤其需要专门处理。
HLL 通量为:
F^HLL={FL,SL≥0SRFL−SLFR+SLSR(UR−UL)SR−SL,SL<0<SRFR,SR≤0 \widehat F_{HLL} = \begin{cases} F_L, & S_L \ge0 \\ \frac{S_R F_L - S_L F_R + S_L S_R(U_R - U_L)}{S_R-S_L}, & S_L < 0 < S_R \\ F_R, & S_R \le0 \end{cases} F HLL=⎩ ⎨ ⎧FL,SR−SLSRFL−SLFR+SLSR(UR−UL),FR,SL≥0SL<0<SRSR≤0
它体现了传播方向:
- 如果所有信号都向右传播,界面由左侧状态决定;
- 如果所有信号都向左传播,界面由右侧状态决定;
- 如果信号向两侧传播,就使用中间表达式。
HLL 将两个外侧波之间的复杂结构近似为一个平均状态。
Rusanov 与 HLL 还有一个直接关系。令:
SL=−a,SR=a S_L = -a,S_R = a SL=−a,SR=a
HLL 就会化简成 Rusanov 通量。
所以,HLL 并不保证在每一种状态下都比 Rusanov 更精细;采用对称速度估计时,两者可以完全相同。
3.3.5 Roe:分解不同的波,再分别处理传播
Roe 的思路是:在界面附近构造一个具有特定守恒性质的局部线性系统,用它近似原来的非线性问题。
对一维 SWE,常用 Roe 平均为:
u~=uLhL+uRhRhL+hRh~=hL+hR2,c~=gh~ \widetilde u = \frac{u_L \sqrt{h_L} + u_R{\sqrt{h_R}}}{\sqrt{h_L} + \sqrt{h_R}} \\ \widetilde h = \frac{h_L + h_R}{2},\widetilde c = \sqrt{g\widetilde h} u =hL +hR uLhL +uRhR h =2hL+hR,c =gh
两个特征速度为:
λ~1=u~−c~,λ~2=u~+c~ \widetilde \lambda_1 = \widetilde u - \widetilde c,\widetilde \lambda_2 = \widetilde u + \widetilde c λ 1=u −c ,λ 2=u +c
把状态差分解成两个波:
UR−UL=α1r1+α2r2 U_R - U_L = \alpha_1 \boldsymbol r_1 + \alpha_2\boldsymbol r_2 UR−UL=α1r1+α2r2
再计算:
F^Roe=FL+FR2−12∑p=12∣λ~p∣αprp \widehat F_{Roe} = \frac{F_L + F_R}{2} - \frac{1}{2}\sum_{p=1}^{2}|\widetilde \lambda_p| \alpha_p \boldsymbol r_p F Roe=2FL+FR−21p=1∑2∣λ p∣αprp
可以把它理解为:每一种波按照自己的传播速度提供相应的数值耗散。
Roe 能较细致地处理波结构,但标准 Roe 方法还存在需要处理的问题,例如跨声速稀疏波的熵修正,以及某些状态下出现非物理负水深。
3.3.6 三种通量应怎样比较
| 通量 | 核心做法 | 主要考虑 |
|---|---|---|
| Rusanov鲁萨诺夫 | 一个最大传播速度控制耗散 | 简单,适合作为基础实现;耗散可能较大 |
| HLL | 使用左右两个传播速度 | 体现传播方向,稳健性依赖速度估计等配套处理 |
| Roe | 对不同特征波分别处理 | 波结构分辨较细,需要熵修正、正水深等处理 |
一个单元界面的平均水面是平的,也不意味着动量通量为零。静水中仍有压力通量;静止状态依靠两侧压力作用相互抵消来保持。
3.4 时间推进
3.4.1 空间离散后,得到的是变化率
完成空间离散和通量计算后,可以写出:
dU‾idt=Li(U‾) \frac{d\overline{\boldsymbol U}_i}{dt} = \mathcal L_i(\overline{\boldsymbol U}) dtdUi=Li(U)
其中:
Li(U‾)=−F^i+12−F^i−12Δx+S‾i \mathcal L_i(\overline{\boldsymbol U}) = -\frac{ \widehat{\boldsymbol F}{i+\frac12} - \widehat{\boldsymbol F}{i-\frac12} }{\Delta x} + \overline{\boldsymbol S}_i Li(U)=−ΔxF i+21−F i−21+Si
\mathcal L 是离散空间算子,它负责根据当前状态计算:
- 各界面的流动;
- 单元内水深的变化率;
- 单元内动量的变化率;
- 必要的源项作用。
此时,整个问题成为一组关于时间的常微分方程。
时间推进方法决定:如何利用这些变化率,把当前状态推进到下一时刻。
这种先离散空间、再求解时间变化的方法通常称为线方法。
3.4.2 显式 Euler:使用当前变化率前进一步
显示 Euler 为:
U(n+1)=Un+ΔtL(Un) U^(n+1) = U^n + \Delta t \mathcal L(U^n) U(n+1)=Un+ΔtL(Un)
含义是:假设在这一个短时间段内,状态按照当前变化率变化。它只计算一次空间算子,形式最简单,时间精度为一阶。
使用 3.3.3 中的例子,设两个单元宽度均为:
Δx=1m \Delta x = 1 m Δx=1m
它们之间的体积通量约为:
F^h=2.215m2/s \widehat F_h = 2.215 m^2/s F h=2.215m2/s
若外侧边界没有水流通过,取:
Δt=0.05s \Delta t = 0.05s Δt=0.05s
则左单元水深减少:
ΔhL=−ΔtΔxF^h≈−0.1107m \Delta h_L = - \frac{\Delta t}{\Delta x}\widehat F_h \approx -0.1107m ΔhL=−ΔxΔtF h≈−0.1107m
右单元增加相同水深:
ΔhR≈+0.1107m \Delta h_R \approx +0.1107m ΔhR≈+0.1107m
于是:
hLn+1≈1.8893hRn+1≈1.1107 h_L^{n+1} \approx 1.8893 \\ h_R^{n+1} \approx 1.1107 hLn+1≈1.8893hRn+1≈1.1107
这里展示了质量分量;实际求解器还必须同步更新动量分量。
4.2.3 Runge-Kutta:在一个时间步内多次评估变化率
Runge--Kutta 是一类方法的统称。它通过构造中间状态,多次评估变化率,再组合得到下一时刻的结果。
常见的二阶 SSP Runge--Kutta 为:
U(1)=Un+ΔtL(Un)U(n+1)=12Un+12U(1)+ΔtL(U(1)) U^{(1)}=U^n+\Delta t\mathcal L(U^n) \\ U^{(n+1)}=\frac{1}{2}U^n+\frac{1}{2}\left U\^{(1)}+\\Delta t \\mathcal L(U\^{(1)}) \\right U(1)=Un+ΔtL(Un)U(n+1)=21Un+21U(1)+ΔtL(U(1))
第一阶段得到预测状态;第二阶段重新计算预测状态下的变化率,再进行组合。第二阶段必须重新计算通量。
4.2.4 SSPRK3 与"强稳定保持"
三阶 SSP Runge-Kutta 的常见形式为:
U(1)=Un+ΔtL(Un)U(2)=34Un+14U(1)+ΔtL(U(1))U(n+1)=13Un+23U(2)+ΔtL(U(2)) U^{(1)}=U^n+\Delta t\mathcal L(U^n) \\ U^{(2)}=\frac{3}{4}U^n+\frac{1}{4}\left U\^{(1)}+\\Delta t \\mathcal L(U\^{(1)}) \\right \\ U^{(n+1)}=\frac{1}{3}U^n+\frac{2}{3}\left U\^{(2)}+\\Delta t \\mathcal L(U\^{(2)}) \\right U(1)=Un+ΔtL(Un)U(2)=43Un+41U(1)+ΔtL(U(1))U(n+1)=31Un+32U(2)+ΔtL(U(2))
它需要三次空间算子评估。
SSP 的含义是:如果空间离散与前向 Euler 在一定步长限制下具有某种合适的稳定性质,SSP 时间方法可以在相应限制下保留该性质。它不能自动修复本来就不稳定或会产生负水深的空间离散。
3.2.5 三种离散方式的区别
| 方法 | 时间阶数 | 每步空间算子评估次数 |
|---|---|---|
| 显式 Euler | 1 | 1 |
| SSPRK2 | 2 | 2 |
| SSPRK3 | 3 | 3 |
| 经典 RK4 | 4 | 4 |
时间阶数更高,并不自动意味着更适合你的实现。还需要考虑稳定性、空间误差、显存访问和总计算成本。
3.2.6 时间精度与空间精度的耦合
假设空间离散只有一阶,而时间推进使用四阶 RK,整体误差仍可能主要来自空间离散:
误差∼CxΔx+CtΔt4 误差 \sim C_x \Delta x + C_t \Delta t^4 误差∼CxΔx+CtΔt4
这是平滑解条件下的示意关系。
因此:
- 一阶空间方法加高阶时间方法,不能自动恢复被空间耗散抹掉的波纹;
- 高阶空间方法加过于粗糙的时间推进,也可能损失精度;
- 存在间断时,局部精度还会受到限制器等因素影响。
一个常见的升级方向是:先建立一阶有限体积与显式 Euler 基线,再增加受限线性重构和 SSPRK2。
3.2.7 时间步长的稳定性要求
对常见一维显式格式,CFL 条件具有如下形式:
Δt≤CCFLΔxmaxi(∣ui∣+ghi) \Delta t \leq C_{CFL}\frac{\Delta x}{max_i(|u_i|+\sqrt{gh_i})} Δt≤CCFLmaxi(∣ui∣+ghi )Δx
这里的 Ccfl 上限依赖具体格式。对于显式 Euler 时间推进,一维情况下 Cmax=1;但在多维或高阶格式下,通常取 0.5∼0.9 以确保安全。
二维非分裂格式常见的保守步长形式为:
Δt≤CCFLaxΔx+azΔz \Delta t \leq \frac{C_{CFL}}{\frac{a_x}{\Delta x}+\frac{a_z}{\Delta z}} Δt≤Δxax+ΔzazCCFL
其中 ax, az 是两个方向的最大传播速度估计。
CFL 约束将前面各层联系起来:物理模型决定传播速度,空间网格决定信息需要跨越的距离,时间方法影响允许的稳定步长。显式 SWE 求解器通常据此选择时间步。
对于二维规则网格,如果其他条件不变,将两个方向的网格间距都减半:
- 单元总数约增加到 4 倍;
- 显式时间步通常也需要减半;
- 模拟同样物理时长的基础计算量可能接近 8 倍。