Bose凝縮の計算
mode = Fs: F_sigma(alpha) 関数の表示
mode = mu: mu (chamical potential), N', n0の計算

Download script from .\bose_condensation.py


import sys
import time
from math import exp, sqrt
import numpy as np
from scipy import integrate # 数値積分関数 integrateを読み込む
from scipy import optimize # newton関数はscipy.optimizeモジュールに入っている
from matplotlib import pyplot as plt


"""
Bose凝縮の計算
mode = Fs: F_sigma(alpha) 関数の表示
mode = mu: mu (chamical potential), N', n0の計算
"""



#定数
pi = 3.14159265358979323846
h = 6.6260755e-34 # Js";
hbar = 1.05459e-34 # "Js";
c = 2.99792458e8 # m/s";
e = 1.60218e-19 # C";
kB = 1.380658e-23 # JK-1";
me = 9.1093897e-31 # kg";
mp = 1.6726231e-27 # kg";
mn = 1.67495e-27 # kg";

zeta32 = 0

# mode = [Fs|mu]
mode = 'Fs' # Fs-α=-mu/kB/Tプロット
#mode = 'mu' # mu-Tプロット

# 有効質量、電子濃度
m = 6.64e-27 # kg, 4He
N = 2.18e22 # cm^-3, Liq He


# Temperature range
Tmin = 3.00 # K
Tmax = 4.00
Tstep = 0.01

# alpha = -EF / kB / T range
alphamin = 0.0
alphamax = 2.0
alphastep = 0.02


#muの誤差がepsより小さくなったら計算終了。TC付近ではEFが10^-9程度にもなるので、小さい値を指定
eps = 1.0e-12
#二分法の最大繰り返し数
nmaxiter = 100
#繰り返し中に途中経過を出力するサイクル数
iprintiterval = 1


# 起動時引数
argv = sys.argv
if len(argv) <= 1:
    print("Usage: python bose_condensation.py mu Tmin Tmax Tstep")
    print("Usage: python bose_condensation.py Fs Tmin Tmax Tstep alphamin alphamax alphastep")
    print(" ex: python bose_condensation.py mu 2.5 4.5 0.01")
    print(" ex: python bose_condensation.py Fs 3 4.5 0.2 0 0.5 0.002")
    exit()

if len(argv) >= 2:
    mode = argv[1]
if len(argv) >= 3:
    Tmin = float(argv[2])
if len(argv) >= 4:
    Tmax = float(argv[3])
if len(argv) >= 5:
    Tstep = float(argv[4])
if len(argv) >= 6:
    alphamin = float(argv[5])
if len(argv) >= 7:
    alphamax = float(argv[6])
if len(argv) >= 8:
    alphastep = float(argv[7])

nT = int((Tmax - Tmin) / Tstep + 1.00001)
nalpha = int((alphamax - alphamin) / alphastep + 1.00001)


# Γ関数
def Gamma(sigma):
    if abs(sigma - 1.0) < 1.0e-6:
        return 1.0
    if abs(sigma - 0.5) < 1.0e-6:
        return sqrt(pi)
    if sigma < 0.5 - 1.0e-6:
        print("Gamma: Abnormal argment sigma = ", sigma)
        print(" Exit")
        exit()
    return (sigma - 1.0) * Gamma(sigma - 1.0)

# Fs(σ, α)の被積分関数
def IntegFunc(y, sigma, alpha):
    if y + alpha > 100.0:
        return 0.0
    return pow(y, sigma - 1.0) / (exp(y + alpha) - 1.0)

# Fs(σ, α)
def Fsalpha(sigma, alpha, Emax = 10.0, eps = 1.0e-8):
    ret = integrate.quad(lambda y: IntegFunc(y, sigma, alpha), 0.0, Emax, epsrel = eps)
    return 1.0 / Gamma(sigma) * ret[0]

# EFを与えてT>Tcでの電子濃度を求める
def Ne(EF, T, Emax = 10.0, eps = 1.0e-8):
    lambdaT = h / sqrt(2.0 * pi * m * kB * T)
    alpha = -EF / (kB * T / e)
    Ne = 1.0 / pow(lambdaT, 3.0) * Fsalpha(1.5, alpha, Emax = Emax, eps = eps) * 1.0e-6
    return Ne

# 二分法でEFを求める
def CalEF(T, N, EFmin, EFmax):
# まず、EFmin,EFmaxにおけるΔQを計算し、それぞれが正・負あるいは負・生となっていることを確認する
    dQmin = Ne(EFmin, T) - N
    dQmax = Ne(EFmax, T) - N
#        print(" EFmin = {:12.8f} dQmin = {:12.4g}".format(EFmin, dQmin))
#        print(" EFmax = {:12.8f} dQmax = {:12.4g}".format(EFmax, dQmax))
    if dQmin * dQmax > 0.0:
        print("Error: Initial Emin and Emax should be chosen as dQmin * dQmax < 0")
        return 0

# 二分法開始
    for i in range(nmaxiter):
        EFhalf = (EFmin + EFmax) / 2.0
        dQhalf = Ne(EFhalf, T) - N
#        print(" Iter {}: EFhalf = {:12.8f} dQhalf = {:12.4g}".format(i, EFhalf, dQhalf))
# EFの精度がepsより小さくなったら計算終了
        if abs(EFmin - EFhalf) < eps and abs(EFmax - EFhalf) < eps:
