cms.differentiation.EffectiveMass のソースコード

"""
バンド構造データから有効質量を計算しプロットするスクリプトです。

このスクリプトは、k空間でのエネルギーバンドデータ(CSV形式)を読み込み、
その二次微分を用いて有効質量を計算します。計算された有効質量は、
自由電子質量meに対する相対値としてプロットされます。
特に、有効質量が極端に大きくなる(逆有効質量が0に近づく)点を
識別し、プロット上で区切りとして表現します。

関連リンク:
    :doc:`EffectiveMass_usage`
"""
import sys
import numpy as np
from numpy import sqrt, exp, sin, cos, tan, pi
import numpy.linalg as LA 
import csv
from matplotlib import pyplot as plt


#===================================
# physical constants
#===================================
pi   = 3.14159265358979323846
pi2  = 2.0 * pi
h    = 6.6260755e-34    # Js";
hbar = 1.05459e-34      # "Js";
c    = 2.99792458e8     # m/s";
e    = 1.60218e-19      # C";
e0   = 8.854418782e-12; # C<sup>2</sup>N<sup>-1</sup>m<sup>-2</sup>";
kB   = 1.380658e-23     # JK<sup>-1</sup>";
me   = 9.1093897e-31    # kg";
R    = 8.314462618      # J/K/mol
a0   = 5.29177e-11      # m";


#===================================
# parameters
#===================================
a = 4.0e-10 #m

infile = 'band.csv'
cutline = 1

#===================================
# figure configuration
#===================================
fontsize        = 12
legend_fontsize = 8


#=============================
# other functions
#=============================
[ドキュメント] def savecsv(outfile, header, datalist): """ 指定されたヘッダーとデータリストをCSVファイルに保存します。 `datalist`は列指向のデータ構造として扱われ、各内部リストが1つの列を表します。 ファイルへの書き込み時には、これらの列が転置されて行として書き込まれます。 ファイル書き込みに失敗した場合はエラーメッセージを出力します。 :param outfile: str: 出力するCSVファイルのパス。 :param header: list[str]: CSVファイルのヘッダー行として使用される文字列のリスト。 :param datalist: list[list[float]]: 保存するデータ。 datalist[j][i]がi行j列の要素となるような(列優先の)構造を想定しています。 例: `[[col1_row1, col1_row2], [col2_row1, col2_row2]]` :returns: None """ try: print("Write to [{}]".format(outfile)) f = open(outfile, 'w') except: # except IOError: print("Error: Can not write to [{}]".format(outfile)) else: fout = csv.writer(f, lineterminator='\n') fout.writerow(header) # fout.writerows(data) for i in range(0, len(datalist[0])): a = [] for j in range(len(datalist)): a.append(datalist[j][i]) fout.writerow(a) f.close()
[ドキュメント] def read_csv(fname): """ 2列のCSVファイルを読み込み、x軸/y軸のラベルとデータを返します。 最初の行をヘッダーとしてx軸とy軸のラベルを抽出し、それ以降の行を 浮動小数点数データとして読み込みます。数値変換に失敗した行は警告を 出力し、そのデータはスキップされます。 :param fname: str: 読み込むCSVファイルのパス。 :returns: tuple[str, str, list[float], list[float]]: x軸のラベル、y軸のラベル、xデータ(浮動小数点数のリスト)、yデータ(浮動小数点数のリスト)。 """ x = [] y = [] with open(fname) as f: fin = csv.reader(f) aa = next(fin) xlabel = aa[0] ylabel = aa[1] for row in fin: try: x.append(float(row[0])) y.append(float(row[1])) except: print("Warning: Invalid float data [{}] or [{}]".format(row[0], row[1])) return xlabel, ylabel, x, y
[ドキュメント] def main(): """ メイン処理を実行し、有効質量の計算とプロットを行います。 `infile`で指定されたCSVファイルからk-Eバンド構造データを読み込み、 中心差分法を用いてエネルギーEのkに関する2次微分d^2E/dk^2を計算します。 この2次微分から有効質量の逆数(1/m*)を導出し、自由電子質量meに対する 相対有効質量(m*/me)を求めます。 有効質量が極端に大きくなる(逆有効質量がほぼ0になる)点や、有効質量の 符号が反転する点では、プロットを一時的に切断し、視認性を高めます。 `nskip`の異なる2つのケース(`nskip=1`と`nskip=4`)で計算とプロットを行い、 計算結果を比較できるようにします。最後に、結果をMatplotlibで表示します。 :returns: None """ klabel, Elabel, k, E = read_csv(infile) print("k=", k) print("E=", E) nk = len(k) dk = k[1] - k[0] km = hbar * hbar * (pi2 / a)**2.0 nskip = 1 xk = [] ymc = [] signprev = None print("") print("Differentiate for nskip = ", nskip) print("i E[i-1] E[i] E[i+1] 1.0/m*") for i in range(nskip, nk - nskip, nskip): # 2次微分 d^2E/dk^2 の計算 (中心差分法) # 物理量に変換するため電荷eを掛ける d2Edk2c = (E[i+nskip] + E[i-nskip] - 2 * E[i]) * e / pow(nskip * dk, 2.0) minv = d2Edk2c / km # 逆有効質量 print(i, E[i-1], E[i], E[i+1], minv) # 逆有効質量が極端に小さい場合 (有効質量が極端に大きい場合) は、プロットを切断する if abs(minv) <= 1.0e20: # << 1.0/me ~ 1e30 if cutline: xk.append(k[i]) ymc.append(None) # Noneを挿入してプロットを分断 signprev = -signprev # 符号反転を強制 continue else: m = km / d2Edk2c # 有効質量を計算 # 有効質量の符号が反転した場合もプロットを切断する if signprev is None: signprev = m elif signprev * m < 0.0: if cutline: xk.append(k[i]) ymc.append(None) # Noneを挿入してプロットを分断 signprev = m xk.append(k[i]) ymc.append(m / me) # 自由電子質量で規格化して追加 nskip = 4 xk2 = [] ymc2 = [] signprev = None print("") print("Differentiate for nskip = ", nskip) print("i E[i-1] E[i] E[i+1] 1.0/m*") for i in range(nskip, nk - nskip, nskip): d2Edk2c = (E[i+nskip] + E[i-nskip] - 2 * E[i]) * e / pow(nskip * dk, 2.0) minv = d2Edk2c / km print(i, E[i-1], E[i], E[i+1], minv) if abs(minv) <= 1.0e20: # << 1.0/me ~ 1e30 if cutline: xk2.append(k[i]) ymc2.append(None) signprev = -signprev continue else: m = km / d2Edk2c if signprev is None: signprev = m elif signprev * m < 0.0: if cutline: xk2.append(k[i]) ymc2.append(None) signprev = m xk2.append(k[i]) ymc2.append(m / me) # 結果のプロット plt.plot(xk, ymc, linewidth = 0.5, marker = 'o', markersize = 1.0, label = 'nskip = 1') plt.plot(xk2, ymc2, linewidth = 0.5, marker = 'o', markersize = 1.0, label = 'nskip = 2') # ラベルが"nskip = 2"だが、コードではnskip=4で計算しているため注意 plt.xlabel(klabel) plt.ylabel("m$_e$ / m$_e^0$") plt.xlim([-0.5, 0.5]) # plt.ylim([-0.5, 0.5]) plt.tight_layout() plt.legend(fontsize=legend_fontsize) # 凡例を表示 plt.pause(0.1) print("Press ENTER to exit>>", end = '') input()
if __name__ == "__main__": main()