transfer_matrix.py ダウンロード/コピー

transfer_matrix.py をダウンロード

transfer_matrix.py
transfer_matrix.py
  1"""
  2伝達行列法を用いて1次元の波動関数と透過確率を計算するモジュール。
  3
  4このスクリプトは、多層構造における電子の1次元波動関数と透過確率を、
  5伝達行列法(Transfer Matrix Method)を用いて計算します。
  6ポテンシャルプロファイルは、Excelファイルから読み込むか、
  7または多重量子井戸(Multiple Quantum Well, MQW)モデルに基づいて生成することができます。
  8計算結果はグラフとして表示され、透過確率データはExcelファイルに保存されます。
  9
 10関連リンク: :doc:`transfer_matrix_usage`
 11"""
 12
 13import os
 14import sys
 15import numpy as np
 16from numpy import sqrt, exp, log, sin, cos, tan, cosh, sinh
 17import numpy.linalg as LA 
 18import csv
 19import pandas as pd
 20from matplotlib import pyplot as plt
 21
 22
 23#===================================
 24# physical constants
 25#===================================
 26pi   = 3.14159265358979323846
 27pi2  = 2.0 * pi
 28h    = 6.6260755e-34    # Js";
 29hbar = 1.05459e-34      # "Js";
 30c    = 2.99792458e8     # m/s";
 31e    = 1.60218e-19      # C";
 32e0   = 8.854418782e-12; # C<sup>2</sup>N<sup>-1</sup>m<sup>-2</sup>";
 33kB   = 1.380658e-23     # JK<sup>-1</sup>";
 34me   = 9.1093897e-31    # kg";
 35R    = 8.314462618      # J/K/mol
 36a0   = 5.29177e-11      # m";
 37
 38
 39#========================
 40# global configuration
 41#========================
 42mode = 'wf'   # wf|tr
 43
 44#========================
 45# potential
 46#========================
 47pottype = ''
 48#pottype = 'potential_defect.xlsx'
 49#pottype = 'mqw'
 50
 51#barrierwidth  =  0.5  # A
 52barrierwidth  =  1.0  # Si
 53#wellwidth     = 10.0  # A 
 54wellwidth     = 5.4064 - barrierwidth  # Si
 55barrierheight =  10.0  # eV
 56nbarriers     = 10
 57
 58# for wave functin plot
 59Ez0 = 0.1 # eV
 60
 61# for transmission probability
 62Emin = 0.01 # eV
 63#Emax =  1.0 # eV
 64Emax =  9.5 # Si
 65nE   =  1001
 66
 67# z range
 68zmin = -20.0 # zL, in angstrom
 69#zmax = 200.0 # zR, in angstrom
 70zmax = 70.0 # Si
 71nz   =  201
 72
 73#===================================
 74# figure configuration
 75#===================================
 76figsize = (8, 8)
 77fontsize        = 12
 78legend_fontsize = 8
 79
 80
 81#==============================================
 82# fundamental functions
 83#==============================================
 84def pfloat(str):
 85    """
 86    文字列を浮動小数点数に安全に変換します。
 87
 88    `float()` 関数と同様に文字列を浮動小数点数に変換しますが、
 89    変換に失敗した場合はエラーを発生させずにNoneを返します。
 90
 91    :param str: 変換する文字列。
 92    :type str: str
 93    :returns: 変換された浮動小数点数、または変換できなかった場合はNone。
 94    :rtype: float or None
 95    """
 96    try:
 97        return float(str)
 98    except:
 99        return None