#                    print(" Success: Convergence reached at EF = {}".format(EFhalf))
            break
        if dQmin * dQhalf < 0.0:
            EFmax = EFhalf
            dQmax = dQhalf
        else:
            EFmin = EFhalf
            dQmin = dQhalf
    else:
        print(" Failed: Convergence did not reach")
        exit()
    return EFhalf


def ExecFs():
    global m, zeta32

# グラフの準備
    fig = plt.figure()

    ax1 = fig.add_subplot(1, 1, 1)
    ax1.set_xlabel("alpha = -mu / kB / T")
    ax1.set_ylabel("Ne (cm-3)")

    for i in range(nT):
        T = Tmax - i * Tstep
        lambdaT = h / sqrt(2.0 * pi * m * kB * T)
        Nmax = 1.0 / pow(lambdaT, 3.0) * zeta32 * 1.0e-6
        print("T = %g K lamda_T = %g nm Nmax = %g cm-3" % (T, lambdaT * 1e9, Nmax))

        print(" alpha\tmu(eV)\tFs\tNe(cm-3)")
        xalpha = []
        xEF = []
        yFs = []
        yNe = []
        for ia in range(nalpha):
            alpha = alphamin + ia * alphastep
            EF = -alpha * kB * T / e
            fs = Fsalpha(1.5, alpha)
            ne = Ne(EF, T)
            xEF.append(EF)
            yFs.append(fs)
            yNe.append(ne)
#            print("%10.6f\t%10.6g\t%16.6g\t%16.6e" % (alpha, EF, fs, ne))
# 温度Tのグラフを追加
            xalpha.append(alpha)

        ax1.plot(xalpha, yNe, label = 'Ne(%g K)' % (T), linewidth = 0.6)

# Nの線を追加
    ax1.plot([alphamin, alphamax], [N, N], color = 'red', linewidth = 0.3, linestyle = 'dashed')
    ax1.set_xlim([alphamin, alphamax])

#=============================
# グラフの表示
#=============================
    ax1.legend()
    plt.pause(0.1)

    print("Press ENTER to exit>>", end = '')
    input()


def ExecMu():
    global m, zeta32

    Tc = h * h / 2.0 / pi / m / kB * pow(N*1.0e6 / zeta32, 2.0/3.0)

    xT = []
    yEF = []
    yEFapprox = []
    print(" T(K) \tlambda_T(nm)\t EF(eV)\t Fapprox(eV)\t N'(cm-3)\t Nmax(cm-3)\t N0(cm-3)")
    for i in range(nT):
        T = Tmax - i * Tstep
        lambdaT = h / sqrt(2.0 * pi * m * kB * T)
        Nmax = 1.0 / pow(lambdaT, 3.0) * zeta32 * 1.0e-6
        if T < Tc:
            EF = 0.0
            EFapprox = 0.0
#            Ncal = Ne(EF, T, lambdaT)
#            N0 = N - Ne(EF, T, lambdaT)
            Ncal = N * pow(T / Tc, 1.5)
            N0 = N - Ncal
            print("%8.5f\t%8.4g\t%12.4g\t%12.4g\t%12.4e\t%12.4e\t%12.4e" % (T, lambdaT * 1.0e9, EF, EFapprox, Ncal, Nmax, N0))
        else:
#初期範囲
            EFmin = -2.0
            EFmax = -1.0e-100
            EF = CalEF(T, N, EFmin, EFmax)
            t = (T - Tc) / Tc
            Aapprox = 9.0 / 16.0 / pi * zeta32 * zeta32 * t * t
            EFapprox = -Aapprox * kB * T / e
            Ncal = Ne(EF, T)
            print("%8.5f\t%8.4g\t%12.4g\t%12.4g\t%12.4e\t%12.4e" % (T, lambdaT * 1.0e9, EF, EFapprox, Ncal, Nmax))
        xT.append(T)
        yEF.append(-EF / (kB * T / e))
        yEFapprox.append(-EFapprox / (kB * T / e))

#=============================
# グラフの表示
#=============================
    fig = plt.figure()

    ax1 = fig.add_subplot(1, 1, 1)
    ax1.plot(xT, yEF, label = 'alpha')
    ax1.plot(xT, yEFapprox, label = 'alpha(approx)', linestyle = '-', linewidth = 0.5, color = 'red')
    ax1.set_xlabel("T (K)")
    ax1.set_ylabel("alpha = -mu/(kBT)")
    ax1.set_xlim([Tmin, Tmax])
    ax1.set_ylim([0.0, max(yEF)])
    ax1.legend()

    plt.pause(0.1)

    print("Press ENTER to exit>>", end = '')
    input()


def main():
    global m, zeta32

    zeta32 = Fsalpha(1.5, 0.0)
    print("m = ", m, " kg")
    print("N = ", N, " cm^-3")
    print("")
    print("G(1.5)=", Gamma(1.5))
    print("F3/2(0)=", zeta32)
    print("")

    Tc = h * h / 2.0 / pi / m / kB * pow(N*1.0e6 / zeta32, 2.0/3.0)
    print("Tc=", Tc, " K")
    print("")

    if mode == 'Fs':
        ExecFs()
    if mode == 'mu':
        ExecMu()


if __name__ == '__main__':
    main()