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))