SWE 的原理解析

二、SWE 的运动机制

SWE 的运动机制可以理解成:水面坡度改变流速,流动的汇聚和发散改变水深。

假设你在平静水面中央制造一个隆起:

  1. 中央与周围出现水面高度差。
  2. 高度差产生水平压力梯度,使水向周围加速。
  3. 中央流出的水多,水面下降;周围得到水,水面上升。
  4. 当水面暂时变平时,水仍然具有速度。
  5. 水继续运动,产生新的凹陷和隆起,扰动由此向外传播。

所以,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 倍。
相关推荐
AiNightVision1 小时前
星光级 是什么?——星光级摄像机是什么?0.001Lux 照度门槛与选型真相
人工智能·算法·车载系统·自动驾驶·无人机·视频·智能硬件
若亦_1 小时前
排序>>选择排序
数据结构·算法·排序算法
重生之小比特1 小时前
【算法拾光】前缀和|一维前缀和 + 二维前缀和
数据结构·算法
释厄6231 小时前
矢量词汇向下不向上公理即词汇归位定律——肤浅即表面
java·人工智能·算法·去中心化·1024程序员节
海绵宝宝转agent1 小时前
Leetcode100+面经
java·笔记·学习·算法·leetcode·深度优先
Shaoshing2 小时前
LeetCode100 283.移动零
java·数据结构·算法·leetcode
海绵宝宝转agent2 小时前
LeetCode100个人题解+java面经总结
java·开发语言·笔记·学习·算法
飞Link10 小时前
什么是 AirSim?一文读懂无人机仿真平台
python·算法·无人机
一去不复返的通信er12 小时前
贪心算法-合并区间(LeetCode 56)
算法·leetcode·贪心算法