Numerov method on linear and logarithmic grids (CN)
背景
Numerov方法是数值求解常微分方程(ODE)的一种方法, 适用于不含一阶项的二阶ODE
在物理上有很多方程满足这种形式, 其中与我最为相关的是薛定谔方程(SE), 更确切的是三维有心势下的径向薛定谔方程(rSE). 原子单位下, rSE写成
其中$R_l$是定义在一维实空间$r$上的波函数$u_l$与矢径长$r$的积, $R_l(r)=ru_l(r)$, $E_l$是能量, $l$是角量子数. 这个方程满足Numerov方程要求的ODE形式
因此可以用该方法数值求解. 本文首先在两种格点方案, 均匀格点和对数格点上推导Numerov方法的核心方程, 即格点递推公式, 然后给出简单的Python实现.
推导
线性均匀格点
首先在线性均匀格点上推导一下Numerov方法. 在$r$点附近对函数$y$作Taylor展开
将正负两式相加
由于
定义$p(r):=f(r)y(r)-s(r), p=y’’, p’‘=y’’’’$, 可以采用与式
把$p, p^{‘’}$表达式
稍作整理, 得到
这就是 Numerov 方法的一般方程. 特别的, 对于齐次方程, $s=0$, 式子可以化简成
取间距为 $h$ 的均匀格点, 此时上式化成三点递推方程,
精确到步长的六次方. 实际应用当中, 我们需要先确定前两个格点上的值, 然后就可以用上式推出第三点及之后所有格点上的函数值.
对数均匀格点
除了实空间均匀格点, 我们也可以使用对数均匀格点 (logarithmic grid), 其上第 n 个实空间格点为
上面的 Numerov 方法不能直接用于格点${r_n}$, 因为这种情况下格点 $r$ 的间距是随格点指标变化的, 但是我们可以通过代数变换使之成为可能.
首先定义变量替换$x\mapsto r$
及定义 $Y(x)$ 为
从而
其中撇号代表对$x$求导而非$r$. 代回到式
令
于是得到 ODE
这与原始ODE
Python实现
以下是忽略了s后, Numerov方法在线性格点和对数格点上的Python实现. Numba 装饰器用于编译优化.
首先是线性均匀格点上的实现numerov
. 这里参考了Kristjan Haule的代码.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@numba.njit
def numerov(f, h, y0, dy0):
'''Solve y''(r) + f(r)y(r)=0 by Numerov method on a linear r grid
Args:
f (1d-array): f
h (float): the step size of linear grid
y0 (float): y value at the first grid point
dy0 (float): first-order derivaitve at the first grid point
'''
y = np.zeros(len(f))
y[0] = y0
y[1] = y0 + h * dy0
h2 = h**2
h2d12 = h2/12.0
w0 = y0 * (1 + h2d12 * f[0])
w1 = y[1] * (1 + h2d12 * f[1])
yn = y[1]
fn = f[1]
for n in range(2, len(f)):
w2 = 2 * w1 - w0 - h2 * fn * yn
fn = f[n]
yn = w2 / (1 + h2d12 * fn)
y[n] = yn
w0, w1 = w1, w2
return y
然后是对数均匀格点上的实现numerov_log
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@numba.njit
def numerov_log(r, f, y0, dy0):
'''Solve y''(r) + f(r)y(r) = 0 by Numerov method on a logarithmic r grid
Args:
r (1d-array): the logarithmic grid
f (1d-array)
y0 (float): y at the first grid
dy0 (float): first-order derivaitve at the first grid
'''
r0 = r[0]
# calculate F(x)
F = np.multiply(f, np.power(r, 2)) - 0.25E0
x = np.log(r/r0)
# step size in x
hx = x[1] - x[0]
# convert boundary condition of y to Y
Y0 = y0 / r0
dY0 = - Y0/2 + dy0 * r0
# call Numerov on linear grid x
Y = numerov(F, hx, Y0, dY0)
return Y * np.sqrt(r * r0)
总结
本文在两种数值格点(均匀格点和对数格点)上推导了Numerov方法的递推方程, 给出了简单的Python实现.