8.2. 【例題】ボーズ・アインシュタイン凝縮の比熱¶
8.2.1. 計算式¶
理想ボーズ気体におけるボーズ・アインシュタイン凝縮の計算では、ボーズ・アインシュタイン積分と呼ばれる次の積分が登場します:
(1)¶
は化学ポテンシャルを温度によって無次元化した量
です。
ボーズ・アインシュタイン凝縮の転移温度を
とすると、
では
となり、このとき積分は
のように実行できます。
一方、
では
以下の方程式を満たすように
を決定する必要があります:
(2)¶
ここで、 は無次元化した温度
です。
が求まったら各種熱力学量が計算できます。
例えば比熱は
によって得られます。
8.2.2. 実装¶
まず、積分 (1) を計算する関数を用意しておきます。
4from scipy import integrate
5from scipy import special
21def integrand(x, s, alpha):
22 # x+alpha > 0
23 e = np.exp(-x-alpha)
24 return np.power(x, s-1) * e / (1.0 - e)
27def bose_einstein_integral(s, alpha, verbose=False):
28 y, err = integrate.quad(integrand, 0, np.inf, args=(s, alpha))
29 if verbose:
30 print(f"integral : {y}")
31 print(f"error : {err}")
32 return y / special.gamma(s)
integrand
で被積分関数を定義しています。
積分変数 に加えて、2つのパラメーター
と
を引数に取ります。
被積分関数の分母が
で発散してしまうので、
のように式変形をして計算しています。
数値積分にはSciPyの scipy.integrate.quad 関数を使っています。 この関数の使い方については scipy.integrateの使い方 を参照してください。 ガンマ関数はscipyに含まれる関数 scipy.special.gamma を利用しています。
次に、 を決定する方程式 (2) を scipy.optimize.root_scalar を使って解きます。
6from scipy import optimize
35def func_alpha(alpha, t):
36 return bose_einstein_integral(1.5, alpha) * np.power(t, 1.5) - special.zeta(1.5)
39def calc_alpha(t, verbose=False):
40 if t<=1:
41 return 0
42
43 a_min = 0
44 a_max = 100
45 sol = optimize.root_scalar(func_alpha, args=(t,), method='brentq', bracket=(a_min, a_max))
46 if verbose:
47 print(sol)
48 return sol.root
func_alpha
で方程式 (2) を定義しています。
このとき、第一引数が決定したい変数 で第二引数がパラメーターです。
optimize.root_scalar
関数に func_alpha
関数を渡すことで方程式 (2) を満たす が得られます。
あとは calc_alpha
関数から を受け取って比熱を計算すれば完成です。
51def calc_specific_heat(alpha, t):
52 if t<=1:
53 z52 = special.zeta(2.5)
54 z32 = special.zeta(1.5)
55 return 15. * z52 / (4. * z32) * np.power(t, 1.5)
56 else:
57 f12 = bose_einstein_integral(0.5, alpha)
58 f32 = bose_einstein_integral(1.5, alpha)
59 f52 = bose_einstein_integral(2.5, alpha)
60 return 15. * f52 / (4. * f32) - 9. * f32 / (4. * f12)
63def solve_bec(t, verbose=False):
64 alpha = calc_alpha(t, verbose=verbose)
65 c = calc_specific_heat(alpha, t)
66 return alpha, c
main関数から solve_bec
関数を呼び出し、結果を表示します。
69def main():
70 t = 1.5
71 alpha, c = solve_bec(t, verbose=True)
72 print(f"alpha = {alpha}")
73 print(f"c = {c}")
8.2.3. 実行結果¶
$ python bec.py
converged: True
flag: 'converged'
function_calls: 17
iterations: 16
root: 0.16114443396626077
alpha = 0.161144433966
c = 1.7103442045884472
8.2.4. 温度変化¶
温度変化を計算するには、main関数だけ新たに作ります。 ファイルの冒頭にある
from bec import solve_bec
の一文によって、bec.pyファイルの中で定義されている solve_bec
関数がインポートされ使用できるようになります。
ただし、bec_t.pyとbec.pyは同じディレクトリに置く必要があります。
計算結果を図示すると、以下のように、ボーズ・アインシュタイン凝縮の比熱が得られます。
