Juliaで可視化:非調和振動子
モースポテンシャルの中を運動する粒子のSchrödinger方程式の解を可視化する.
パッケージ
Juliaのパッケージモードでadd Plots
, add LaTeXStrings
, add SpecialPolynomials
, add SpecialFunctions
を実行し, 事前にパッケージをインストールしておく必要がある. また, ノート上ではusing Plots
, using LaTeXStrings
, using SpecialPolynomials
, using Functions
を宣言する. Jupyter Notebookのインストール・使い方についてはこちらの記事, Plots.jlの使い方についてはこちらの記事を参照されたい.
# using Pkg
# Pkg.add("Plots")
# Pkg.add("LaTeXStrings")
# Pkg.add("SpecialPolynomials")
# Pkg.add("SpecialFunctions")
using Plots
using LaTeXStrings
using SpecialPolynomials
using SpecialFunctions
時間に依存しないSchrödinger方程式
モースポテンシャル
Morse(1929)より式(4)の記号を少し変えたモースポテンシャルは
であり, この中で運動する質量
である. これに対する時間に依存しないSchrödinger方程式
の解は戸田(1999)とWikipediaをそれぞれ修正して
と与えらえる. ただし,
V(r, re, De, a) = De*( exp(-2*a*(r-re)) -2*exp(-a*(r-re)) )
# using SpecialFunctions
# using SpecialPolynomials
Γ(z) = try; gamma(z); catch; Inf; end
function ψ(n, r, re ,De, a, µ)
ℏ = 1.0
λ = sqrt(2*µ*De)/(a*ℏ)
ξ = 2*λ*exp(-a*(r-re))
s = 2*λ-2*n-1
N = sqrt(factorial(n)s*a/Γ(s+n+1))
return N*ξ^(s/2)*exp(-ξ/2)*basis(Laguerre{s}, n)(ξ)
end
function E(n, De, a, µ)
ℏ = 1.0
k = 2*a^2*De
ω = sqrt(k/µ)
χ = ℏ*ω/(4*De)
return - De + ℏ*ω*(n+1/2) - χ*ℏ*ω*(n+1/2)^2
end
re = 1.38436
De = 1.13133356259 - 1
k = 12.772/15.569141/2
a = sqrt(k/(2*De))
µ = 1/(1/1837.108542 + 1/1837.108542)
println("re = ", re)
println("De = ", De)
println("k = ", k)
println("a = ", a)
println("µ = ", µ)
re = 1.38436
De = 0.13133356259000006
k = 0.4101703491541377
a = 1.249623750214457
µ = 918.554271
以上の関数とパラメータを用いて, モースポテンシャルは以下のように描写できる.
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(-3:0.02:7, r->V(r,re,De,a), label="", lc="#578FC7", lw=2)
# 表示
plot!() |> display
モースポテンシャルでは有限の束縛状態でない準位では
for n in 0:15
println(n, "\t", E(n+1,De,a,µ)-E(n,De,a,µ) > 0)
end
0 true
1 true
2 true
3 true
4 true
5 true
6 true
7 true
8 true
9 true
10 true
11 true
12 false
13 false
14 false
15 false
束縛状態のエネルギー準位を全て描写すると
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(0:0.02:7, r->V(r,re,De,a), label="", lc="#578FC7", lw=2)
# エネルギー
for n in 11:-1:0
plot!(0:0.02:7, r-> E(n,De,a,µ)<V(r,re,De,a) ? NaN : E(n,De,a,µ), label="", lc="#578FC7", lw=1)
end
# 表示
plot!() |> display
波動関数をエネルギーの高さまでシフトし, 縦に縮めて書き足す. ここでは
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(-3:0.02:7, r->V(r,re,De,a), label="", lc="#000000", lw=2)
for n in 11:-1:0
# エネルギー(破線)
hline!([E(n,De,a,µ)], label="", lc="#000000", ls=:dash)
# エネルギー(実線)
plot!(0:0.02:7, r-> E(n,De,a,µ)<V(r,re,De,a) ? NaN : E(n,De,a,µ), label="", lc="#000000", lw=2)
# 波動関数
plot!(0:0.02:7, r->0.004*ψ(n,r,re,De,a,µ)+E(n,De,a,µ), label=latexstring("n=$n"), lc=n+1, lw=2)
end
# 表示
plot!() |> display
数値積分による検算
固有関数が正しく宣言できているのか見た目だけでは判断できないことが多いので, ライブラリの使い方が正しいか, バグが無いか, 文献に誤りがないか等を確認する意味も含め, 規格化条件
# 数値積分のルーチン
integral(func, x_min, x_max, dx) = sum(func.(x_min:dx:x_max)*dx)
# 規格化条件の確認
println("n \t∫|ψ(r)|²dr")
for n in 0:11
println(n, "\t", integral(r->ψ(n,r,re,De,a,µ)^2, -10, 50, 0.001))
end
n ∫|ψ(r)|²dr
0 1.0000000000000002
1 1.0
2 0.9999999999999998
3 1.0000000000000004
4 1.0
5 0.9999999999999997
6 0.9999999999999999
7 0.9999999999999997
8 0.9999999999999989
9 1.0
10 0.9999999999999999
11 0.9999999999999988
次にエネルギーを数値積分によって評価する. 調和振動子とは違ってビリアル定理が使えないので, 運動項と向き合わなければならない. 2階微分は差分法を用いて
と近似できるので, 実関数であること
と離散化できる. ただし,
println("n \tE\t\t\t∫ψHψdr")
dr = 0.005
ψVψ(n,r,re,De,a,µ) = V(r,re,De,a) * ψ(n,r,re,De,a,µ)^2
ψTψ(n,r,re,De,a,µ,dr) = -1/(2*µ) * ψ(n,r,re,De,a,µ) * (ψ(n,r+dr,re,De,a,µ)-2*ψ(n,r,re,De,a,µ)+ψ(n,r-dr,re,De,a,µ))/dr^2
ψHψ(n,r,re,De,a,µ,dr) = ψTψ(n,r,re,De,a,µ,dr) + ψVψ(n,r,re,De,a,µ)
for n in 0:11
println(n, "\t", E(n,De,a,µ), "\t", integral(r->ψHψ(n,r,re,De,a,µ,dr), dr, 100, dr))
end
n E ∫ψHψdr
0 -0.12098032966578513 -0.12098063308527979
1 -0.10154887790721412 -0.10155018470683336
2 -0.08381744493512158 -0.08382034362426742
3 -0.06778603074950751 -0.06779072698018129
4 -0.05345463535037193 -0.053461018312416515
5 -0.040823258737714835 -0.040830967539695506
6 -0.0298919009115362 -0.02990039094983932
7 -0.020660561871836063 -0.020669171190581332
8 -0.013129241618614396 -0.0131372572629767
9 -0.007297940151871213 -0.0073046645173990635
10 -0.003166657471606507 -0.0031714746521237978
11 -0.0007353935778202786 -0.0007378357145039691
調和近似
このポテンシャルの調和近似に相当する調和振動子ポテンシャルとそのハミルトニアンの固有値および固有関数は
ただし,
である. エネルギーをモールポテンシャルと比較すると, 第3項(非調和項)のみの違いであることがわかる. また, 調和近似と言ったものの, むしろ先にバネ定数
module HO
using SpecialPolynomials
# ポテンシャル
V(r, re, De, k) = - De + 1/2*k*(r-re)^2
# 固有関数
# using SpecialPolynomials
function ψ(r,re,n,k,m)
ℏ = 1.0
ω = sqrt(k/m) # mu = 1 / (1/m1 + 1/m2)
A = sqrt(1/(factorial(n)*2^n)*sqrt(m*ω/(π*ℏ)))
ξ = sqrt(m*ω/ℏ) * (r-re)
return A*basis(Hermite, n)(ξ)*exp(-ξ^2/2)
end
# 固有値
function E(n,De,k,m)
ℏ = 1
ω = sqrt(k/m)
return - De + ℏ*ω*(n+1/2)
end
end
描写してモースポテンシャルと比較すると, 極小点ではよく似た形をしていることがわかる.
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(0:0.02:7, r->V(r,re,De,a), label="Morse Potential", lc="#578FC7", lw=2)
plot!(0:0.02:7, r->HO.V(r,re,De,k), label="Harmonic Oscillator", lc="#BC1C5F", lw=2)
# 表示
plot!() |> display
次にエネルギーを描写する. 低い準位では, 高い準位に比べればよく一致している. 準位の間隔が一定であるため, 束縛状態の数は少なくなる.
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(0:0.02:7, r->V(r,re,De,a), label="Morse Potential", lc="#578FC7", lw=2)
plot!(0:0.02:7, r->HO.V(r,re,De,k), label="Harmonic Oscillator", lc="#BC1C5F", lw=2)
# エネルギー
for n in 11:-1:0
plot!(0:0.02:7, r-> E(n,De,a,µ)<V(r,re,De,a) ? NaN : E(n,De,a,µ), label="", lc="#578FC7")
end
for n in 5:-1:0
plot!(0:0.02:7, r-> HO.E(n,De,k,µ)<HO.V(r,re,De,k) ? NaN : HO.E(n,De,k,µ), label="", lc="#BC1C5F")
end
# 表示
plot!() |> display
次に調和振動子の波動関数を描写する.
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(-3:0.02:17, r->V(r,re,De,a), label="", lc="#737B85", lw=1, ls=:dash)
plot!(-3:0.02:17, r->HO.V(r,re,De,k), label="", lc="#000000", lw=2)
for n in 11:-1:0
# エネルギー(実線)
plot!(0:0.02:7, r-> E(n,De,a,µ)<V(r,re,De,a) ? NaN : E(n,De,a,µ), label="", lc="#737B85", lw=1, ls=:dash)
end
for n in 5:-1:0
# エネルギー(破線)
# hline!([HO.E(n,De,k,µ)], label="", lc="#000000", ls=:dash)
# エネルギー(実線)
plot!(0:0.02:7, r-> HO.E(n,De,k,µ)<HO.V(r,re,De,k) ? NaN : HO.E(n,De,k,µ), label="", lc="#000000", lw=2)
# 波動関数
plot!(0:0.02:7, r->0.004*HO.ψ(r,re,n,k,µ)+HO.E(n,De,k,µ), label=latexstring("n=$n"), lc=n+1, lw=2)
end
# 表示
plot!() |> display
調和振動子の波動関数(破線)とモース振動子の波動関数(実線)を比較すると, 以下のようになる. 低い準位では非調和性が小さく, 調和近似による記述も高い準位に比べれば悪くない. 高い振動準位では, エネルギーの差に加えて, 波動関数の最大値が長距離側へシフトする傾向も顕著に表れる.
# 軸ラベル, 描写範囲, 凡例位置
plot(xlabel=L"r", ylabel=L"V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(-3:0.02:17, r->V(r,re,De,a), label="", lc="#000000", lw=2)
plot!(-3:0.02:17, r->HO.V(r,re,De,k), label="", lc="#000000", lw=1, ls=:dot)
# 波動関数
for n in 5:-1:0
plot!(0:0.02:7, r->0.004*HO.ψ(r,re,n,k,µ)+HO.E(n,De,k,µ), label="", lc=n+1, lw=1, ls=:dot)
plot!(0:0.02:7, r->0.004*ψ(n,r,re,De,a,µ)+E(n,De,a,µ), label=latexstring("n=$n"), lc=n+1, lw=2)
end
# 表示
plot!() |> display
時間に依存するSchrödinger方程式
時間に依存するSchrödinger方程式
の解は一般に
である. これが解であることは単に代入すれば示せる(総和と微分演算子が交換可能である条件を確認せよ). ただし,
を定義する係数である.
function Ψ(N,t,r,re,De,a,µ) # ← 大文字のΨなので注意
sum = 0.0 + im*0.0
for n in 0:N
sum += c(n) * ψ(n,r,re,De,a,µ) * exp(im*E(n,De,a,µ)*t)
end
return sum
end
# 時間発展の描写
function draw(num)
anim = Animation()
N = 10
for i in 0:100
# 時刻
t = 10.0*i
# 描写範囲, タイトルなど
plt = plot(title="t=$t", xlabel="r", ylabel="V(r)", xlims=(0.2,6.2), ylims=(-0.14,0.01), legend=:bottomright)#, size=(450,400))
# ポテンシャル
plot!(0:0.01:17, r->V(r,re,De,a), label="", lc="#000000", lw=2)
# 実部 Re Ψ(x,t)
plot!(plt, 0:0.01:7, r->real(Ψ(N,t,r,re,De,a,µ))*0.05 + sum(c.(0:N) .* E.(0:N,De,a,µ)), label="Re", lc=1)
# 虚部 Im Ψ(x,t)
plot!(plt, 0:0.01:7, r->imag(Ψ(N,t,r,re,De,a,µ))*0.05 + sum(c.(0:N) .* E.(0:N,De,a,µ)), label="Im", lc=2)
# 確率密度 |Ψ(x,t)|^2
plot!(plt, 0:0.01:7, r->abs(Ψ(N,t,r,re,De,a,µ))^2*0.05 + sum(c.(0:N) .* E.(0:N,De,a,µ)), label="P(x,t)", lc=3, lw=2)
# コマの追加
frame(anim, plt)
end
gif(anim, "TDSE_$(num).gif", fps = 20)
end
まず, 初期条件が純粋に基底状態のみ(
c(n) = n==0 ? 1 : 0
draw(1)
次に, 基底状態と第1励起状態を等しい割合で混ぜた初期条件(
c(n) = n<2 ? 0.5 : 0
draw(2)
最後に,
c(n) = 2.0^(-n-1)
draw(3)
動作環境
versioninfo()
Julia Version 1.6.2
Commit 1b93d53fc4 (2021-07-14 15:36 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, haswell)
参考文献
この記事の元になったJupyter Notebookのデータは下記のリンクにある.
Juliaで可視化シリーズ
Discussion