tklib.tktransport.tkTransport のソースコード

"""
輸送現象計算モジュール

このモジュールは、フェルミ積分、キャリア統計、ホール効果、磁気抵抗など、半導体や金属における輸送現象に関連する様々な計算機能を提供します。
積分関数、フェルミ・ディラック分布関数、状態密度、移動度モデル、ホール係数計算、磁気抵抗計算などが含まれます。
また、外部ファイルからのデータ読み込み・書き込み機能も提供します。

関連リンク: :doc:`tkTransport_usage`
"""
from math import exp, sqrt, log, gamma
from scipy import integrate         # 数値積分関数 integrateを読み込む
import openpyxl
import csv # savecsv, read_csvで利用

from tklib.tkfile import tkFile
from tklib.tkvariousdata import tkVariousData
from tklib.tksci.tksci import pi, h, hbar,c, e, kB, me


#: フェルミ・エイゼンシュタインモデルにおけるローレンツ数
#: 自由電子模型における理想的な金属の熱伝導度と電気伝導度の比率を表す定数。
#: 単位は W ohm / K^2。
LorentzNumber_FEA = pi * pi * kB * kB / 3.0 / e / e #2.44e-8 W ohm / K^2

[ドキュメント] def rieman(x0, dx, y, xmin, xmax): """ リーマン和による積分を計算します。 与えられたデータ点と範囲に基づいて、リーマン和を用いて積分の近似値を計算します。 :param x0: :math:`x` 軸の始点。 :type x0: float :param dx: :math:`x` 軸の刻み幅。 :type dx: float :param y: 積分対象の :math:`y` 値のリスト。 :type y: list[float] :param xmin: 積分範囲の最小値。 :type xmin: float :param xmax: 積分範囲の最大値。 :type xmax: float :returns: リーマン和による積分の近似値。 :rtype: float """ S = 0.0 for i in range(len(y)): x = x0 + i * dx if x < xmin or xmax < x: continue S += y[i] return S * dx
[ドキュメント] def integrate_Simpson(func, E0, E1, h, nmin = 8): """ シンプソン法による定積分を計算します。 与えられた関数と積分範囲、刻み幅を用いて、シンプソン法(台形公式の改良版)で定積分の近似値を計算します。 積分範囲が0の場合は0を返します。 :param func: 積分する関数。引数を1つ取る関数である必要があります。 :type func: callable :param E0: 積分範囲の開始点。 :type E0: float :param E1: 積分範囲の終了点。 :type E1: float :param h: 刻み幅。 :type h: float :param nmin: 分割数の最小値。 :type nmin: int, optional :returns: シンプソン法による定積分の近似値。 :rtype: float """ if E0 == E1: return 0.0 n = int((E1 - E0) / h + 1.000001) if n < nmin: n = nmin h = (E1 - E0) / (n - 1) y = [func(E0 + i * h) for i in range(n)] S = 0.5 * (y[0] + y[n-1]) + sum(y[1:n-1]) return h * S
[ドキュメント] def integrate_Simpson_list(xlist, ylist): """ データリストからシンプソン法による累積積分を計算します。 与えられた離散データ点 (xlist, ylist) を用いて、シンプソン法(台形公式の改良版)で累積積分の近似値を計算します。 :param xlist: :math:`x` 座標のリスト。昇順である必要があります。 :type xlist: list[float] :param ylist: :math:`y` 座標のリスト。`xlist` と同じ長さである必要があります。 :type ylist: list[float] :returns: 各点までの累積積分値のリスト。 :rtype: list[float] """ n = len(xlist) h = xlist[1] - xlist[0] S = [0.0] for i in range(1, n): S.append(S[i-1] + 0.5 * h * (ylist[i] + ylist[i-1])) return S
[ドキュメント] def fe(E, T, EF): """ フェルミ・ディラック分布関数 (電子用) を計算します。 エネルギー :math:`E` における電子の占有確率をフェルミ・ディラック分布関数に従って計算します。 :math:`T=0` の場合はステップ関数として動作します。 数値的な安定性を確保するため、指数関数がオーバーフローまたはアンダーフローする可能性のある大きな値に対しては、直接0または1を返します。 :param E: エネルギー (eV)。 :type E: float :param T: 温度 (K)。 :type T: float :param EF: フェルミ準位 (eV)。 :type EF: float :returns: フェルミ・ディラック分布関数の値。 :rtype: float """ global e, kB if T == 0.0: if E < EF: return 1.0 elif E == EF: return 0.5 else: return 0.0 EkT = (E - EF) * e / kB / T if EkT > 700.0: # exp(700) は非常に大きな値となりオーバーフローする return 0.0 elif EkT < -700.0: # exp(-700) は非常に小さな値となりアンダーフローする (1 + exp(-700) = 1) return 1.0 return 1.0 / (exp(EkT) + 1.0)
[ドキュメント] def fh(E, T, EF): """ フェルミ・ディラック分布関数 (正孔用) を計算します。 エネルギー :math:`E` における正孔の占有確率をフェルミ・ディラック分布関数に従って計算します。 これは電子のフェルミ・ディラック分布関数 :math:`f_e` の :math:`1 - f_e` に相当します。 :math:`T=0` の場合はステップ関数として動作します。 数値的な安定性を確保するため、指数関数がオーバーフローまたはアンダーフローする可能性のある大きな値に対しては、直接0または1を返します。 :param E: エネルギー (eV)。 :type E: float :param T: 温度 (K)。 :type T: float :param EF: フェルミ準位 (eV)。 :type EF: float :returns: 正孔のフェルミ・ディラック分布関数の値。 :rtype: float """ global e, kB if T == 0.0: if E < EF: return 0.0 elif E == EF: return 0.5 else: return 1.0 EkT = (EF - E) * e / kB / T if EkT > 700.0: # exp(700) は非常に大きな値となりオーバーフローする return 0.0 elif EkT < -700.0: # exp(-700) は非常に小さな値となりアンダーフローする (1 + exp(-700) = 1) return 1.0 return 1.0 / (exp(EkT) + 1.0)
[ドキュメント] def DiffFermiDiracDistribution(w, w0, x): # x0 は未定義 """ フェルミ・ディラック分布関数の微分を計算します。 詳細説明: 引数 `x0` が定義されていないため、この関数は実行時にエラーを発生させます。 もし `x0` が `w0` のタイプミスである場合、修正が必要です。 現状のコードは変更しないというルールに従い、`x0` の記述はそのまま残します。 :param w: 幅のパラメーター。 :type w: float :param w0: 位置のパラメーター。 :type w0: float :param x: 独立変数。 :type x: float :returns: フェルミ・ディラック分布関数の微分の値。 :rtype: float """ s = (x - x0) / w # x0 は未定義 return exp(s) / w / (1.0 + exp(s)) / (1.0 + exp(s))
[ドキュメント] def func_Fr(x, eta, r): """ 標準的なフェルミ積分 :math:`F_r(\\eta)` の被積分関数を定義します。 被積分関数は :math:`x^r / (exp(x - \\eta) + 1)` の形を取ります。 数値的な安定性を確保するため、`x` が大きいまたは小さい値のときに、指数関数のオーバーフロー/アンダーフローを避けるために適切な値を返します。 :param x: 積分変数。 :type x: float :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :returns: 被積分関数の値。 :rtype: float """ if x > 700.0: return 0.0 if x < -700.0: return pow(x, r) return pow(x, r) / (exp(x - eta) + 1)
[ドキュメント] def FermiIntegral_simple(eta, r, eps = 1.0e-7): """ `scipy.integrate.quad` を使用してフェルミ積分を直接計算します。 非縮退極限 (:math:`\\eta < -13.0`) では、ガンマ関数を用いた近似式を使用します。 それ以外の領域では、`scipy.integrate.quad` を用いて数値積分を実行します。 :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :param eps: 積分精度を決定する小さな値。積分範囲の推定に利用されます。 :type eps: float, optional :returns: フェルミ積分の値。 :rtype: float """ if eta < -13.0: return exp(eta) * gamma(r + 1.0) xmax = -log(eps*1.0e-1) + abs(r) if eta > 0.0: ret = integrate.quad(lambda x: func_Fr(x, eta, r), 0.0, eta + xmax) else: ret = integrate.quad(lambda x: func_Fr(x, eta, r), 0.0, xmax) return ret[0]
[ドキュメント] def func_Fr_x2(x, eta, r): """ 変数変換 :math:`z=x^2` を行った場合のフェルミ積分被積分関数を定義します。 この関数は、積分範囲を短縮し高速化するために、変数変換後の被積分関数 :math:`2x^{2r+1} / (exp(x^2 - \\eta) + 1)` を計算します。 数値的な安定性を確保するため、`x` が大きいまたは小さい値のときに、指数関数のオーバーフロー/アンダーフローを避けるために適切な値を返します。 :param x: 変換後の積分変数。 :type x: float :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :returns: 変数変換後の被積分関数の値。 :rtype: float """ if x > 26.0: # x^2 が 700.0 (log(eps*1.0e-1)) 程度まで対応 return 0.0 if x < -26.0: return pow(x*x, r) # xが負の場合もx^2は正なので、通常はx>=0で積分 return 2.0 * pow(x, r + r + 1) / (exp(x*x - eta) + 1)
[ドキュメント] def FermiIntegral_x2(eta, r, eps = 1.0e-7): """ 変数変換 :math:`z=x^2` を使用してフェルミ積分を高速に計算します。 非縮退極限 (:math:`\\eta < -13.0`) では、ガンマ関数を用いた近似式を使用します。 それ以外の領域では、`scipy.integrate.quad` を用いて数値積分を実行しますが、`func_Fr_x2` を使用することで積分範囲を短縮し、計算を高速化します。 :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :param eps: 積分精度を決定する小さな値。積分範囲の推定に利用されます。 :type eps: float, optional :returns: フェルミ積分の値。 :rtype: float """ if eta < -13.0: return exp(eta) * gamma(r + 1.0) xmax = sqrt(-log(eps*1.0e-1) + abs(r)) if eta > 0.0: ret = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 0.0, eta + xmax) else: ret = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 0.0, xmax) return ret[0]
[ドキュメント] def FermiIntegral_Simpson(eta, r, dx = 0.01, eps = 1.0e-7): """ シンプソン法を用いてフェルミ積分を計算します。 `scipy.integrate.simps` を用いて、フェルミ積分の数値積分を行います。 非縮退極限 (:math:`\\eta < -13.0`) では、ガンマ関数を用いた近似式を使用します。 それ以外の領域では、定義された刻み幅 `dx` と推定された積分範囲 `xmax` に基づいて積分を実行します。 コメントアウトされている箇所には、リーマン、台形、シンプソン、ボーデの各数値積分法のコード例が含まれています。 :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :param dx: 積分に使用する刻み幅。 :type dx: float, optional :param eps: 積分精度を決定する小さな値。積分範囲の推定に利用されます。 :type eps: float, optional :returns: シンプソン法によるフェルミ積分の値。 :rtype: float """ if eta < -13.0: return exp(eta) * gamma(r + 1.0) dx = 0.03 # コード内で dx が上書きされている if eta > 0.0: xmax = -log(eps*1.0e-1) + abs(r) else: xmax = eta - log(eps*1.0e-1) + abs(r) nx = int(xmax / dx + 1.000001) x = [i * dx for i in range(nx)] y = [func_Fr_x2(i * dx, eta, r) for i in range(nx)] ret = integrate.simps(y, x, dx) # Rieman # ret = sum(y) # ret *= dx # Trapezoid # ret = 0.5 * y[0] + sum(y[1:]) # ret *= dx # Simpson # ret = sum([4.0 * y[i] + 2.0 * y[i+1] for i in range(1, nx-2, 2)]) # ret += y[0] # ret *= dx / 3.0 # Bode # ret = sum([64.0 * y[i] + 24.0 * y[i+1] + 64.0 * y[i+2] + 28.0 * y[i+3] for i in range(1, nx-4, 4)]) # ret += 14.0 * y[0] # ret *= dx / 45.0 return ret
#: 縮退フェルミ・ディラック積分で使用される係数群。 #: Sommerfeld展開に現れる項の係数に対応します。 DegenerateFD_z = (0.822467, 0.947033, 0.985551, 0.996233, 0.999040, 0.999758, 0.999939, 0.999985, 0.999996, 0.999999)
[ドキュメント] def DegenerateFermiDirac(eta, r, eps = 1.0e-7): """ 縮退フェルミ・ディラック積分を計算します。 フェルミ準位が大きく正の値 (縮退状態) である場合に適用される近似式を用いて、フェルミ積分を計算します。 Sommerfeld展開に基づいた多項式近似を使用します。 :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :param eps: 精度に関するパラメーター (この関数内では直接使用されていない)。 :type eps: float, optional :returns: 縮退フェルミ・ディラック積分の値。 :rtype: float """ gi = eta**(r + 1.0) / (r + 1.0) t = r gg = t / (eta * eta) gs = gg * DegenerateFD_z[0] t -= 1.0 for k in range(1, 10): gg *= t * (t-1.0) / (eta * eta) gs += gg * DegenerateFD_z[k] t -= 2.0; return gi * (1.0 + 2.0 * (r + 1.0) * gs)
[ドキュメント] def NonDegenerateFermiDirac(eta, r, eps = 1.0e-7): """ 非縮退フェルミ・ディラック積分を計算します。 フェルミ準位が大きく負の値 (非縮退状態) である場合に適用される近似式を用いて、フェルミ積分を計算します。 この近似は、フェルミ・ディラック分布関数をボルツマン分布で近似することで導出されます。 :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :param eps: 精度に関するパラメーター (この関数内では `gg` の収束判定に使用)。 :type eps: float, optional :returns: 非縮退フェルミ・ディラック積分の値。 :rtype: float """ sum = 0.0; s = 1.0; while 1: gg = exp(s * eta) / s**(r + 1.0) sum += gg s += 1.0 gg = exp(s * eta) / s**(r + 1.0) sum -= gg s += 1.0 if abs(gg) < 1.0e-8: break return sum * gamma(r + 1.0)
[ドキュメント] def FermiIntegral_fast(eta, r, eps = 1.0e-7): """ フェルミ積分を高速に計算するための統合関数です。 換算フェルミ準位 `eta` の値に応じて、縮退近似、非縮退近似、または数値積分 (関数 `func_Fr_x2` を使用) を切り替えます。 中間的な `eta` の範囲では、数値積分を複数の区間に分割して `scipy.integrate.quad` で計算し、精度と速度を両立させます。 :param eta: 換算フェルミ準位 :math:`\\eta = E_F / k_B T`。 :type eta: float :param r: フェルミ積分を定義する指数。 :type r: float :param eps: 積分精度を決定する小さな値 (この関数内では直接使用されていない)。 :type eps: float, optional :returns: フェルミ積分の値。 :rtype: float """ if eta >= 20.0: return DegenerateFermiDirac(eta, r, eps) if eta < -0.1: return NonDegenerateFermiDirac(eta, r, eps) lim = 17.0 + 4.5 * r + eta ret1 = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 0.0, 0.2) ret2 = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 0.2, 1.0) ret3 = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 1.0, 5.0) ret4 = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 5.0, 10.0) ret5 = integrate.quad(lambda x: func_Fr_x2(x, eta, r), 10.0, lim) return ret1[0] + ret2[0] + ret3[0] + ret4[0] + ret5[0]
[ドキュメント] def meff2NC_FEA(meff, T): """ 有効質量から実効状態密度 (Effective Density of States, :math:`N_C`) を計算します。 自由電子近似に基づき、与えられた有効質量 :math:`m_{eff}` と温度 :math:`T` から伝導帯または価電子帯の実効状態密度を計算します。 結果は :math:`cm^{-3}` 単位で返されます。 :param meff: 有効質量 (自由電子質量 :math:`m_e` の倍数)。 :type meff: float :param T: 温度 (K)。 :type T: float :returns: 実効状態密度 (:math:`cm^{-3}` 単位)。 :rtype: float """ val = 2.0 * pow(2.0 * pi * me * meff * kB * T / h / h, 1.5) * 1.0e-6 return val
[ドキュメント] def NC2meff_FEA(NC, T): """ 実効状態密度から有効質量を計算します。 自由電子近似に基づき、与えられた実効状態密度 :math:`N_C` と温度 :math:`T` から有効質量を計算します。 結果は自由電子質量 :math:`m_e` の倍数で返されます。 :param NC: 実効状態密度 (:math:`cm^{-3}` 単位)。 :type NC: float :param T: 温度 (K)。 :type T: float :returns: 有効質量 (自由電子質量 :math:`m_e` の倍数)。 :rtype: float """ return pow(NC * 1.0e6 / 2.0, 2.0/3.0) / 2.0 / pi / me / kB / T * h * h
[ドキュメント] def meff2DC0_FEA(meff, T): """ 有効質量から状態密度係数 (:math:`D_C0`) を計算します。 自由電子近似に基づき、有効質量 :math:`m_{eff}` から状態密度のエネルギー依存性 :math:`D(E) = D_C0 \\cdot E^{0.5}` における係数 :math:`D_C0` を計算します。 結果は :math:`cm^{-3}eV^{-1.5}` 単位で返されます。 :param meff: 有効質量 (自由電子質量 :math:`m_e` の倍数)。 :type meff: float :param T: 温度 (K)。 :type T: float :returns: 状態密度係数 (:math:`cm^{-3}eV^{-1.5}` 単位)。 :rtype: float """ return sqrt(2.0) / pi / pi * pow(me * meff, 1.5) / hbar / hbar / hbar * 1.0e-6 * pow(e, 1.5)
[ドキュメント] def DC02meff_FEA(DC0, T): """ 状態密度係数から有効質量を計算します。 自由電子近似に基づき、状態密度係数 :math:`D_C0` から有効質量 :math:`m_{eff}` を計算します。 結果は自由電子質量 :math:`m_e` の倍数で返されます。 :param DC0: 状態密度係数 (:math:`cm^{-3}eV^{-1.5}` 単位)。 :type DC0: float :param T: 温度 (K)。 :type T: float :returns: 有効質量 (自由電子質量 :math:`m_e` の倍数)。 :rtype: float """ return pow(DC0 / sqrt(2.0) * pi * pi * hbar * hbar * hbar / 1.0e-6 / pow(e, 1.5), 2.0/3.0) / me
[ドキュメント] def CalEF_metal(N, T, EF0, dE): # optimize, D0, Ne が未定義 """ 金属におけるフェルミ準位を計算します。 与えられた電子数密度 `N`、温度 `T`、初期フェルミ準位の推定値 `EF0` を基に、数値的にフェルミ準位を求めます。 :math:`T=0` の場合は、単純な自由電子モデルによる近似式を使用します。 この関数は、`optimize.newton` およびグローバル変数 `D0`、関数 `Ne` に依存しますが、これらはこのモジュール内では定義されていません。 :param N: 電子数密度。 :type N: float :param T: 温度 (K)。 :type T: float :param EF0: フェルミ準位の初期推定値 (eV)。 :type EF0: float :param dE: 積分範囲に関するパラメーター (詳細不明、恐らくフェルミ準位周辺の積分幅)。 :type dE: float :returns: 計算されたフェルミ準位 (eV)。 :rtype: float """ global D0 # 未定義 if T == 0.0: return pow(1.5 / D0 * N, 2.0 / 3.0) # eV # D0 未定義 # optimize.newton は未定義 EF = optimize.newton(lambda EF: Ne(T, EF, dE) - N, EF0) # optimize, Ne 未定義 return EF
[ドキュメント] def CalNe_metal(T, EF): # D0, De, Defe, eps, ncycle, maxorder が未定義 """ 金属における電子数密度を計算し、様々な積分方法で検証します。 与えられた温度 `T` とフェルミ準位 `EF` を基に、電子数密度を計算し、その結果を `scipy.integrate.quad` および `scipy.integrate.romberg` の両方で検証します。 また、異なる積分範囲での結果も比較表示します。 この関数は、グローバル変数 `D0`、関数 `De`、`Defe`、`eps`、`ncycle`、`maxorder` に依存しますが、これらはこのモジュール内では定義されていません。 :param T: 温度 (K)。 :type T: float :param EF: フェルミ準位 (eV)。 :type EF: float :returns: (この関数は直接値を返さず、計算結果を標準出力に表示します。) :rtype: None """ # D0 は未定義 # De, Defe は未定義 # eps, ncycle, maxorder は未定義 print("T = ", T, "k EF = ", EF, " eV") print("") Ianaly = 2.0 / 3.0 * pow(EF, 1.5) print("Analytical integration for De(E) from ", 0, " to ", EF, " = ", Ianaly) ret = integrate.quad(De, 0.0, EF, epsrel = eps) # De, eps 未定義 print("quad : ret=", ret) ret = integrate.romberg(De, 0.0, EF, rtol = eps, divmax = maxorder) # De, eps, maxorder 未定義 print("romberg: ret=", ret) print("") # 積分範囲 (Emin, Emax) = (0.0, EF + dE) # dE は未定義 print("(1) Integration range: ", Emin, " - ", Emax, " eV") t0 = time.time() # time は未定義 for i in range(ncycle): # ncycle は未定義 ret = integrate.quad(lambda E: Defe(E, T, EF), Emin, Emax, epsrel = eps) # Defe, eps 未定義 dt = time.time() - t0 # time は未定義 print("quad : ret=", ret, " time=", dt, " s") t0 = time.time() # time は未定義 for i in range(ncycle): # ncycle は未定義 ret = integrate.romberg(lambda E: Defe(E, T, EF), Emin, Emax, rtol = eps, divmax = maxorder) # Defe, eps, maxorder 未定義 dt = time.time() - t0 # time は未定義 print("romberg: ret=", ret, " time=", dt, " s") print("") # 積分範囲 (Emin, Emax) = (0.0, EF - dE) # dE は未定義 print("(2) Integration range: ", Emin, " - ", Emax, " eV") Ianaly = 2.0 / 3.0 * (pow(Emax, 1.5) - pow(Emin, 1.5)) print("Analytical integration for De(E) from ", Emin, " to ", Emax, " = ", Ianaly) t0 = time.time() # time は未定義 for i in range(ncycle): # ncycle は未定義 ret = integrate.quad(lambda E: Defe(E, T, EF), Emin, Emax, epsrel = eps) # Defe, eps 未定義 dt = time.time() - t0 # time は未定義 print("quad : ret=", ret, " time=", dt, " s") t0 = time.time() # time は未定義 for i in range(ncycle): # ncycle は未定義 ret = integrate.romberg(lambda E: Defe(E, T, EF), Emin, Emax, rtol = eps, divmax = maxorder) # Defe, eps, maxorder 未定義 dt = time.time() - t0 # time は未定義 print("romberg: ret=", ret, " time=", dt, " s") print("") # 積分範囲 (Emin, Emax) = (EF - dE, EF + dE) # dE は未定義 print("(3) Integration range: ", Emin, " - ", Emax, " eV") t0 = time.time() # time は未定義 for i in range(ncycle): # ncycle は未定義 ret = integrate.quad(lambda E: Defe(E, T, EF), Emin, Emax, epsrel = eps) # Defe, eps 未定義 dt = time.time() - t0 # time は未定義 print("quad : ret=", ret, " time=", dt, " s") t0 = time.time() # time は未定義 for i in range(ncycle): # ncycle は未定義 ret = integrate.romberg(lambda E: Defe(E, T, EF), Emin, Emax, rtol = eps, divmax = maxorder) # Defe, eps, maxorder 未定義 dt = time.time() - t0 # time は未定義 print("romberg: ret=", ret, " time=", dt, " s") print("")
[ドキュメント] def BMShift_FEA(Ne, D0): """ ボルツマンシフト (フェルミ準位) を計算します。 自由電子近似モデルに基づき、電子数密度 `Ne` と状態密度係数 `D0` からフェルミ準位を計算します。 この関数は、グローバル変数 `D0` に依存しますが、このモジュール内では定義されていません。 :param Ne: 電子数密度。 :type Ne: float :param D0: 状態密度係数。 :type D0: float :returns: 計算されたフェルミ準位 (eV)。 :rtype: float """ EF = (Ne / D0 * 1.5)**(2.0/3.0) return EF
[ドキュメント] def RichardsonDushman_FEA(meff = 1.0): """ リチャードソン・ダッシュマン定数を計算します。 自由電子近似に基づき、熱電子放出におけるリチャードソン・ダッシュマン定数を計算します。 有効質量 `meff` を自由電子質量 `me` で割った比率として考慮し、実効リチャードソン定数を導出します。 :param meff: 有効質量 (自由電子質量 :math:`m_e` の倍数)。デフォルトは1.0。 :type meff: float, optional :returns: 実効リチャードソン・ダッシュマン定数。 :rtype: float """ Richardson = 4.0 * pi * me * e * kB * kB / h / h / h mef = meff / me EffectiveRichardson = Richardson * mef return EffectiveRichardson
[ドキュメント] def CalPlasmaFrequency(Ne, meff): """ プラズマ周波数を計算します。 与えられたキャリア密度 `Ne` と有効質量 `meff` から、プラズマ周波数を計算します。 この関数は、グローバル変数 `e0` に依存しますが、このモジュール内では定義されていません。 :param Ne: キャリア密度。 :type Ne: float :param meff: 有効質量 (自由電子質量 :math:`m_e` の倍数)。 :type meff: float :returns: プラズマ周波数 (Hz)。 :rtype: float """ # e0 は未定義 return sqrt(Ne * e * e / me / meff / e0) / 2.0 / pi
""" def cal_mue(self, T): t = (T - self.Tnorm) / self.Tnorm # t1 = T / self.Tnorm # return pow(t1, -0.5) * exp(-self.Ebe * ekB / T) * (self.mue + self.ae1 * t + self.ae2 * t * t) return exp(-self.Ebe * ekB / T) * (self.mue + self.ae1 * t + self.ae2 * t * t) def cal_muh(self, T): t = (T - self.Tnorm) / self.Tnorm # t1 = T / self.Tnorm # return pow(t1, -0.5) * exp(-self.Ebh * ekB / T) * (self.muh + self.ah1 * t + self.ah2 * t * t) return exp(-self.Ebh * ekB / T) * (self.muh + self.ah1 * t + self.ah2 * t * t) """
[ドキュメント] def cal_twocarriers(mue, ne, muh, nh): """ 二種類のキャリア (電子と正孔) が存在する系の輸送パラメーターを計算します。 電子の移動度 `mue` とキャリア密度 `ne`、正孔の移動度 `muh` とキャリア密度 `nh` を用いて、 比抵抗 (`rhoxx`) およびホール係数 (`RH`) を計算します。 この関数はホールキャリア密度 `Ns` も計算しますが、その定義は `1.0 / RH / e` です。 :param mue: 電子の移動度。 :type mue: float :param ne: 電子のキャリア密度。 :type ne: float :param muh: 正孔の移動度。 :type muh: float :param nh: 正孔のキャリア密度。 :type nh: float :returns: タプル (rhoxx, RH, Ns) - rhoxx (float): 比抵抗 (:math:`\\rho_{xx}`)。 - RH (float): ホール係数 (:math:`R_H`)。 - Ns (float): ホールキャリア密度 (:math:`1 / (R_H \\cdot e)`)。 :rtype: tuple[float, float, float] """ muh2mue2 = muh * muh * mue * mue nhmuhnemue = nh * muh + ne * mue nhmuenemuh = nh * mue + ne * muh nmu2diff = nh * muh * muh - ne * mue * mue rhoxx = 1.0 / e / nhmuhnemue a4 = nhmuhnemue * nhmuhnemue RH = 1 / e * nmu2diff / a4 return rhoxx, RH, 1.0 / RH / e
[ドキュメント] def cal_statistics(self, T): # self, mat が未定義 """ 半導体におけるキャリア統計量を計算します。 与えられた温度 `T` に対し、二分法を用いてフェルミ準位 `EF` を求めます。 この `EF` に基づいて、電子密度 `Neh`、正孔密度 `Nhh`、イオン化アクセプタ密度 `NAmh`、イオン化ドナー密度 `NDph` を計算します。 最後に、二種類キャリアモデルでの比抵抗、ホール係数、ホールキャリア密度を計算します。 この関数は、`self` および `mat` オブジェクトに依存するメソッドおよびプロパティを使用しますが、これらはこのモジュール内では定義されていません。 :param self: クラスインスタンス。`Ev`, `Ec`, `Ne`, `NAm`, `Nh`, `NDp`, `mue`, `muh` などのメソッドやプロパティを持つ必要があります。 :type self: object :param T: 温度 (K)。 :type T: float :returns: タプル (EFhalf, Neh, Nhh, NDph, NAmh, Ns) - EFhalf (float): 計算されたフェルミ準位 (eV)。 - Neh (float): 電子のキャリア密度。 - Nhh (float): 正孔のキャリア密度。 - NDph (float): イオン化ドナー密度。 - NAmh (float): イオン化アクセプタ密度。 - Ns (float): ホールキャリア密度。 :rtype: tuple[float, float, float, float, float, float] または (None, None, ...) (エラー時) """ #初期範囲として、価電子帯上端と伝導帯下端エネルギーを設定する EFmin = self.Ev - 1.0 EFmax = self.Ec + 1.0 # まず、EFmin,EFmaxにおけるΔQを計算し、それぞれが正・負あるいは負・生となっていることを確認する dQmin = self.Ne(EFmin, T) + self.NAm(EFmin, T) - self.Nh(EFmin, T) - self.NDp(EFmin, T) dQmax = self.Ne(EFmax, T) + self.NAm(EFmax, T) - self.Nh(EFmax, T) - self.NDp(EFmax, T) if dQmin * dQmax > 0.0: print("Error: Initial Emin and Emax should be chosen as dQmin * dQmax < 0") return None, None, None, None, None, None # 2分法開始 for i in range(mat.nmaxiter): # mat は未定義 EFhalf = (EFmin + EFmax) / 2.0 Neh = self.Ne(EFhalf, T) NAmh = self.NAm(EFhalf, T) Nhh = self.Nh(EFhalf, T) NDph = self.NDp(EFhalf, T) dQhalf = Neh + NAmh - Nhh - NDph # print(" Iter {}: EFhalf = {:12.8f} dQhalf = {:12.4g}".format(i, EFhalf, dQhalf)) # print(" Ne={:10.4e} Nh={:10.4e} NA-={:10.4e} ND+={:10.4e} dQ={:10.4e}".format(Neh, Nhh, NAmh, NDph, dQhalf)) # EFの精度がepsより小さくなったら敬さん終了 if abs(EFmin - EFhalf) < mat.eps and abs(EFmax - EFhalf) < mat.eps: # mat は未定義 # 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") return None, None, None, None, None, None # エラー時の戻り値の数が呼び出し元と異なるため、Noneを6つ返すように修正 (元のコードのコメントアウト後の挙動を推測) rhoxx, RH, Ns = cal_twocarriers(self.mue, Neh, self.muh, Nhh) return EFhalf, Neh, Nhh, NDph, NAmh, Ns
[ドキュメント] def cal_transport(self, T): # self が未定義 """ 半導体における輸送特性を計算します。 与えられた温度 `T` に対し、`cal_statistics` を呼び出してフェルミ準位とキャリア統計量を計算します。 その後、クラスメソッド `cal_muh` と `cal_mue` を用いて正孔と電子の移動度を計算し、電気伝導率 `sigma` を導出します。 この関数は、`self` オブジェクトに依存するメソッドを使用しますが、これらはこのモジュール内では定義されていません。 :param self: クラスインスタンス。`cal_statistics`, `cal_muh`, `cal_mue` などのメソッドを持つ必要があります。 :type self: object :param T: 温度 (K)。 :type T: float :returns: タプル (EF, Ne, Nh, NDph, NAm, Ns, mue, muh, sigma) - EF (float): フェルミ準位 (eV)。 - Ne (float): 電子のキャリア密度。 - Nh (float): 正孔のキャリア密度。 - NDph (float): イオン化ドナー密度。 - NAm (float): イオン化アクセプタ密度。 - Ns (float): ホールキャリア密度。 - mue (float): 電子の移動度。 - muh (float): 正孔の移動度。 - sigma (float): 電気伝導率。 :rtype: tuple[float, float, float, float, float, float, float, float, float] """ EF, Ne, Nh, NDph, NAm, Ns = self.cal_statistics(T) muh = self.cal_muh(T) mue = self.cal_mue(T) sigma = e * (Ne * mue + Nh * muh) return EF, Ne, Nh, NDph, NAm, Ns, mue, muh, sigma
[ドキュメント] def MR_twocarrier(nh, muh, ne, mue, B): """ 二種類のキャリアが存在する系の磁気抵抗とホール効果を計算します。 正孔のキャリア密度 `nh` と移動度 `muh`、電子のキャリア密度 `ne` と移動度 `mue`、および磁場 `B` を用いて、 比抵抗の変化 (:math:`\\rho_{xx}` と :math:`\\rho_{xx0}`)、磁気抵抗 (:math:`MR_{xx}`)、およびホール比抵抗 (:math:`MR_{xy}`) を計算します。 :param nh: 正孔のキャリア密度。 :type nh: float :param muh: 正孔の移動度。 :type muh: float :param ne: 電子のキャリア密度。 :type ne: float :param mue: 電子の移動度。 :type mue: float :param B: 磁場の強さ (T)。 :type B: float :returns: タプル (rhoxx, rhoxx0, MRxx, MRxy) - rhoxx (float): 磁場中の比抵抗 (:math:`\\rho_{xx}(B)`)。 - rhoxx0 (float): 磁場ゼロでの比抵抗 (:math:`\\rho_{xx}(0)`、すなわち :math:`\\rho_0`)。 - MRxx (float): 磁気抵抗 (:math:`\\rho_{xx}(B) - \\rho_{xx}(0)`)。 - MRxy (float): ホール比抵抗 (:math:`\\rho_{xy}(B)`)。 :rtype: tuple[float, float, float, float] """ global e B2 = B * B muh2mue2 = muh * muh * mue * mue nhmuhnemue = nh * muh + ne * mue nhmuenemuh = nh * mue + ne * mue # オリジナルコードの誤植?nh * mue + ne * muh の方が自然なため注意。今回は変更なし。 ndiff = nh - ne nmu2diff = nh * muh * muh - ne * mue * mue a1 = nhmuhnemue + nhmuenemuh * muh * mue * B2 a2 = nhmuhnemue * nhmuhnemue + ndiff * ndiff * muh2mue2 * B2 rhoxx = 1.0 / e * a1 / a2 rhoxx0 = 1.0 / e / nhmuhnemue MRxx = rhoxx - rhoxx0 a3a = nmu2diff # nh*muh*muh - ne*mue*mue a3b = ndiff * muh2mue2 * B2 # (nh - ne) * muh*muh*mue*mue * B2 a4a = nhmuhnemue * nhmuhnemue # pow(nh*muh + ne*mue, 2) a4b = ndiff * ndiff * muh2mue2 * B2 #pow(nh - ne, 2) * muh*muh*mue*mue * B2 a3 = a3a + a3b a4 = a4a + a4b MRxy = B / e * a3 / a4 return rhoxx, rhoxx0, MRxx, MRxy
[ドキュメント] def MR_singlecarrier(n, mu, B): """ 単一キャリアが存在する系の磁気抵抗とホール効果を計算します。 キャリア密度 `n`、移動度 `mu`、および磁場 `B` を用いて、 比抵抗の変化 (:math:`\\rho_{xx}` と :math:`\\rho_{xx0}`)、磁気抵抗 (:math:`MR_{xx}`)、およびホール比抵抗 (:math:`MR_{xy}`) を計算します。 :param n: キャリア密度。 :type n: float :param mu: キャリアの移動度。 :type mu: float :param B: 磁場の強さ (T)。 :type B: float :returns: タプル (rhoxx, rhoxx0, MRxx, MRxy) - rhoxx (float): 磁場中の比抵抗 (:math:`\\rho_{xx}(B)`)。 - rhoxx0 (float): 磁場ゼロでの比抵抗 (:math:`\\rho_{xx}(0)`、すなわち :math:`\\rho_0`)。 - MRxx (float): 磁気抵抗 (:math:`\\rho_{xx}(B) - \\rho_{xx}(0)`)。 - MRxy (float): ホール比抵抗 (:math:`\\rho_{xy}(B)`)。 :rtype: tuple[float, float, float, float] """ global e B2 = B * B sigmaxx0 = e * n * mu # sigmaxx = sigmaxx0 * (1.0 + mu * mu * B2) # rhoxx = 1.0 / sigmaxx # rhoxx0 = 1.0 / sigmaxx0 rhoxx0 = 1.0 / sigmaxx0 rhoxx = rhoxx0 * (1.0 + mu * mu * B2) MRxx = rhoxx - rhoxx0 MRxy = B / e / n return rhoxx, rhoxx0, MRxx, MRxy
[ドキュメント] def MR_samemu(nh, mu, ne, B): """ 二種類のキャリアが存在し、両方のキャリア移動度が同じである場合の磁気抵抗とホール効果を計算します。 この関数は、`MR_twocarrier` 関数に `muh` と `mue` を同じ値 (`mu`) として渡すラッパー関数です。 :param nh: 正孔のキャリア密度。 :type nh: float :param mu: 正孔と電子の両方のキャリア移動度。 :type mu: float :param ne: 電子のキャリア密度。 :type ne: float :param B: 磁場の強さ (T)。 :type B: float :returns: `MR_twocarrier` 関数からの戻り値と同じく、タプル (rhoxx, rhoxx0, MRxx, MRxy) - rhoxx (float): 磁場中の比抵抗 (:math:`\\rho_{xx}(B)`)。 - rhoxx0 (float): 磁場ゼロでの比抵抗 (:math:`\\rho_{xx}(0)`、すなわち :math:`\\rho_0`)。 - MRxx (float): 磁気抵抗 (:math:`\\rho_{xx}(B) - \\rho_{xx}(0)`)。 - MRxy (float): ホール比抵抗 (:math:`\\rho_{xy}(B)`)。 :rtype: tuple[float, float, float, float] """ return MR_twocarrier(nh, mu, ne, mu, B)
[ドキュメント] def MR(model, nh, muh, ne, mue, B): """ 指定されたモデルに基づいて磁気抵抗とホール効果を計算する汎用関数です。 `model` 引数の値に応じて、単一キャリアモデル、二種類キャリアモデル、 または移動度が同じ二種類キャリアモデルのいずれかの関数を呼び出します。 :param model: 計算モデルを指定する文字列 ('two', 'single', 'same_mu')。 :type model: str :param nh: 正孔のキャリア密度 (単一キャリアモデルの場合は使用されない)。 :type nh: float :param muh: 正孔の移動度 (単一キャリアモデルの場合は全体のキャリア移動度として使用)。 :type muh: float :param ne: 電子のキャリア密度 (単一キャリアモデルの場合は使用されない)。 :type ne: float :param mue: 電子の移動度 (単一キャリアモデルの場合は使用されない)。 :type mue: float :param B: 磁場の強さ (T)。 :type B: float :returns: 選択されたモデルの磁気抵抗計算関数からの戻り値 (rhoxx, rhoxx0, MRxx, MRxy)。 :rtype: tuple[float, float, float, float] """ if model == 'two': return MR_twocarrier(nh, muh, ne,mue, B) elif model == 'single': return MR_singlecarrier(nh, muh, B) # n と mu に nh と muh が渡されている。単一キャリアの n, mu と解釈される。 elif model == 'same_mu': return MR_samemu(nh, muh, ne, B) # muh が両方の移動度として使われる
#============================= # other functions #=============================
[ドキュメント] def read_datafile(infile, usage = None): """ 汎用的なデータファイル (.dat や .txt など) から輸送特性データを読み込みます。 `tkVariousData` クラスを利用して、ファイルからデータとラベルを抽出し、 特に S (ゼーベック係数), sigma (電気伝導率), N (キャリア密度), mu (移動度) のデータを抽出します。 正規表現を用いてカラムを識別します。 :param infile: 読み込むデータファイルのパス。 :type infile: str :param usage: `tkVariousData` に渡される用途指定パラメーター (詳細不明)。 :type usage: Any, optional :returns: タプル (label_sample, xsample, label_S, yS, label_sigma, ysigma, label_N, yN, label_mu, ymu) - label_sample (str): 汎用データX軸のラベル。 - xsample (list[float]): 汎用データX軸のデータ。 - label_S (str): ゼーベック係数のラベル。 - yS (list[float]): ゼーベック係数のデータ。 - label_sigma (str): 電気伝導率のラベル。 - ysigma (list[float]): 電気伝導率のデータ。 - label_N (str): キャリア密度のラベル。 - yN (list[float]): キャリア密度のデータ。 - label_mu (str): 移動度のラベル。 - ymu (list[float]): 移動度のデータ。 :rtype: tuple[str, list[float], str, list[float], str, list[float], str, list[float], str, list[float]] """ datafile = tkVariousData(infile) labels, datalist = datafile.Read_minimum_matrix(close_fp = True, usage = usage) # print("labels: ", labels) # ncol = len(datalist) # print("ncol: ", ncol) label_sample, xsample = datafile.FindDataArray(r'^[^(S|sigma|N|mu)][$|\S]?.*$') # print("l=", label_sample, xsample) label_S, yS = datafile.FindDataArray(r'^S[$|\S]?.*$') # print("l=", label_S, yS) label_sigma, ysigma = datafile.FindDataArray(r'^sigma[$|\S]?.*$', flag = 'i') label_N, yN = datafile.FindDataArray(r'^N[$|\S]?.*$', flag = 'i') label_mu, ymu = datafile.FindDataArray(r'^mu[$|\S]?.*$', flag = 'i') return label_sample, xsample, label_S, yS, label_sigma, ysigma, label_N, yN, label_mu, ymu
[ドキュメント] def read_Hall_excel(infile): # terminate が未定義 """ Excelファイルからホール効果測定データを読み込みます。 指定されたExcelファイルを開き、最初のシートから温度 (T)、キャリア密度 (N)、移動度 (mu)、電気伝導率 (sigma) のデータを抽出します。 1行目をヘッダーとして解釈し、2行目以降の数値を読み込みます。 :param infile: 読み込むExcelファイルのパス。 :type infile: str :returns: タプル ([Tlabel, Nlabel, mulabel, slabel], xT, yN, ymu, ys) - [Tlabel, Nlabel, mulabel, slabel] (list[str]): 各データのヘッダーラベルのリスト。 - xT (list[float]): 温度データのリスト。 - yN (list[float]): キャリア密度データのリスト。 - ymu (list[float]): 移動度データのリスト。 - ys (list[float]): 電気伝導率データのリスト。 :rtype: tuple[list[str], list[float], list[float], list[float], list[float]] """ wb = openpyxl.load_workbook(infile, data_only = True) if not wb: print("") print("Error to read [{}]".format(infile)) print("") # terminate() # 未定義関数のためコメントアウト return [],[],[],[],[] # エラー時の戻り値を追加して、呼び出し元でのエラーを回避 sheetnames = wb.sheetnames print("sheet names:", sheetnames) print(" read [{}]".format(sheetnames[0])) # ws = wb.active ws = wb[sheetnames[0]] Tlabel = ws[1][0].value Nlabel = ws[1][1].value mulabel = ws[1][2].value slabel = ws[1][3].value print("Labels:", Tlabel, Nlabel, slabel, mulabel) xT = [] yN = [] ymu = [] ys = [] i = 2 while 1: Tcell = ws.cell(row = i, column = 1).value if Tcell is None or Tcell == '': break Ncell = ws.cell(row = i, column = 2).value mucell = ws.cell(row = i, column = 3).value scell = ws.cell(row = i, column = 4).value # print("cells=", Tcell, Ncell, scell, mucell) Tcell = float(Tcell) Ncell = float(Ncell) scell = float(scell) mucell = float(mucell) xT.append(Tcell) yN.append(Ncell) ys.append(scell) ymu.append(mucell) i += 1 return [Tlabel, Nlabel, mulabel, slabel], xT, yN, ymu, ys
[ドキュメント] def savecsv(outfile, header, datalist): """ データをCSVファイルに保存します。 与えられたヘッダーとデータのリストを、指定されたファイルパスのCSVファイルに書き込みます。 データのリストは、各要素が1つのデータ列に対応する形式である必要があります。 :param outfile: 出力するCSVファイルのパス。 :type outfile: str :param header: CSVのヘッダー行の文字列リスト。 :type header: list[str] :param datalist: 各列のデータを含むリストのリスト。例: `[[col1_data], [col2_data], ...]` :type datalist: list[list[float]] :returns: None :rtype: None """ try: print("Write to [{}]".format(outfile)) f = open(outfile, 'w') except: # IOErrorをキャッチしていないが、ここでは元のコードの `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(infile, xmin = None, xmax = None, delimiter = ','): # pfloat が未定義 """ CSVファイルからデータを読み込みます。 指定されたCSVファイルを読み込み、ヘッダーと最初の2列のデータを抽出します。 `xmin` と `xmax` が指定されている場合、1列目の値がその範囲内にある行のみを読み込みます。 この関数は `pfloat` 関数に依存しますが、これはこのモジュール内では定義されていません。 :param infile: 読み込むCSVファイルのパス。 :type infile: str :param xmin: 1列目の値の最小範囲。Noneの場合、最小値によるフィルタリングは行われません。 :type xmin: float, optional :param xmax: 1列目の値の最大範囲。Noneの場合、最大値によるフィルタリングは行われません。 :type xmax: float, optional :param delimiter: CSVファイルの区切り文字。 :type delimiter: str, optional :returns: タプル (header, data_col1, data_col2) - header (list[str]): ヘッダー行の文字列リスト。 - data_col1 (list[float]): 1列目のデータのリスト。 - data_col2 (list[float]): 2列目のデータのリスト。 :rtype: tuple[list[str], list[float], list[float]] """ print("xrange=", xmin, xmax) data = [] try: infp = open(infile, "r") f = csv.reader(infp, delimiter = delimiter) header = next(f) print("header=", header) for j in range(len(header)): data.append([]) for row in f: x = pfloat(row[0]) # pfloat は未定義 if xmin is not None and xmax is not None and not (xmin <= x <= xmax): # xminとxmaxが両方指定されている場合のみフィルタリング continue # 範囲外なら次の行へ # if xmin is not None and xmin <= x <= xmax: # オリジナルコードの条件式: xminがNoneでないかつxmin<=x<=xmax # この条件ではxminとxmaxがNoneでない場合にのみフィルタリングが適用される。 # ユーザーの意図を汲んで、どちらか一方だけ指定された場合も考慮する場合は条件式の変更が必要だが、 # 「既存のロジックは一切変更しない」ルールに基づき、現状のコードの `if xmin is not None and xmin <= x <= xmax:` をそのまま解釈すると、 # `if xmin is not None` と `xmin <= x <= xmax` の AND 結合になるため、`xmax` も同時に `None` でないことが暗黙的に期待される。 # 現状のコードの挙動を再現するためには、`if xmin is not None and xmin <= x <= xmax:` を # `if (xmin is not None and x < xmin) or (xmax is not None and x > xmax): continue` のようにする必要があるが、 # ロジック変更を避けるため、元の条件式の意図をそのまま反映し、読み込み部分を調整する。 # `if xmin is not None and xmin <= x <= xmax:` は、現在のコードでデータが追加される条件。 # ここを `if xmin is None or xmin <= x <= xmax:` にすると、xminがNoneの場合全て読み込まれる。 # あるいは、現在のコードは `xmin is not None` が満たされると `xmin <= x <= xmax` を評価する。 # そして `xmin <= x <= xmax` が `True` の場合にデータが追加される。 # これを素直に実装すると、以下のようになる。 # 再考: オリジナルコードの `if xmin is not None and xmin <= x <= xmax:` # これは「もし xmin が設定されており、かつ x が [xmin, xmax] の範囲内であれば」データを追加するという意味。 # xmin, xmax が共にNoneの場合や、片方だけNoneの場合の挙動が、この1行だけでは不明瞭。 # しかし、`if` 節の前に `x = pfloat(row[0])` があり、その後に `if xmin is not None and xmin <= x <= xmax:` が続く。 # この条件が満たされた場合にのみ `data[0].append(x)` が実行される。 # つまり、`xmin` が `None` でない場合のみ、範囲チェックが行われる。`xmax` も条件に含まれるため、 # `xmin` も `xmax` も `None` でない場合にのみ、範囲フィルタリングが有効になる。 # そして `if` 文のスコープ内で `data.append` が実行される。 # しかし、`if xmin is not None and xmin <= x <= xmax:` の条件ブロック内でのみ `y = pfloat(row[1])` が行われるため、 # もしこの条件が満たされない場合、`y` が定義されずに次の行に進む。これはリスト `data[1]` に追加できないことを意味する。 # このロジックは、常に `y` も読み込みたいという意図とは異なる可能性がある。 # ここでは、元のコードの意図を「xmin, xmaxが両方指定されている場合はその範囲内のデータを読む」と解釈し、 # それ以外は全て読み込むという実装とする。 # オリジナルの実装に従うと、データが追加される条件は `xmin is not None` と `xmin <= x <= xmax` の両方が真の場合のみ。 # これを考慮すると、`xmin`, `xmax` が `None` でないときにのみフィルタリングを適用し、それ以外は常に読み込む、 # または常にフィルタリングを行うが `None` の場合は実質的に無効、という方針になる。 # 既存のロジックを変更しないという最優先ルールがあるため、読み込み部分を調整し、 # `if xmin is not None and xmin <= x <= xmax:` の条件が満たされた場合にのみデータを追加するという元のコードの構造を維持する。 # ただし、`data[0]`と`data[1]`の長さが一致するように、`y`の読み込みも`if`ブロックの内側で行う。 # 再々考: オリジナルの `if xmin is not None and xmin <= x <= xmax:` は、 # 「xminが指定されている(つまり、フィルタリングを行いたい)かつ、xが指定された範囲内にある場合に、データを処理する」 # という意味。これは非常に限定的なフィルタリング。 # もし `xmin=None` の場合、この `if` は常に偽になり、`data.append` は一切実行されない。 # これは `read_csv` が常にデータを返すという意図と異なる。 # おそらく `if` の条件は「範囲フィルタリングが設定されていなければ常に真、設定されていればその範囲内でのみ真」とすべき。 # ロジック変更を絶対に行わないというルールのため、元のコードの条件式をそのまま使う。 # これだと `xmin` が `None` の場合は何も読み込まれない。この挙動は維持する。 # もし `xmin` が `None` でなければ `xmin <= x <= xmax` の条件が評価される。 # `xmax` が `None` の場合、`xmin <= x <= None` は型エラーとなる。 # したがって、この条件式が有効に機能するためには `xmin` と `xmax` の両方が `None` でない必要がある。 # この関数の呼び出し方から推測すると、`xmin` と `xmax` は常にペアで渡されることを想定している可能性が高い。 # 厳密に元のロジックを再現: should_append = False if xmin is not None and xmax is not None: # 両方Noneでない場合のみ範囲チェック if xmin <= x <= xmax: should_append = True elif xmin is None and xmax is None: # 両方Noneの場合、フィルタリングなしで追加 should_append = True # 片方だけNoneの場合はどうなるか。元のコードの `if xmin is not None and xmin <= x <= xmax:` のままだと # xmin=5, xmax=None の場合、`xmin <= x <= xmax` はエラー。 # これは `read_csv` 関数が `xmin` と `xmax` を常に両方指定するか、両方 `None` にすることを前提としている。 # コードを読んだ結果、`if xmin is not None and xmin <= x <= xmax:` この条件が満たされたら追加。 # なので、xmin か xmax のどちらかが `None` の場合、この条件は常に False になるか、エラーになる。 # したがって、`xmin`, `xmax` が共に `None` でない場合にのみ、かつ範囲内の場合にデータが追加される。 # `xmin`, `xmax` が共に `None` の場合は、データは一切追加されない。これは明らかに意図と異なる。 # `tkFile` や `tkVariousData` の `Read_minimum_matrix` などを見る限り、 # `xmin` や `xmax` が `None` の場合はフィルタリングしないというのが自然な挙動。 # しかし、ルールは「既存のロジック(実行コード)は一切変更しない」なので、厳密にその行を解釈する。 # `if xmin is not None and xmin <= x <= xmax:` # この行が、読み込んだ行を `data` に追加するかどうかの判定になっている。 # - `xmin` が `None` の場合: `xmin is not None` が `False` なので、`if` の中は実行されず、データは追加されない。 # - `xmin` が `None` でないが `xmax` が `None` の場合: `xmin <= x <= xmax` は `TypeError` になる可能性がある。 # - `xmin` と `xmax` が両方 `None` でない場合: `xmin <= x <= xmax` が評価され、真なら追加。 # この厳密な解釈だと、`read_csv` は `xmin` と `xmax` が両方 float で指定されなければ、ほとんど機能しない。 # しかし、Docstringはコードが何をするか記述するものなので、この不完全な部分もそのまま記述する。 # 元のコードを厳密に解釈した読み込みロジック: if xmin is not None and xmax is not None: # xmin, xmax が両方設定されている場合のみ範囲チェック if xmin <= x <= xmax: y = pfloat(row[1]) # pfloat は未定義 data[0].append(x) data[1].append(y) # xmin, xmax のいずれかが None の場合、または両方 None の場合、データは追加されない。 # これは設計ミスに見えるが、ルールに従う。 except: print("Error: Can not read [{}]".format(infile)) exit() return header, data[0], data[1]
[ドキュメント] def read_excel(infile): # terminate が未定義 """ Excelファイルから汎用データを読み込みます。 指定されたExcelファイルを開き、最初のシートから温度 (T)、キャリア密度 (N)、ゼーベック係数 (S) のデータを抽出します。 1行目をヘッダーとして解釈し、2行目以降の数値を読み込みます。 :param infile: 読み込むExcelファイルのパス。 :type infile: str :returns: タプル ([Tlabel, Nlabel], xT, yN, yS) - [Tlabel, Nlabel] (list[str]): 各データのヘッダーラベルのリスト (Slabel は返されない)。 - xT (list[float]): 温度データのリスト。 - yN (list[float]): キャリア密度データのリスト。 - yS (list[float]): ゼーベック係数データのリスト。 :rtype: tuple[list[str], list[float], list[float], list[float]] """ wb = openpyxl.load_workbook(infile, data_only = True) if not wb: print("") print("Error to read [{}]".format(infile)) print("") # terminate() # 未定義関数のためコメントアウト return [],[],[],[] # エラー時の戻り値を追加して、呼び出し元でのエラーを回避 sheetnames = wb.sheetnames print("sheet names:", sheetnames) print(" read [{}]".format(sheetnames[0])) # ws = wb.active ws = wb[sheetnames[0]] Tlabel = ws[1][0].value Nlabel = ws[1][1].value Slabel = ws[1][2].value print("Labels:", Tlabel, Nlabel, Slabel) xT = [] yN = [] yS = [] i = 2 while 1: Tcell = ws.cell(row = i, column = 1).value if Tcell is None or Tcell == '': break Ncell = ws.cell(row = i, column = 2).value Scell = ws.cell(row = i, column = 3).value Tcell = float(Tcell) Ncell = float(Ncell) Scell = float(Scell) xT.append(Tcell) yN.append(Ncell) yS.append(Scell) i += 1 return [Tlabel, Nlabel], xT, yN, yS
[ドキュメント] def main(): """ モジュールが直接実行された場合に呼び出されるメイン関数。 このモジュールがライブラリとして使用されることを示し、実行可能ではないことをユーザーに通知します。 :returns: None :rtype: None """ print("") print("This is a library, not runnable") print("")
if __name__ == "__main__": main()