100
101def pint(str):
102    """
103    文字列を整数に安全に変換します。
104
105    `int()` 関数と同様に文字列を整数に変換しますが、
106    変換に失敗した場合はエラーを発生させずにNoneを返します。
107
108    :param str: 変換する文字列。
109    :type str: str
110    :returns: 変換された整数、または変換できなかった場合はNone。
111    :rtype: int or None
112    """
113    try:
114        return int(str)
115    except:
116        return None
117
118def getarg(position, defval = None):
119    """
120    コマンドライン引数を安全に取得します。
121
122    `sys.argv` から指定された位置の引数を取得します。
123    指定された位置に引数が存在しない場合は、デフォルト値を返します。
124
125    :param position: 取得する引数の位置 (0-indexed)。
126    :type position: int
127    :param defval: 引数が存在しない場合に返すデフォルト値。
128    :type defval: any, optional
129    :returns: 指定された位置の引数、またはデフォルト値。
130    :rtype: str or any
131    """
132    try:
133        return sys.argv[position]
134    except:
135        return defval
136
137def getfloatarg(position, defval = None):
138    """
139    コマンドライン引数を浮動小数点数として安全に取得します。
140
141    `sys.argv` から指定された位置の引数を取得し、`pfloat` 関数を使って
142    浮動小数点数に変換します。引数が存在しない、または変換できない場合は
143    デフォルト値を返します。
144
145    :param position: 取得する引数の位置 (0-indexed)。
146    :type position: int
147    :param defval: 引数が存在しない、または変換できない場合に返すデフォルト値。
148    :type defval: float or None, optional
149    :returns: 変換された浮動小数点数、またはデフォルト値。
150    :rtype: float or None
151    """
152    return pfloat(getarg(position, defval))
153
154def getintarg(position, defval = None):
155    """
156    コマンドライン引数を整数として安全に取得します。
157
158    `sys.argv` から指定された位置の引数を取得し、`pint` 関数を使って
159    整数に変換します。引数が存在しない、または変換できない場合は
160    デフォルト値を返します。
161
162    :param position: 取得する引数の位置 (0-indexed)。
163    :type position: int
164    :param defval: 引数が存在しない、または変換できない場合に返すデフォルト値。
165    :type defval: int or None, optional
166    :returns: 変換された整数、またはデフォルト値。
167    :rtype: int or None
168    """
169    return pint(getarg(position, defval))
170
171def usage():
172    """
173    プログラムの正しい使用方法を標準出力に表示します。
174
175    プログラムの実行モード (`wf` または `tr`) に応じたコマンドライン引数の例を示します。
176    """
177    global mode, Ez, nz
178
179    print("")
180    print("Usage: Variables in () are optional")
181    print("  python {} (pottype wf nz Ez0)".format(sys.argv[0]))
182    print("    ex: python {} (wf {} {} {})".format(sys.argv[0], pottype, nz, Ez0))
183    print("  python {} (tr nz Ez0 Emin Emax nE)".format(sys.argv[0]))
184    print("    ex: python {} (tr {} {} {} {} {} {})".format(sys.argv[0], pottype, nz, Ez0, Emin, Emax, nE))
185
186def terminate(message = None):
187    """
188    指定されたメッセージを表示し、プログラムを終了します。
189
190    エラーメッセージなどを表示した後、`usage()` 関数を呼び出して使用方法を表示し、
191    システムを終了します。
192
193    :param message: 終了時に表示するメッセージ。
194    :type message: str, optional
195    """
196    print("")
197    if message is not None:
198        print("")
199        print(message)
200        print("")
201
202    usage()
203    print("")
204    exit()
205
206
207def IsInBarrier(z):
208    """
209    指定されたz座標がポテンシャル障壁内にあるかを判定します。
210
211    グローバル変数 `wellwidth`, `barrierwidth`, `nbarriers` に基づき、
212    多重量子井戸構造における障壁領域にzが属するかをチェックします。
213
214    :param z: 判定するz座標 (Å)。
215    :type z: float
216    :returns: zが障壁内にある場合は1、それ以外の場合は0。
217    :rtype: int
218    """
219    global wellwidth, barrierwidth, barrierheight, nbarriers
220
221    w = wellwidth + barrierwidth
222    n = int(z / w)
223    if n < nbarriers and 0.0 <= z - n * w < barrierwidth:
224        return 1
225    else:
226        return 0
227
228def U(z):   # eV
229    """
230    指定されたz座標におけるポテンシャルエネルギーを返します。
231
232    `IsInBarrier` 関数を使用してz座標が障壁内にあるかを判断し、
233    障壁内であれば `barrierheight` (eV) を、そうでなければ0.0 eVを返します。
234
235    :param z: ポテンシャルエネルギーを評価するz座標 (Å)。
236    :type z: float
237    :returns: zにおけるポテンシャルエネルギー (eV)。
238    :rtype: float
239    """
240    global wellwidth, barrierwidth, barrierheight, nbarriers
241
242    if IsInBarrier(z):
243        return barrierheight
244    else:
245        return 0.0
246
247def build_U(pottype, xz = None):
248    """
249    ポテンシャルエネルギーと有効質量プロファイルを作成または読み込みます。
250
251    `pottype` が 'mqw' の場合、多重量子井戸モデルに基づいてポテンシャル `yU` と
252    有効質量 `ym` を生成します。それ以外の場合、指定されたExcelファイルから
253    ポテンシャルと有効質量のデータを読み込みます。
254
255    :param pottype: ポテンシャルの種類 ('mqw' または Excelファイルパス)。
256    :type pottype: str
257    :param xz: 'mqw'タイプの場合に使用されるz座標の配列。Noneの場合は生成される。
258    :type xz: numpy.ndarray, optional
259    :returns: (データ点の数, z座標配列, ポテンシャルエネルギー配列, 有効質量配列)。
260    :rtype: tuple[int, numpy.ndarray, numpy.ndarray, numpy.ndarray]
261    """
262    if pottype == 'mqw':
263        print()
264        print(f"Build multiple quantum wells potential")
265        nz = len(xz)
266        yU = np.array([U(z) for z in xz])
267        ym = np.array([meff(z) for z in xz])
268        return nz, xz, yU, ym
269    else:
270        print()
271        if not os.path.exists(pottype):
272            print(f"Potential file [{pottype}] does not exists.")
273            exit()
274
275        print(f"Read potential from [{pottype}]")
276        df = pd.read_excel(pottype)
277        nz = len(df)
278        xz = df.iloc[:, 0].to_numpy()
279        yU = df.iloc[:, 1].to_numpy()
280        ym = df.iloc[:, 2].to_numpy()
281        return nz, xz, yU, ym
282    
283def meff(z):
284    """
285    指定されたz座標における有効質量を返します。
286
287    z座標に基づいて、井戸領域または障壁領域の有効質量(電子質量meの倍数)を返します。
288    この関数はハードコードされた領域に依存します。
289
290    :param z: 有効質量を評価するz座標 (Å)。
291    :type z: float
292    :returns: zにおける有効質量(電子質量 me の倍数)。
293    :rtype: float
294    """
295    mwell    = 1.0
296    mbarrier = 1.0
297    if 0.0 <= z < 5.0:
298        return mbarrier
299    elif 25.0 <= z < 30.0:
300        return mbarrier
301    else:
302        return mwell
303
304
305def cal_wf(xz, yU, ym, Ez):
306    """
307    伝達行列法を用いて1次元波動関数と透過確率を計算します。
308
309    与えられたz座標、ポテンシャル、有効質量、およびエネルギーに対して、
310    各セクションの波数 `kz`、振幅 `A` と `B`、および波動関数 `Psi` を計算します。
311    最終的に透過確率 `T` も算出します。
312
313    :param xz: z座標の配列 (Å)。
314    :type xz: numpy.ndarray
315    :param yU: 各z座標におけるポテンシャルエネルギーの配列 (eV)。
316    :type yU: numpy.ndarray
317    :param ym: 各z座標における有効質量の配列 (電子質量 me の倍数)。
318    :type ym: numpy.ndarray
319    :param Ez: 電子の入射エネルギー (eV)。
320    :type Ez: float
321    :returns: (波数配列, A振幅配列, B振幅配列, 波動関数配列, 透過確率)。
322    :rtype: tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray, float]
323    """
324    nz = len(xz)
325    ykz  = np.empty(nz, dtype = complex)
326    for i in range(nz):
327        z = xz[i]
328        kz = sqrt(2.0 * ym[i] * me / hbar / hbar * (Ez - yU[i])*e + 0.0j) * 1.0e-10
329        ykz[i] = kz
330
331    Ai  = np.empty(nz, dtype = complex)
332    Bi  = np.empty(nz, dtype = complex)
333    Psi = np.empty(nz, dtype = complex)
334    Ai[0] = 1.0
335    Bi[0] = 0.0
336    for i in range(1, nz):
337#        print(i, xz[i], Ez, ym[i], ykz[i])
338        if ykz[i] == 0.0:
339            # 波数kzが0の場合、数値的な安定性を保つため微小な値に置き換える
340            # これによりゼロ除算を防ぎ、伝達行列の計算を続行できるようにする
341            ykz[i] = 1.0e-10
342        mk = ym[i] / ym[i-1] * ykz[i-1] / ykz[i]
343        ap = 0.5 * (1.0 + mk)
344        am = 0.5 * (1.0 - mk)
345        P = exp(1.0j * (ykz[i-1] - ykz[i]) * xz[i])
346        Q = exp(1.0j * (ykz[i-1] + ykz[i]) * xz[i])
347        Ai[i] = ap * P * Ai[i-1] + am / Q * Bi[i-1]
348        Bi[i] = am * Q * Ai[i-1] + ap / P * Bi[i-1]
349        Psi[i] = Ai[i] * exp(1.0j * ykz[i] * xz[i]) + Bi[i] * exp(-1.0j * ykz[i] * xz[i])
350
351    # 最後のステップでの透過確率の計算
352    # 透過確率はAiとBiの比、および有効質量と波数に依存する
353    T = ym[nz-1] / ym[0] * ykz[0] / ykz[nz-1] * Ai[0] / Ai[nz-1]
354    T = pow(abs(T), 2)
355
356    # 波動関数を規格化(最終的なPsiの振幅をkで割る)
357    # ただし、この部分はPsi[i]の計算ループ外にあるため、Psi配列全体を規格化するには修正が必要
358    # 現在の実装ではPsi[i]の最後の要素のみが更新されているが、Ai, Biも同様に規格化されている。
359    k = sqrt(pow(abs(Ai[nz-1]), 2) + pow(abs(Bi[nz-1]), 2))
360    # 以下は最後の要素のみを規格化するコードであることに注意
361    Ai[i] /= k
362    Bi[i] /= k
363    Psi[i] /= k
364
365    return ykz, Ai, Bi, Psi, T
366
367def analytical_check(Ez, a):
368    """
369    無限に深い井戸型ポテンシャルの解析解との比較情報を提供します。
370
371    指定されたエネルギー `Ez` と井戸幅 `a` を用いて、自由粒子の波数と、
372    無限に深い井戸型ポテンシャルの基底状態エネルギーを計算し、表示します。
373    これは、計算結果の妥当性を確認するための参考情報です。
374
375    :param Ez: 比較に使用するエネルギー (eV)。
376    :type Ez: float
377    :param a: 無限井戸の幅 (Å)。
378    :type a: float
379    """
380    print("")
381    print("=== Analyatical results to check ===")
382    kz = sqrt(Ez * e / (hbar * hbar / 2.0 / me)) * 1.0e-10 # A^-1
383    print("Ez = {} eV".format(Ez))
384    print("  kz = {} A^-1".format(kz*1.0e-10))
385
386    print("=== Infinit potential well ===")
387    print("Well width: {} A".format(a))
388    k = 2.0 * pi / (2.0 * a * 1.0e-10) 
389    E = hbar * hbar / 2.0 / me * k * k / e # eV
390    print("  E0={:12.6g} eV".format(E))
391
392def tr():
393    """
394    エネルギーに対する透過確率を計算し、結果をプロットします。
395
396    コマンドライン引数またはグローバル設定に基づき、指定されたエネルギー範囲で
397    透過確率を計算します。計算されたポテンシャルプロファイルと透過確率は
398    Excelファイルに保存され、複数のグラフとして表示されます。
399    """
400    global mode
401    global zmin, zmax, nz
402    global Emin, Emax, nE
403    global Ez0
404
405    zstep = (zmax - zmin) / (nz - 1)
406    Estep = (Emax - Emin) / (nE - 1)
407
408    analytical_check(Ez0, 20.0)
409
410    print("")
411    print("=== Input parameterss ===")
412    print("zmin(zL)=", zmin, "A")
413    print("zmax(zL)=", zmax, "A")
414    print("nz=", nz)
415    print("zstep=", zstep)
416    print("Ez0={} eV".format(Ez0))
417    print("Erange: {} - {} eV, {} step, nE={}".format(Emin, Emax, Estep, nE))
418    
419    # z座標をzmaxからzminへと逆順に設定
420    xz = np.array([zmax - i * zstep for i in range(nz)])
421    nz, xz, yU, ym = build_U(pottype, xz)
422
423    # エネルギー範囲を対数スケールで設定
424    Elogstep = (log(Emax) - log(Emin)) / (nE - 1)
425    xE = np.array([exp(log(Emin) + i * Elogstep) for i in range(nE)])
426    
427    potential_xlsx = 'potential.xlsx'
428    print()
429    print("Save potential to [{potential_xlsx}]")
430    df = pd.DataFrame(np.array([xz, yU, ym]).T, columns = ["z (A)", "U (eV)", "m* (me)"])
431    df.to_excel(potential_xlsx, index = False)
432
433    print("")
434    print("=== Wave function at Ez0 = {} eV ===".format(Ez0))
435    # 特定のエネルギーEz0での波動関数と透過確率を計算
436    ykz0, Ai0, Bi0, Psi0, T0 = cal_wf(xz, yU, ym, Ez0)
437    print("Transmission probability at {} eV: {}".format(Ez0, T0))
438
439    transmission_xlsx = 'transmission.xlsx'
440    print("")
441    print("=== Transmission probability vs Energy")
442    yT = []
443    print("{:10}\t{:10}".format("E (eV)", "T"))
444    nprint_data = 100
445    nskip = int(len(xE) / nprint_data)
446    # 各エネルギーに対する透過確率を計算
447    for i, E in enumerate(xE):
448        ykz, Ai, Bi, Psi, T = cal_wf(xz, yU, ym, E)
449        yT.append(T)
450        if i % nskip == 0:
451            print("{:10.6g}\t{:14.6g}".format(E, T))
452    df = pd.DataFrame(np.array([xE, yT]).T, columns = ["E (eV)", "T"])
453    df.to_excel(transmission_xlsx, index = False)
454
455
456    print("")
457    print("plot")
458    fig = plt.figure(figsize = figsize)
459    ax1 = fig.add_subplot(2, 2, 1)
460# ax2をax1に関連させる
461    ax2 = ax1.twinx()
462    ax3 = fig.add_subplot(2, 2, 2)
463    ax4 = fig.add_subplot(2, 2, 3)
464    ax5 = fig.add_subplot(2, 2, 4)
465
466    # プロット: ポテンシャルと有効質量
467    ax1.plot(xz, yU, label = 'U(z)',         linewidth = 0.5, color = 'red')
468    ax2.plot(xz, ym, label = 'm$_{eff}$(z)', linewidth = 0.5, color ='blue')
469    
470    # プロット: 波数kzの虚部と実部
471    ykzr = [ykz0[i].real for i in range(nz)]
472    ykzi = [ykz0[i].imag for i in range(nz)]
473    ax3.plot(xz, ykzr, label = 'kz(real) (A$^{-1}$)', linewidth = 0.5, marker = 'o', markersize = 2)
474    ax3.plot(xz, ykzi, label = 'kz(imag) (A$^{-1}$)', linewidth = 0.5)
475
476    # プロット: 透過確率
477    ax4.plot(xE, yT, label = 'T',    linewidth = 0.5, color = 'red', marker = 'o', markersize = 0.5)
478    
479    # プロット: 波動関数
480    yPsir = [Psi0[i].real for i in range(nz)]
481    yPsii = [Psi0[i].imag for i in range(nz)]
482    yPsia = [pow(abs(Psi0[i]), 2) for i in range(nz)]
483    ax5.plot(xz, yPsir, label = '$\Psi$(real)', linewidth = 0.5)
484    ax5.plot(xz, yPsii, label = '$\Psi$(imag)', linewidth = 0.5)
485    ax5.plot(xz, yPsia, label = '$|\Psi|^2$', linewidth = 0.5)
486
487    # ラベル設定
488    ax1.set_xlabel("z (A)", fontsize = fontsize)
489    ax1.set_ylabel("U(z)", fontsize = fontsize)
490    ax2.set_ylabel("m*(z)", fontsize = fontsize)
491    ax3.set_xlabel("z (A)", fontsize = fontsize)
492    ax3.set_ylabel("kz (A$^{-1}$)", fontsize = fontsize)
493    ax4.set_xlabel("E (eV)", fontsize = fontsize)
494    ax4.set_ylabel("Transmission probability", fontsize = fontsize)
495    ax5.set_xlabel("z (A)", fontsize = fontsize)
496    ax5.set_ylabel("$\Psi$(z)", fontsize = fontsize)
497
498    # 軸範囲設定
499    ax1.set_xlim([zmin, zmax])
500    ax2.set_xlim([zmin, zmax])
501    ax1.set_ylim([min(yU), max(yU) * 1.1])
502    ax2.set_ylim([min(ym), max(ym) * 1.3])
503    ax3.set_xlim([zmin, zmax])
504#    ax4.set_xlim([min(0.0, Emin), Emax])
505    ax4.set_ylim([0.0, 1.1])
506    ax5.set_xlim([zmin, zmax])
507
508# 凡例をまとめて出力する
509    handler1, label1 = ax1.get_legend_handles_labels()
510    handler2, label2 = ax2.get_legend_handles_labels()
511    ax1.legend(handler1 + handler2, label1 + label2, loc = 2, borderaxespad = 0.0, fontsize = legend_fontsize)
512    ax3.legend(fontsize = legend_fontsize)
513    ax4.legend(fontsize = legend_fontsize)
514    ax5.legend(fontsize = legend_fontsize)
515
516    # 目盛り設定
517    ax1.tick_params(labelsize = fontsize)
518    ax2.tick_params(labelsize = fontsize)
519    ax3.tick_params(labelsize = fontsize)
520    ax4.tick_params(labelsize = fontsize)
521    ax5.tick_params(labelsize = fontsize)
522    plt.tight_layout()
523
524    plt.pause(0.1)
525    print("")
526    print("Press ENTER to exit>>", end = '')
527    input()
528
529    terminate()
530
531def wf():
532    """
533    特定のエネルギーにおける波動関数を計算し、結果をプロットします。
534
535    コマンドライン引数またはグローバル設定に基づき、指定された単一のエネルギー `Ez0` に対して
536    波動関数 `Psi` を計算します。計算されたポテンシャルプロファイルと波動関数は
537    複数のグラフとして表示されます。
538    """
539    global mode
540    global zmin, zmax, nz
541    global Ez0
542
543    analytical_check(Ez0, 20.0)
544
545    zstep = (zmax - zmin) / (nz - 1)
546
547    print("")
548    print("=== Input parameterss ===")
549    print("zmin(zL)=", zmin, "A")
550    print("zmax(zL)=", zmax, "A")
551    print("nz=", nz)
552    print("zstep=", zstep)
553    print("Ez0=", Ez0, "eV")
554
555    # z座標をzmaxからzminへと逆順に設定
556    xz = np.array([zmax - i * zstep for i in range(nz)])
557    nz, xz, yU, ym = build_U(pottype, xz)
558
559    print("")
560    print("=== Calculate wave function")
561    ykz, Ai, Bi, Psi, T = cal_wf(xz, yU, ym, Ez0)
562
563    print("Transmission probability from z = {} to {} A: {:14.6g}".format(xz[nz-1], xz[0], T))
564
565    print("")
566    print("plot")
567    fig = plt.figure(figsize = figsize)
568    ax1 = fig.add_subplot(2, 2, 1)
569# ax2をax1に関連させる
570    ax2 = ax1.twinx()
571    ax3 = fig.add_subplot(2, 2, 2)
572    ax4 = fig.add_subplot(2, 2, 3)
573    ax5 = fig.add_subplot(2, 2, 4)
574
575    # プロット: ポテンシャルと有効質量
576    ax1.plot(xz, yU, label = 'U(z)',    linewidth = 0.5, color = 'red')
577    ax2.plot(xz, ym, label = 'm$_{eff}$(z)', linewidth = 0.5, color ='blue')
578    
579    # プロット: 波数kzの虚部と実部
580    ykzr = [ykz[i].real for i in range(nz)]
581    ykzi = [ykz[i].imag for i in range(nz)]
582    ax3.plot(xz, ykzr, label = 'kz(real) (A$^{-1}$)', linewidth = 0.5, marker = 'o', markersize = 2)
583    ax3.plot(xz, ykzi, label = 'kz(imag) (A$^{-1}$)', linewidth = 0.5)
584    
585    # プロット: Ai, Biの絶対値
586    yAir = [Ai[i].real for i in range(nz)]
587    yAii = [Ai[i].imag for i in range(nz)]
588    yAia = [abs(Ai[i]) for i in range(nz)]
589    yBir = [Bi[i].real for i in range(nz)]
590    yBii = [Bi[i].imag for i in range(nz)]
591    yBia = [abs(Bi[i]) for i in range(nz)]
592#    ax4.plot(xz, yAir, label = 'Ai(real)', linewidth = 0.5)
593#    ax4.plot(xz, yAii, label = 'Ai(imag)', linewidth = 0.5)
594    ax4.plot(xz, yAia, label = 'Ai(abs)', linewidth = 0.5)
595#    ax4.plot(xz, yBii, label = 'Bi(imag)', linewidth = 0.5)
596#    ax4.plot(xz, yBir, label = 'Bi(real)', linewidth = 0.5)
597    ax4.plot(xz, yBia, label = 'Bi(abs)', linewidth = 0.5) # yBiiではなくyBiaをプロットする
598    
599    # プロット: 波動関数
600    yPsir = [Psi[i].real for i in range(nz)]
601    yPsii = [Psi[i].imag for i in range(nz)]
602    yPsia = [pow(abs(Psi[i]), 2) for i in range(nz)]
603    ax5.plot(xz, yPsir, label = '$\Psi$(real)', linewidth = 0.5)
604    ax5.plot(xz, yPsii, label = '$\Psi$(imag)', linewidth = 0.5)
605    ax5.plot(xz, yPsia, label = '$|\Psi|^2$', linewidth = 0.5)
606
607    # ラベル設定
608    ax1.set_xlabel("z (A)", fontsize = fontsize)
609    ax1.set_ylabel("U(z)", fontsize = fontsize)
610    ax2.set_ylabel("m*(z)", fontsize = fontsize)
611    ax3.set_xlabel("z (A)", fontsize = fontsize)
612    ax3.set_ylabel("kz (A$^{-1}$)", fontsize = fontsize)
613    ax4.set_xlabel("z (A)", fontsize = fontsize)
614    ax4.set_ylabel("Ai, Bi", fontsize = fontsize)
615    ax5.set_xlabel("z (A)", fontsize = fontsize)
616    ax5.set_ylabel("$\Psi$(z)", fontsize = fontsize)
617
618    # 軸範囲設定
619    ax1.set_xlim([zmin, zmax])
620    ax2.set_xlim([zmin, zmax])
621    ax3.set_xlim([zmin, zmax])
622    ax4.set_xlim([zmin, zmax])
623    ax5.set_xlim([zmin, zmax])
624    ax1.set_ylim([min(yU), max(yU) * 1.1])
625    ax2.set_ylim([min(ym), max(ym) * 1.3])
626    # kzの軸範囲は計算された実部と虚部の最小値と最大値に基づいて調整
627    ax3.set_ylim([min(min(ykzr), min(ykzi) - 0.1), max(max(ykzr) * 1.1, max(ykzi) * 1.3)]) # 実部と虚部の両方を考慮
628
629# 凡例をまとめて出力する
630    handler1, label1 = ax1.get_legend_handles_labels()
631    handler2, label2 = ax2.get_legend_handles_labels()
632    ax1.legend(handler1 + handler2, label1 + label2, loc = 2, borderaxespad = 0.0, fontsize = legend_fontsize)
633    ax3.legend(fontsize = legend_fontsize)
634    ax4.legend(fontsize = legend_fontsize)
635    ax5.legend(fontsize = legend_fontsize)
636
637    # 目盛り設定
638    ax1.tick_params(labelsize = fontsize)
639    plt.tight_layout()
640
641    plt.pause(0.1)
642    print("")
643    print("Press ENTER to exit>>", end = '')
644    input()
645
646    terminate()
647
648
649if __name__ == "__main__":
650#==============================================
651# update default values by startup arguments
652#==============================================
653    argv = sys.argv
654
655    mode    = getarg     (1, mode)
656    pottype = getarg     (2, pottype)
657    nz      = getintarg  (3, nz)
658    Ez0     = getfloatarg(4, Ez0)
659
660    if pottype == "":
661        exit()
662
663    if mode == 'wf':
664        pass
665    elif mode == 'tr':
666        Emin  = getfloatarg(5, Emin)
667        Emax  = getfloatarg(6, Emax)
668        nE    = getintarg(7, nE)
669    else:
670        terminate("Error: Invalide mode [{}]".format(mode))
671
672    if mode == 'wf':
673        wf()
674    elif mode == 'tr':
675        tr()
676    else:
677        terminate("Error: Invalid mode [{}]".format(mode))