7.2. 【例題】デバイ模型の格子比熱

7.2.1. 数式

統計物理学で扱うデバイ模型(音波分散を考慮に入れた格子振動)の比熱を無次元化すると以下の積分で表されます:

(1)\frac{C}{3 N k_\mathrm{B}}
= \frac{3}{4} t^3 \int_0^{1/t} dx \frac{x^4}{\sinh^2 x/2}

ここで、t は温度をデバイ振動数 \omega_\mathrm{D} で無次元化した量 t \equiv k_\mathrm{B} T/\hbar \omega_\mathrm{D}、 積分変数 x は振動数 \omegax \equiv \hbar \omega / k_\mathrm{B} T のように無次元化した量です。

この積分は解析的に実行できないので、統計力学の教科書では低温極限 t\to0 と高温極限 t=\infty を考えて、積分を解析的に評価しています。数値積分を使って一般の温度における比熱の値を計算してみましょう。

7.2.2. 実装

ソースコード debye.py

数値積分の方法 で解説したように、被積分関数 f(x) を任意の点 x で計算できる場合には、 scipy.integrate.quad 関数を使います。この関数の詳細は scipy.integrateの使い方 もしくは公式ドキュメントを参照してください。

まず、被積分関数を定義します。

13def integrand(x):
14    if x==0:
15        return 0
16    return x**4 / np.sinh(x/2.)**2

sinhの計算にはNumPyにある関数を使用します。NumPyで利用できる数学関数の一覧は Mathematical functions にあります。 x=0 のときに分母が0になってしまうので、場合分けをしています。より正確に実装するなら、x=0 近傍でテイラー展開の式を使って計算します。

次にここで定義した関数を scipy.integrate.quad 関数に渡すことで数値積分を行います。

19def specific_heat(t, verbose=False):
20    if t==0:
21        return 0
22    y, err = integrate.quad(integrand, 0, 1./t)
23    if verbose:
24        print(f"integral : {y}")
25        print(f"error    : {err}")
26    return (3./4.) * t**3 * y

あとはこの関数を呼び出せば計算できます。 main関数を定義して、if __name__ == '__main__': からmain関数を呼び出すようにしておきます。

29def main():
30    t = 0.1
31    c = specific_heat(t, verbose=True)
32    print(f"T = {t}")
33    print(f"c = {c}")

7.2.3. 実行結果

$ python debye.py
integral : 101.094670708
error    : 7.2900227173e-07
T = 0.1
c = 0.0758210030311

7.2.4. 温度変化

さて、数値積分が実行できるようになったので、t を変えて計算しましょう。先ほどのファイルdebye.pyはそのままにして置いておき、別のファイルを用意して新たにmain部分だけを書きます。

ソースコード debye_t.py

以下のようにインポートすることで、debye.pyの中で定義されたspecific_heat関数が使えるようになります:

4from debye import specific_heat

このとき、debye.pyのスクリプトが一通り実行されますが、if __name__ == '__main__': 以下は無視されます。したがって、debye.pyにあるmain関数は実行されません。後は、t の値を変化させながら specific_heat 関数を繰り返し呼び出せば温度変化を計算できます。

 7def main():
 8    tmin = 0
 9    tmax = 2
10    n = 201
11    for t in np.linspace(tmin, tmax, n):
12        c = specific_heat(t)
13        print(f"{t:.4f} {c:.5e}")

ttmin から tmax まで等間隔に分割するのに numpy.linspace 関数を使っています。 linspace はデフォルトで終点も含めるようになっているので、点の数を n=201 としてきりの良い間隔になるようにしています。

実行して得られた結果を図示すると以下のようになります。

../_images/debye.png

破線は低温における近似式 C/3Nk_\mathrm{B} \simeq (4\pi^4 /5) t^3 で、t \lesssim 1 においてよい近似になっていることが確認できます。