数值求解波动方程 [5]
二维 PML
在二维空间里有两个空间轴 , 那么 PML 变换也应该分别施加在这两个轴上. 对于二维 PML 变换应有
和
.
对二维波动方程施加拉普拉斯变换得 . 然后施加 PML 变换, 为了简便, 记
, 则得
. 因为
只与
有关而与
无关, 所以有
, 同理
也有类似的结论. 那么上式左右同乘
得
. 计算可得:
,
和
, 代入上式得:
引入新量 , 使得
, 上式右边变为
, 并且由定义有
. 把全部东西从 s 域变回时域即得到:
这就是二维的 PML 波动方程了.

在写出离散化前, 为了简便先进行一下符号约定: 记 为
, 用这个记法可以很方便地描述与任意一个元素相邻的其他元素, 比如说
, 还有
, 根据这个记法可以有
, 虽然在一定程度上会产生歧义, 但是因为离散化后的式子只会有指定索引的元素, 而没有一整个场, 所以将就着用吧.
使用上述记法, 并使用 以节省内存, 二维 PML 波动方程离散化为
其中 和
.
离散化后, 出现了 10 个系数, 这些系数的重复度较高, 所以可以先预计算一部分系数, 然后在 update! 里再计算其他系数, 这样就可以在提升计算速度的同时不占用大量内存. 但是我内存大, 下面实现预计算全部 10 个系数, 以使计算效率最大化.

根据上面的式子, 二维 PML 波动方程实现为:

尽管看起来长得有点恐怖, 但是逻辑是跟之前的一样的 (用了很多 julia 特性化简). 模拟成品如下:


另外重写了 WaveRecord 类和方法, 现在产生的中间帧会储存在硬盘上而不是直接放在内存上, 并且暴露里中间把场渲染成图片的方法: `save_frame`.

上面的视频使用以下代码进行模拟:




三维波动方程 & PML 版本
因为受限于内存以及计算速度等因素, 三维波动方程就不打算进行实现了 (主要是懒), 所以干脆在这里把三维的 PML 一起放出了.
三维波动方程为 . 为三维的加上 PML 与二维的类似:
首先把波动方程从时域变为 s 域得 .
做 PML 变换得 , 其中
.
上式乘以 得
.
计算可得: 以及
.
引入 4 个新量: , 即
.
把新量代入, 再转回时域得到
,
这就是三维 PML 波动方程了, 虽然原理都是一样的, 但是这个真的太长了, debug 十万年, 所以就原谅我不去实现了 (

有可能这就是数值模拟波动方程的最后一篇专栏了, 虽然最关键的还有一个麦克斯韦方程组还没搞, 但是上面的标量三维 PML 波动方程都这么复杂了, 更何况三维 PML 麦克斯韦方程组.

