《Level Set Methods and Dynamic Implicit Surfaces》
Level Set的核心思想是用数量场中的等值面表示几何曲面,求解 Level Set 的实质,还是是用数值方法求解一个微分方程。既然涉及到空间微分方程,绕不开的一个问题就是数值微分。最简单的中心差分由于数值震荡的原因无法使用,迎风格式很简单很有效然而精度不高。Level Set 计算中最常用的 WENO 差分格式,然而这格式实在比较复杂,加之网上找到的资料多为流体方程求解所用,花了不少力气才看懂。
ϕ t + V ⃗ ∇ ϕ = 0 \phi_t + \vec{V} \nabla{\phi} =0
ϕ t + V ∇ ϕ = 0
其中
V ⃗ = { u , v , w } \vec{V} = \{ u,v,w\}
V = { u , v , w }
在一维情况下展开为:
ϕ n + 1 − ϕ n Δ t + u n ϕ x n = 0 \frac{{\phi}^{n+1}-{{\phi}^n}}{{\Delta}t} + u^n{{\phi}^n_x} = 0
Δ t ϕ n + 1 − ϕ n + u n ϕ x n = 0
可见,求解方程首先需要计算$${{\phi}^n_x}$$,即第n时间步上$${{\phi}x}$$的数值。
为简单,下面定义$${{\phi} {i}} = {{\phi}_{x_i}}$$
CFL条件用于控制空间步长与时间步长,保持数值稳定性。一般认为,满足下式时,数值求解是稳定的,误差不会扩大:
Δ t < Δ x m a x { ∣ u ∣ } \Delta{t} < \frac{\Delta{x}}{max\{ |u| \}}
Δ t < m a x { ∣ u ∣ } Δ x
令α = Δ t m a x { ∣ u ∣ } Δ x \alpha = \Delta{t} \frac{max\{ |u| \}}{\Delta{x}}α = Δ t Δ x m a x { ∣ u ∣ } .一般,保守的取值是使得 $ \alpha = 0.5 $,激进的优化中可以取到 $ \alpha = 0.9 $.
定义:
D + ϕ = ϕ + = ϕ i + 1 − ϕ i Δ x D^+{\phi} = {\phi}^+=\frac{{\phi}_{i+1}-{{\phi}_i}}{{\Delta}x}
D + ϕ = ϕ + = Δ x ϕ i + 1 − ϕ i
D − ϕ = ϕ − = ϕ i − ϕ i − 1 Δ x D^-{\phi} = {\phi}^-=\frac{{\phi}_{i}-{{\phi}_{i-1}}}{{\Delta}x}
D − ϕ = ϕ − = Δ x ϕ i − ϕ i − 1
迎风格式的思想是与物理实际相结合,运动方向是哪边来的,就利用哪边的导数信息(或者主要利用哪边的),故有:
ϕ i = { ϕ i − u i > 0 ϕ i + u i < 0 {\phi}_{i}=\left\{
\begin{aligned}
{\phi}^-_i &\qquad& u_i > 0\\
{\phi}^+_i &\qquad& u_i < 0
\end{aligned}
\right.
ϕ i = { ϕ i − ϕ i + u i > 0 u i < 0
至此,一切都很简单。
Hamilton Jacobi ENO格式,精度比上述迎风格式高,可以到三阶精度。ENO全称Essentially Nonoscillatiry,精选非震荡,听着有点像广告……
三阶精度不稀奇,难度在于保证光滑性与数值稳定性。保证数值稳定性的思想仍是迎风的思想,根据u uu 的符号侧重使用某一边的数值信息,但是ENO格式提高了对ϕ + {\phi}^+ϕ + 或者ϕ − {\phi}^-ϕ − 的估计精度;对于光滑性的保证,ENO格式的原则是:在临近节点中选择选择可以使得结果最为光滑的点,作为插值模板,构建公式。
##差分定义
1.零阶,定义在网格点上:
D i 0 ϕ = ϕ i D^0_i{\phi}={\phi}_i
D i 0 ϕ = ϕ i
2.一阶,定义在网格中间:
D i + 1 / 2 1 ϕ = D i + 1 0 ϕ − D i 0 ϕ Δ x D^1_{i+1/2}{\phi}=\frac{D^0_{i+1}{\phi}-D^0_{i}{\phi}}{\Delta{x}}
D i + 1 / 2 1 ϕ = Δ x D i + 1 0 ϕ − D i 0 ϕ
3.二阶,定义在网格点上:
D i 2 ϕ = D i + 1 / 2 1 ϕ − D i − 1 / 2 1 ϕ 2 Δ x D^2_{i}{\phi}=\frac{D^1_{i+1/2}{\phi}-D^1_{i-1/2}{\phi}}{2\Delta{x}}
D i 2 ϕ = 2 Δ x D i + 1 / 2 1 ϕ − D i − 1 / 2 1 ϕ
4.三阶,定义在网格点上:
D i + 1 / 2 3 ϕ = D i + 1 2 ϕ − D i 1 ϕ 3 Δ x D^3_{i+1/2}{\phi}=\frac{D^2_{i+1}{\phi}-D^1_{i}{\phi}}{3\Delta{x}}
D i + 1 / 2 3 ϕ = 3 Δ x D i + 1 2 ϕ − D i 1 ϕ
##差分格式
构建ϕ ( x ) {\phi}(x)ϕ ( x ) 的牛顿插值多项式如下:
ϕ ( x ) = Q 0 ( x ) + Q 1 ( x ) + Q 2 ( x ) + Q 3 ( x ) {\phi}(x) = Q_0(x) + Q_1(x) + Q_2(x) + Q_3(x)
ϕ ( x ) = Q 0 ( x ) + Q 1 ( x ) + Q 2 ( x ) + Q 3 ( x )
在x i x_ix i 处对上式两边取导数,则有:
ϕ ′ ( x i ) = Q 1 ′ ( x ) + Q 2 ′ ( x ) + Q 3 ′ ( x ) {\phi}'(x_i) = {Q_1}'(x) + {Q_2}'(x) + {Q_3}'(x)
ϕ ′ ( x i ) = Q 1 ′ ( x ) + Q 2 ′ ( x ) + Q 3 ′ ( x )
首先求一阶导数的估计,由于是 ϕ x − \phi^-_xϕ x − 的情况, 从k = i − 1 k=i-1k = i − 1 侧估计一阶导数,如下 :
Q 1 ( x ) = ( D k + 1 / 2 1 ) ( x − x i ) Q_1(x) = (D^1_{k+1/2})(x-x_i)
Q 1 ( x ) = ( D k + 1 / 2 1 ) ( x − x i )
Q 1 ′ ( x ) = D k + 1 / 2 1 {Q_1}'(x) = D^1_{k+1/2}
Q 1 ′ ( x ) = D k + 1 / 2 1
下面看Q 2 Q_2Q 2 ,从牛顿多项式的形式上来讲:
Q 2 ( x ) = c ( x − x k ) ( x − x k + 1 ) Q_2(x) = c(x-x_k)(x-x_{k+1})
Q 2 ( x ) = c ( x − x k ) ( x − x k + 1 )
两边求导:
Q 2 ′ ( x ) = c [ 2 ( i − k ) − 1 ] Δ x {Q_2}'(x) = c[2(i-k)-1]\Delta{x}
Q 2 ′ ( x ) = c [ 2 ( i − k ) − 1 ] Δ x
其中,c cc 为二阶差分,但是二阶差分有两个,用哪一个呢?前面说过了:这取决于哪边的光滑……感觉好奇怪,但是情况就是这么个情况:
c = { D k 2 ϕ ∣ D k 2 ϕ ∣ < ∣ D k + 1 2 ϕ ∣ D k + 1 2 ϕ ∣ D k 2 ϕ ∣ > ∣ D k + 1 2 ϕ ∣ c=\left\{
\begin{aligned}
D^2_k\phi &\qquad& |{D^2_k\phi}| < |D^2_{k+1}\phi| \\
D^2_{k+1}\phi &\qquad& |{D^2_k\phi}| > |D^2_{k+1}\phi|
\end{aligned}
\right.c = { D k 2 ϕ D k + 1 2 ϕ ∣ D k 2 ϕ ∣ < ∣ D k + 1 2 ϕ ∣ ∣ D k 2 ϕ ∣ > ∣ D k + 1 2 ϕ ∣
可以看出来,上面所谓“从k = i − 1 k=i-1k = i − 1 侧”开始,其实是定义了一个类似程序指针的变量,定义了下面一步要计算哪一个节点的值。算完Q 2 Q_2Q 2 之后,需要再定义一个指针变量k ∗ k^*k ∗ 留着后面用:
k ∗ = { k − 1 ∣ D k 2 ϕ ∣ < ∣ D k + 1 2 ϕ ∣ k ∣ D k 2 ϕ ∣ > ∣ D k + 1 2 ϕ ∣ k^*=\left\{
\begin{aligned}
k-1 &\qquad& |{D^2_k\phi}| < |D^2_{k+1}\phi| \\
k &\qquad& |{D^2_k\phi}| > |D^2_{k+1}\phi|
\end{aligned}
\right.k ∗ = { k − 1 k ∣ D k 2 ϕ ∣ < ∣ D k + 1 2 ϕ ∣ ∣ D k 2 ϕ ∣ > ∣ D k + 1 2 ϕ ∣
第三步,依葫芦画瓢,设Q 3 Q_3Q 3 的形式如下:
Q 3 ( x ) = c ∗ ( x − x k ∗ ) ( x − x k ∗ + 1 ) ( x − x k ∗ + 2 ) Q_3(x) = c^*(x-x_{k^*})(x-x_{k^*+1})(x-x_{k^*+2})
Q 3 ( x ) = c ∗ ( x − x k ∗ ) ( x − x k ∗ + 1 ) ( x − x k ∗ + 2 )
两边求导:
Q 3 ′ ( x ) = c ∗ [ 3 ( i − k ∗ ) 2 − 6 ( i − k ∗ ) + 2 ] ( Δ x ) 2 {Q_3}'(x) = c^*[3(i-k^*)^2-6(i-k^*)+2](\Delta{x})^2
Q 3 ′ ( x ) = c ∗ [ 3 ( i − k ∗ ) 2 − 6 ( i − k ∗ ) + 2 ] ( Δ x ) 2
其中:
c ∗ = { D k ∗ + 1 / 2 3 ϕ ∣ D k ∗ + 1 / 2 3 ϕ ∣ < ∣ D k ∗ + 3 / 2 3 ϕ ∣ D k ∗ + 3 / 2 3 ϕ ∣ D k ∗ + 1 / 2 3 ϕ ∣ > ∣ D k ∗ + 3 / 2 3 ϕ ∣ c*=\left\{
\begin{aligned}
D^3_{k*+1/2}\phi &\qquad& |{D^3_{k*+1/2}\phi}| < |D^3_{k*+3/2}\phi| \\
D^3_{k*+3/2}\phi &\qquad& |{D^3_{k*+1/2}\phi}| > |D^3_{k*+3/2}\phi|
\end{aligned}
\right.c ∗ = { D k ∗ + 1 / 2 3 ϕ D k ∗ + 3 / 2 3 ϕ ∣ D k ∗ + 1 / 2 3 ϕ ∣ < ∣ D k ∗ + 3 / 2 3 ϕ ∣ ∣ D k ∗ + 1 / 2 3 ϕ ∣ > ∣ D k ∗ + 3 / 2 3 ϕ ∣
至此,Q 1 , 2 , 3 Q_{1,2,3}Q 1 , 2 , 3 全部到手,可以计算ϕ x − \phi^-_xϕ x − 了
只有一句:开始的时候定义k = i k=ik = i 即可。
ENO格式成于“essentially”精选,也缺陷于精选,因为“精选”就意味着丢弃。
例如,对于ϕ x i − \phi^-_{x_i}ϕ x i − ,HJ_ENO格式使用了如下共计六个节点的数值:
{ ϕ i − 3 , ϕ i − 2 , ϕ i − 2 , ϕ i , ϕ i + 1 , ϕ i + 2 } \{{\phi_{i-3}},{\phi_{i-2}},{\phi_{i-2}},{\phi_{i}},{\phi_{i+1}},{\phi_{i+2}}\}
{ ϕ i − 3 , ϕ i − 2 , ϕ i − 2 , ϕ i , ϕ i + 1 , ϕ i + 2 }
这些节点每一个都参与了计算,但是精选之后能留下来的有多少呢?
令:
v 1 = D − ϕ i − 2 v 2 = D − ϕ i − 1 v 3 = D − ϕ i v 4 = D − ϕ i + 1 v 5 = D − ϕ i + 2 v_1=D^-{\phi_{i-2}}\qquad v_2=D^-{\phi_{i-1}}\qquad \\ v_3=D^-{\phi_{i}}\qquad v_4=D^-{\phi_{i+1}}\qquad v_5=D^-{\phi_{i+2}}\qquad
v 1 = D − ϕ i − 2 v 2 = D − ϕ i − 1 v 3 = D − ϕ i v 4 = D − ϕ i + 1 v 5 = D − ϕ i + 2
ENO格式的运算实质上是一个有两个分支的流程,对其整理可以发现可能的执行结果只有下面三种:
ϕ x 1 = v 1 3 − 7 v 2 6 + 11 v 3 6 ϕ x 2 = − v 2 6 + 5 v 3 6 + v 4 3 ϕ x 3 = v 3 3 + 5 v 4 6 − v 5 6 \begin{aligned}
\phi^1_x &=& \frac{v_1}{3}-\frac{7v_2}{6}+\frac{11v_3}{6}\\
\phi^2_x &=& -\frac{v_2}{6} +\frac{5v_3}{6} + \frac{v_4}{3}\\
\phi^3_x &=& \frac{v_3}{3}+\frac{5v_4}{6}-\frac{v_5}{6}
\end{aligned}
ϕ x 1 ϕ x 2 ϕ x 3 = = = 3 v 1 − 6 7 v 2 + 6 1 1 v 3 − 6 v 2 + 6 5 v 3 + 3 v 4 3 v 3 + 6 5 v 4 − 6 v 5
两个分支下来,最后得到的只可能是这三种结果,详细的条件选择太烦,不写了,总之浪费了计算能力。
WENO格式解决这个问题的思路是:这么多点还是要的,否则不精确,但是计算结果不要丢掉,想想办法利用一下,不能减轻计算量提高点精度也是好的。于是他们做了一个加权平均,WENO之“W”即 weight 。
WENO的几个作者Chi-Wang Shu,Guang-Shan Jiang, Danping Peng,乍看都是中国人,不过署名学校是 University of California at Los Angeles以及Brown University。
对于证明细节也不细写,总之,在函数的光滑区间内,取ω 1 = 0.1 \omega_1 = 0.1ω 1 = 0 . 1 ,ω 2 = 0.6 \omega_2 = 0.6ω 2 = 0 . 6 ,ω 3 = 0.3 \omega_3 = 0.3ω 3 = 0 . 3 的时候,加权平均:
ϕ x = ω 1 ϕ x 1 + ω 2 ϕ x 2 + ω 3 ϕ x 3 \phi_{x} = \omega_1\phi^1_x + \omega_2\phi^2_x + \omega_3\phi^3_x
ϕ x = ω 1 ϕ x 1 + ω 2 ϕ x 2 + ω 3 ϕ x 3
可以得到五阶精度的导数值估计。后面又有神人证明,若在每一个ω \omegaω 上附加一项O ( ( Δ x ) 2 ) O((\Delta{x})^2)O ( ( Δ x ) 2 ) ,即修改为ω 1 = 0.1 + O ( ( Δ x ) 2 ) \omega_1 = 0.1 + O((\Delta{x})^2)ω 1 = 0 . 1 + O ( ( Δ x ) 2 ) ,ω 2 = 0.6 + O ( ( Δ x ) 2 ) \omega_2 = 0.6 + O((\Delta{x})^2)ω 2 = 0 . 6 + O ( ( Δ x ) 2 ) ,ω 3 = 0.3 + O ( ( Δ x ) 2 ) \omega_3 = 0.3 + O((\Delta{x})^2)ω 3 = 0 . 3 + O ( ( Δ x ) 2 ) ,精度仍然是五阶。
看起来特别简单。问题是,不光滑区间怎样处理?需要构造一种算法来调整,该算法原则如下:
在光滑区间内,保证ω s = ω s − o r i g i n + O ( ( Δ x ) 2 ) \omega_s = \omega_{s-origin} + O((\Delta{x})^2)ω s = ω s − o r i g i n + O ( ( Δ x ) 2 )
在包含奇点的区间上,尽量消除包含奇点的计算模板的影响,也就相当于是自动选择三种ENO候选格式ϕ x i \phi^i_xϕ x i 中不受影响的那一个
显然,核心思想还是“找最光滑的”,那么首先要知道每个模板光滑程度如何。分别定义三个模板的光滑度:
S 1 = 13 12 ( v 1 − 2 v 2 + v 3 ) 2 + 1 4 ( v 1 − 4 v 2 + 3 v 3 ) S 2 = 13 12 ( v 2 − 2 v 3 + v 4 ) 2 + 1 4 ( v 2 − v 4 ) S 3 = 13 12 ( v 3 − 2 v 4 + v 5 ) 2 + 1 4 ( 3 v 3 − 4 v 4 + v 5 ) \begin{aligned}
S_1 &=& \frac{13}{12}(v_1-2v_2+v_3)^2 + \frac{1}{4}(v_1-4v_2+3v_3)\\
S_2 &=& \frac{13}{12}(v_2-2v_3+v_4)^2 + \frac{1}{4}(v_2-v_4)\\
S_3 &=& \frac{13}{12}(v_3-2v_4+v_5)^2 + \frac{1}{4}(3v_3-4v_4+v_5)
\end{aligned}
S 1 S 2 S 3 = = = 1 2 1 3 ( v 1 − 2 v 2 + v 3 ) 2 + 4 1 ( v 1 − 4 v 2 + 3 v 3 ) 1 2 1 3 ( v 2 − 2 v 3 + v 4 ) 2 + 4 1 ( v 2 − v 4 ) 1 2 1 3 ( v 3 − 2 v 4 + v 5 ) 2 + 4 1 ( 3 v 3 − 4 v 4 + v 5 )
继续定义,中间变量:
α 1 = 0.1 ( S 1 + ϵ ) 2 α 2 = 0.6 ( S 1 + ϵ ) 2 α 3 = 0.3 ( S 1 + ϵ ) 2 \begin{aligned}
\alpha_1 &=& \frac{0.1}{(S_1 + \epsilon)^2}\\
\alpha_2 &=& \frac{0.6}{(S_1 + \epsilon)^2}\\
\alpha_3 &=& \frac{0.3}{(S_1 + \epsilon)^2}
\end{aligned}
α 1 α 2 α 3 = = = ( S 1 + ϵ ) 2 0 . 1 ( S 1 + ϵ ) 2 0 . 6 ( S 1 + ϵ ) 2 0 . 3
其中ϵ \epsilonϵ 的存在是为了防止出现被零除,其定义为:
ϵ = 1 0 − 6 m a x { ( v 1 ) 2 , ( v 2 ) 2 , ( v 3 ) 2 , ( v 4 ) 2 , ( v 5 ) 2 } + 1 0 − 99 \epsilon = 10^{-6}max \left\{ (v_1)^2,(v_2)^2,(v_3)^2,(v_4)^2,(v_5)^2 \right\} +10^{-99}
ϵ = 1 0 − 6 m a x { ( v 1 ) 2 , ( v 2 ) 2 , ( v 3 ) 2 , ( v 4 ) 2 , ( v 5 ) 2 } + 1 0 − 9 9
现在,可以计算得到新的ω i \omega_iω i :
ω 1 = α 1 α 1 + α 2 + α 3 ω 2 = α 2 α 1 + α 2 + α 3 ω 3 = α 3 α 1 + α 2 + α 3 \begin{aligned}
\omega_1 &=& \frac{\alpha_1}{\alpha_1 + \alpha_2 + \alpha_3}\\
\omega_2 &=& \frac{\alpha_2}{\alpha_1 + \alpha_2 + \alpha_3}\\
\omega_3 &=& \frac{\alpha_3}{\alpha_1 + \alpha_2 + \alpha_3}
\end{aligned}
ω 1 ω 2 ω 3 = = = α 1 + α 2 + α 3 α 1 α 1 + α 2 + α 3 α 2 α 1 + α 2 + α 3 α 3
用这个加权平均即可。WENO格式除初始化(选择 ϕ x + \phi^+_xϕ x + 或者 ϕ x − \phi^-_xϕ x − )以外,没有出现分支,一则不浪费计算能力,二则便于GPU并行化计算(GPU计算在某些时候需要尽量避免程序分支)。
最后,上面计算的都是ϕ x − \phi^-_xϕ x − ,对于ϕ x − \phi^-_xϕ x − ,将v i v_iv i 定义的网格点向正方形平移即可,如图:
如图,(a)图为函数图像,(b)图为ENO的“权重取值”,只有0和1,因为ENO格式只取一个,(c)图为WENO算法下的权重。后面两图中,○+×分别代表123项的权重。可以看出,在多数情况下,WENO的权重很接近0.1、0.6、0.3,但是在接近奇点处会自动调整为更合适的值,保证数值计算的稳定性。