【Python】水素原子の可視化:ラゲール陪多項式計算モジュール
概要
scipy(python)のラゲール陪多項式(Associated Laguerre polynomial)を使用する際の注意点についての記事です。
水素原子におけるシュレディンガー方程式の解を描画したいと思った時、その解の中にラゲール陪多項式という特殊函数が出てきます。有難いことにscipyライブラリには、ラゲール陪多項式を計算するモジュールがあり、これを利用できます。(scipy.special.assoc_laguerreなど)
問題なのが、ラゲール陪多項式の定義が資料によって揺れており、恐らく殆ど全ての量子力学の教科書に載っている定義とscipyで実装されているものが異なるということです。
なので、量子力学の教科書を見ながらラゲール陪多項式の計算モジュールを使用すると高確率で間違えます。
ちなみに、多くの量子力学の教科書(参考[7-11])で、ラゲール陪多項式
実際にscipyの実装との違いを確認した量子力学の教科書は、サクライ、シッフ、ランダウ、猪木・川合、(メシア)です(参考[7-11])。上記の教科書では、元となる定義式は違えど、式変形をしていけば式
よって、殆どの量子力学の教科書は式
また、この記事ではpythonのscipyライブライについてのみ解説しますが、Julia、Mathematicaなどでも同様の問題があるようです(Julia、mathematicaでの報告記事)。
まずは結論(忙しい人用)
御託はいいから早くコードを修正したいという人は、式
図1. 【間違った例】水素原子の動径波動関数:
図2. 【間違った例】水素原子の動径確率密度分布:
下記はコードの変更例です。
適宜、アレンジしてください。
import scipy
'''
~~~ 中略 ~~~
'''
#コードのこの部分を
hoge = hoge2 * scipy.special.assoc_laguerre(x, n+l, 2*l+1)
import scipy
'''
~~~ 中略 ~~~
'''
#このように変更
coff = (-1)**(2*l+1) * scipy.special.factorial(n+l)
hoge = hoge2 * coff * scipy.special.assoc_laguerre(x, n-l-1, 2*l+1)
ラゲール陪多項式:scipyと量子力学の教科書の違い
scipyでは式
大きく違うのは
式
式
式
ここで、式
ラゲール多項式の定義の違いも念のため書いておく。元となる微分方程式に違いは見られなかったが、解の形を露わに書き下すときに定数倍だけ違いが出てくる。元の微分方程式が線形なので、どちらの定義も正しく、どちらを採用するかは好みの問題である。式
検証:水素原子の動径波動関数と動径確率密度分布
上記まででscipyと物理の教科書との違いを述べたが、本当にそうなっているかを確認する。確認は水素原子の動径波動関数
スピンを考慮せず、電子と原子核の相互作用の影響をクーロンポテンシャルで置き換えると、定常状態における水素原子中の電子の波動関数
動径波動関数はラゲール陪多項式を用いて式
scipyのラゲール陪多項式計算モジュールの動作確認は、水素原子の1s, 2p, 3d, 4s軌道に対して行った。計算モジュールを使用した場合と、式
図3, 4に動作確認の結果を示す。実線がscipyのラゲール陪多項式計算モジュールを使用した場合の結果で、ドットで示しているのがプログラム中に関数をあからさまに記述した場合の結果である。図3, 4ともに実線とドットは重なっているので、計算モジュールを意図した通りに使用できていることが分かった。
図3. ラゲール陪多項式計算モジュールの動作確認:動径波動関数
図4. ラゲール陪多項式計算モジュールの動作確認:動径確率密度分布
使用したプログラムは下記。
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import factorial
from scipy.special import assoc_laguerre
#動径波動関数
def R_nl(r, n, l):
a0 = 1.0
zeta = 2.0/n/a0 * r
#修正係数
n_d = n-l-1
L_coff = (-1)**(2*l+1) * factorial(n+l)
f_coff = - ((2.0/n/a0)**3 * factorial(n-l-1)/2.0/n/factorial(n+l)**3)**(1.0/2.0)
f = f_coff * np.exp(-zeta/2.0) * zeta**l * L_coff * assoc_laguerre(zeta, n_d, 2*l+1)
return f
Nr = 101
rmin = 0.0
rmax = 40.0
r = np.linspace(rmin, rmax, Nr)
#動径波動関数の計算
#ラゲール陪多項式の計算モジュール使用
R_nl_1s = R_nl(r, 1, 0)
R_nl_2p = R_nl(r, 2, 1)
R_nl_3d = R_nl(r, 3, 2)
R_nl_4s = R_nl(r, 4, 0)
#関数ベタ打ち
a00 = 1.0
R_nl_1s_exp = 2 * (1/a00)**(3/2) * np.exp(-r/a00)
R_nl_2p_exp = (1/2/a00)**(3/2) * r/np.sqrt(3)/a00 * np.exp(-r/2/a00)
R_nl_3d_exp = 4/81/np.sqrt(30) * (1/a00) ** (3/2) * r**2/a00**2 * np.exp(-r/3/a00)
R_nl_4s_exp = 1/768 * (1/a00)**(3/2) * (192 - 144*r/a00 + 24*r**2/a00**2 - r**3/a00**3)*np.exp(-r/4/a00)
#動径確率密度分布の計算
#ラゲール陪多項式の計算モジュール使用
P_nl_1s = r**2 * R_nl_1s**2
P_nl_2p = r**2 * R_nl_2p**2
P_nl_3d = r**2 * R_nl_3d**2
P_nl_4s = r**2 * R_nl_4s**2
#関数ベタ打ち
P_nl_1s_exp = r**2 * R_nl_1s_exp**2
P_nl_2p_exp = r**2 * R_nl_2p_exp**2
P_nl_3d_exp = r**2 * R_nl_3d_exp**2
P_nl_4s_exp = r**2 * R_nl_4s_exp**2
#グラフフォントサイズ
plt.rcParams["font.size"] = 18
#動径波動関数の描画
fig1, ax1 = plt.subplots(2,2, figsize=(20,10))
fig1.subplots_adjust(hspace=0.4, wspace=0.3)
fig1.suptitle('$R_{nl}(r)$: Radial wave function')
ax1[0][0].plot(r, R_nl_1s, label='Module')
ax1[0][1].plot(r, R_nl_2p, label='Module')
ax1[1][0].plot(r, R_nl_3d, label='Module')
ax1[1][1].plot(r, R_nl_4s, label='Module')
ax1[0][0].plot(r, R_nl_1s_exp, label='Explicit', linestyle='None', marker='o')
ax1[0][1].plot(r, R_nl_2p_exp, label='Explicit', linestyle='None', marker='o')
ax1[1][0].plot(r, R_nl_3d_exp, label='Explicit', linestyle='None', marker='o')
ax1[1][1].plot(r, R_nl_4s_exp, label='Explicit', linestyle='None', marker='o')
ax1[0][0].set_title('1s')
ax1[0][1].set_title('2p')
ax1[1][0].set_title('3d')
ax1[1][1].set_title('4s')
for i in range(2):
for j in range(2):
ax1[i][j].grid()
ax1[i][j].legend()
ax1[i][j].set_xlabel('r/$a_0$')
ax1[i][j].set_ylabel('$R_{nl}(r)$')
#動径確率密度分布の描画
fig2, ax2 = plt.subplots(2,2, figsize=(20,10))
fig2.subplots_adjust(hspace=0.4, wspace=0.3)
fig2.suptitle('$P_{nl}(r)$: Radial probability density distribution')
ax2[0][0].plot(r, P_nl_1s, label='Module')
ax2[0][1].plot(r, P_nl_2p, label='Module')
ax2[1][0].plot(r, P_nl_3d, label='Module')
ax2[1][1].plot(r, P_nl_4s, label='Module')
ax2[0][0].plot(r, P_nl_1s_exp, label='Explicit', linestyle='None', marker='o')
ax2[0][1].plot(r, P_nl_2p_exp, label='Explicit', linestyle='None', marker='o')
ax2[1][0].plot(r, P_nl_3d_exp, label='Explicit', linestyle='None', marker='o')
ax2[1][1].plot(r, P_nl_4s_exp, label='Explicit', linestyle='None', marker='o')
ax2[0][0].set_title('1s')
ax2[0][1].set_title('2p')
ax2[1][0].set_title('3d')
ax2[1][1].set_title('4s')
for i in range(2):
for j in range(2):
ax2[i][j].grid()
ax2[i][j].legend()
ax2[i][j].set_xlabel('r/$a_0$')
ax2[i][j].set_ylabel('$P_{nl}(r)$')
水素原子の1s~4f軌道
本来の目的は水素原子の動径波動関数
図5. 水素原子の動径波動関数:
図6. 水素原子の動径確率密度分布:
使用したプログラムは下記。
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import factorial
from scipy.special import assoc_laguerre
#動径波動関数
def R_nl(r, n, l):
a0 = 1.0
zeta = 2.0/n/a0 * r
#修正係数
n_d = n-l-1
L_coff = (-1)**(2*l+1) * factorial(n+l)
f_coff = - ((2.0/n/a0)**3 * factorial(n-l-1)/2.0/n/factorial(n+l)**3)**(1.0/2.0)
f = f_coff * np.exp(-zeta/2.0) * zeta**l * L_coff * assoc_laguerre(zeta, n_d, 2*l+1)
return f
Nr = 401
rmin = 0.0
rmax = 40.0
r = np.linspace(rmin, rmax, Nr)
#動径波動関数の計算
R_nl_1s = R_nl(r, 1, 0)
R_nl_2s = R_nl(r, 2, 0)
R_nl_2p = R_nl(r, 2, 1)
R_nl_3s = R_nl(r, 3, 0)
R_nl_3p = R_nl(r, 3, 1)
R_nl_3d = R_nl(r, 3, 2)
R_nl_4s = R_nl(r, 4, 0)
R_nl_4p = R_nl(r, 4, 1)
R_nl_4d = R_nl(r, 4, 2)
R_nl_4f = R_nl(r, 4, 3)
#動径確率密度分布の計算
P_nl_1s = r**2 * R_nl_1s**2
P_nl_2s = r**2 * R_nl_2s**2
P_nl_2p = r**2 * R_nl_2p**2
P_nl_3s = r**2 * R_nl_3s**2
P_nl_3p = r**2 * R_nl_3p**2
P_nl_3d = r**2 * R_nl_3d**2
P_nl_4s = r**2 * R_nl_4s**2
P_nl_4p = r**2 * R_nl_4p**2
P_nl_4d = r**2 * R_nl_4d**2
P_nl_4f = r**2 * R_nl_4f**2
#グラフフォントサイズ
plt.rcParams["font.size"] = 18
#動径波動関数の描画
fig1, ax1 = plt.subplots(2,2, figsize=(20,10))
fig1.subplots_adjust(hspace=0.4, wspace=0.3)
fig1.suptitle('$R_{nl}(r)$: Radial wave function')
ax1[0][0].plot(r, R_nl_1s, label='1s')
ax1[0][1].plot(r, R_nl_2s, label='2s')
ax1[0][1].plot(r, R_nl_2p, label='2p')
ax1[1][0].plot(r, R_nl_3s, label='3s')
ax1[1][0].plot(r, R_nl_3p, label='3p')
ax1[1][0].plot(r, R_nl_3d, label='3d')
ax1[1][1].plot(r, R_nl_4s, label='4s')
ax1[1][1].plot(r, R_nl_4p, label='4p')
ax1[1][1].plot(r, R_nl_4d, label='4d')
ax1[1][1].plot(r, R_nl_4f, label='4f')
ax1[0][0].set_title('n=1, l=0')
ax1[0][1].set_title('n=2, l=0, 1')
ax1[1][0].set_title('n=3, l=0, 1, 2')
ax1[1][1].set_title('n=4, l=0, 1, 2, 3')
for i in range(2):
for j in range(2):
ax1[i][j].grid()
ax1[i][j].legend()
ax1[i][j].set_xlabel('r/$a_0$')
ax1[i][j].set_ylabel('$R_{nl}(r)$')
#動径確率密度分布の描画
fig2, ax2 = plt.subplots(2,2, figsize=(20,10))
fig2.subplots_adjust(hspace=0.4, wspace=0.3)
fig2.suptitle('$P_{nl}(r)$: Radial probability density distribution')
ax2[0][0].plot(r, P_nl_1s, label='1s')
ax2[0][1].plot(r, P_nl_2s, label='2s')
ax2[0][1].plot(r, P_nl_2p, label='2p')
ax2[1][0].plot(r, P_nl_3s, label='3s')
ax2[1][0].plot(r, P_nl_3p, label='3p')
ax2[1][0].plot(r, P_nl_3d, label='3d')
ax2[1][1].plot(r, P_nl_4s, label='4s')
ax2[1][1].plot(r, P_nl_4p, label='4p')
ax2[1][1].plot(r, P_nl_4d, label='4d')
ax2[1][1].plot(r, P_nl_4f, label='4f')
ax2[0][0].set_title('n=1, l=0')
ax2[0][1].set_title('n=2, l=0, 1')
ax2[1][0].set_title('n=3, l=0, 1, 2')
ax2[1][1].set_title('n=4, l=0, 1, 2, 3')
for i in range(2):
for j in range(2):
ax2[i][j].grid()
ax2[i][j].legend()
ax2[i][j].set_xlabel('r/$a_0$')
ax2[i][j].set_ylabel('$P_{nl}(r)$')
#画像の保存
fig1.savefig('動径波動関数')
fig2.savefig('動径確率密度分布')
動作環境
・python 3.9.13
・scipy 1.7.3
・Spyder 5.9.2
・Windows10 64bit
参考
[1]. scipy.special.assoc_laguerre(scipy公式ヘルプ)(参照2022-09-11)
[2]. scipy.special.genlaguerre(scipy公式ヘルプ)(参照2022-09-11)
[3]. Juliaで可視化:水素原子(参照2022-09-11)
[4]. ラゲールの陪多項式とassociated Laguerre polynomialsの指しているものが違った件(参照2022-09-11)
[5]. ラゲール多項式(英語版wikipedia)(参照2022-09-11)
[6]. ラゲールの陪多項式(日本語版wikipedia)(参照2022-09-11)
[7]. J.J.Sakurai. 現代の量子力学(上). 吉岡書店, 2006, p.351-353.
[8]. Schiff. 量子力学(上). 吉岡書店, 2004, p.106-108.
[9]. Landau, Lifshitz. 量子力学1(非相対論的理論), 東京図書, 1991, p.138-142.
[10]. 猪木, 川合. 量子力学Ⅰ. 講談社サイエンティフィク, 2010, p.148-152.
[11]. Messiah, Albert. Quantum Mechanics. 2014.
Discussion