H1s_HF_LDA.py ダウンロード/コピー
H1s_HF_LDA.py
H1s_HF_LDA.py
1"""
2概要:
3H-like 1s軌道エネルギーレベル計算モジュール。
4詳細説明:
5このモジュールは、H-like 1s軌道のエネルギーレベルを計算するために、1s動径関数とスレーターのX-αポテンシャルを使用します。
6ハートリー・フォック・スレーター(HFS)法の基本的な概念に基づき、電子間の相互作用を交換ポテンシャルで近似して扱います。
7動径関数の指数係数kaや電子数Neなどを変分法で最適化し、全エネルギーを最小化する計算も可能です。
8"""
9import os
10import sys
11from math import exp, sqrt
12import numpy as np
13from math import log, exp
14from numpy import arange
15from scipy import integrate # 数値積分関数 integrateを読み込む
16from scipy.interpolate import interp1d
17from scipy import optimize
18from scipy.optimize import minimize
19from matplotlib import pyplot as plt
20
21
22# constants
23pi = 3.14159265358979323846
24h = 6.6260755e-34 # Js";
25hbar = 1.05459e-34 # "Js";
26c = 2.99792458e8 # m/s";
27e = 1.60218e-19 # C";
28kB = 1.380658e-23 # JK<sup>-1</sup>";
29me = 9.1093897e-31 # kg";
30e0 = 8.854418782e-12; # C<sup>2</sup>N<sup>-1</sup>m<sup>-2</sup>";
31e2_4pie0 = 2.30711e-28 # Nm<sup>2</sup>";
32a0 = 5.29177e-11 * 1.0e10 # A
33HartreeToeV = 27.2116 # eV";
34RyToeV = HartreeToeV / 2.0
35pi2 = pi + pi
36pi4 = pi2 + pi2
37
38
39# mode: 'd': debug mode, plot fundamental graphs
40# 'g': plot graph
41# 'k': sweep ka, 'n': sweep Ne
42# 'v': add variational calculation, 'e': energy-based output
43mode = 'k'
44ELabel = 'E 1s'
45
46# Nuclear and orbital parameters
47Z = 1.0
48n = 1
49l = 0
50m = 0
51ka = 1.0 # coefficient of the exponent in R1s
52Ne = 1.0
53
54# Number of electrons, Slater's alpha
55alpha = 2.0 / 3.0
56
57# Radius range and integration (quad()) parameters
58Rmin = 0.0
59Rmax = 20.0
60nR = 2001
61Rstep = None
62Rmaxdata = None
63nmaxdiv = 40
64epsR = 1.0e-4
65eps = 1.0e-8
66
67# Ne mesh to calculate 1st and 2nd derivative of Etot
68hparab = 0.01
69
70# iteration parameters
71#Nearray = [1.0, 0.8, 0.6]
72#Nearray = [1.0, 0.8, 0.6, 0.5, 0.4, 0.3, 0.1, 0.01, 0.001]
73Nearray = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.07, 0.05, 0.04, 0.03, 0.02, 0.01, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6]
74kaarray = [0.5, 0.6, 0.65, 0.7, 0.8, 0.9, 0.95, 1.0, 1.05, 1.1, 1.2, 1.4]
75
76#=============================================
77# scipy.optimize.minimizeで使うアルゴリズム
78#=============================================
79#nelder-mead Downhill simplex
80#powell Modified Powell
81#cg conjugate gradient (Polak-Ribiere method)
82#bfgs BFGS法
83#newton-cg Newton-CG
84#trust-ncg 信頼領域 Newton-CG 法
85#dogleg 信頼領域 dog-leg 法
86#L-BFGS-B’ (see here)
87#TNC’ (see here)
88#COBYLA’ (see here)
89#SLSQP’ (see here)
90#trust-constr’(see here)
91#dogleg’ (see here)
92#trust-exact’ (see here)
93#trust-krylov’ (see here)
94method = "nelder-mead"
95#method = 'cg'
96#method = 'powell'
97#method = 'bfgs'
98
99maxiter = 1000
100tol = 1.0e-3
101h_diff = 1.0e-3
102
103def pfloat(str):
104 """
105 概要: 文字列を浮動小数点数に安全に変換します。
106
107 詳細説明:
108 標準のfloat()関数と異なり、変換に失敗した場合でもエラーを発生させずにNoneを返します。
109 これにより、不正な入力があってもプログラムが中断されるのを防ぎます。
110
111 :param str: 変換する文字列。
112 :type str: str
113 :returns: 変換された浮動小数点数、または変換に失敗した場合はNone。
114 :rtype: float or None
115 """
116 try:
117 return float(str)
118 except:
119 return None
120
121def pint(str):
122 """
123 概要: 文字列を整数に安全に変換します。
124
125 詳細説明:
126 標準のint()関数と異なり、変換に失敗した場合でもエラーを発生させずにNoneを返します。
127 これにより、不正な入力があってもプログラムが中断されるのを防ぎます。
128
129 :param str: 変換する文字列。
130 :type str: str
131 :returns: 変換された整数、または変換に失敗した場合はNone。
132 :rtype: int or None
133 """
134 try:
135 return int(str)
136 except:
137 return None
138
139def getarg(position, defval = None):
140 """
141 概要: コマンドライン引数を安全に取得します。
142
143 詳細説明:
144 sys.argvリストから指定された位置の引数を取得します。
145 指定された位置が存在しない場合、エラーを発生させずにデフォルト値を返します。
146
147 :param position: 取得する引数のsys.argv内でのインデックス。
148 :type position: int
149 :param defval: 引数が存在しない場合に返すデフォルト値。デフォルトはNone。
150 :type defval: any, optional
151 :returns: 指定された位置の引数、または引数が存在しない場合はdefval。
152 :rtype: str or any
153 """
154 try:
155 return sys.argv[position]
156 except:
157 return defval
158
159def getfloatarg(position, defval = None):
160 """
161 概要: コマンドライン引数を浮動小数点数として安全に取得します。
162
163 詳細説明:
164 指定された位置のコマンドライン引数を取得し、pfloat()関数を使用して浮動小数点数に変換します。
165 引数が存在しない場合や変換に失敗した場合、エラーを発生させずにデフォルト値を返します。
166
167 :param position: 取得する引数のsys.argv内でのインデックス。
168 :type position: int
169 :param defval: 引数が存在しない場合や変換に失敗した場合に返すデフォルト値。デフォルトはNone。
170 :type defval: float or None, optional
171 :returns: 変換された浮動小数点数、または失敗した場合はdefval。
172 :rtype: float or None
173 """
174 return pfloat(getarg(position, defval))
175
176def getintarg(position, defval = None):
177 """
178 概要: コマンドライン引数を整数として安全に取得します。
179
180 詳細説明:
181 指定された位置のコマンドライン引数を取得し、pint()関数を使用して整数に変換します。
182 引数が存在しない場合や変換に失敗した場合、エラーを発生させずにデフォルト値を返します。
183
184 :param position: 取得する引数のsys.argv内でのインデックス。
185 :type position: int
186 :param defval: 引数が存在しない場合や変換に失敗した場合に返すデフォルト値。デフォルトはNone。
187 :type defval: int or None, optional
188 :returns: 変換された整数、または失敗した場合はdefval。
189 :rtype: int or None
190 """
191 return pint(getarg(position, defval))
192
193def usage(ka = ka, Z = Z, n = n, l = l, m = m):
194 """
195 概要: プログラムの使用方法を表示します。
196
197 詳細説明:
198 コマンドライン引数の構文と利用可能なモードオプションをユーザーに示します。
199 デフォルト値のka, Z, n, l, mは現在のグローバル変数から取得されますが、
200 直接引数として渡すことも可能です。
201
202 :param ka: 1s動径関数の指数部の係数。デフォルトはグローバル変数ka。
203 :type ka: float, optional
204 :param Z: 原子番号。デフォルトはグローバル変数Z。
205 :type Z: float, optional
206 :param n: 主量子数。デフォルトはグローバル変数n。
207 :type n: int, optional
208 :param l: 方位量子数。デフォルトはグローバル変数l。
209 :type l: int, optional
210 :param m: 磁気量子数。デフォルトはグローバル変数m。
211 :type m: int, optional
212 :returns: なし
213 :rtype: None
214 """
215 print("")
216 print("Usage: Variables in () are optional")
217 print(" (i) python {} mode Z ka Ne".format(sys.argv[0]))
218 print(" mode: combination of the following key characters")
219 print(" d: debug mode, plot fundamental graphs")
220 print(" v: add variational calculations")
221 print(" e: output based on energy (default: based on E 1s eigen value)")
222 print(" k: sweep ka")
223 print(" n: sweep Ne")
224 print(" g : plot graph")
225 print(" ex: python {} nvg {} {} {}".format(sys.argv[0], Z, ka, Ne))
226 print(" ex: python {} k {} {} {}".format(sys.argv[0], Z, ka, Ne))
227
228def terminate(message = None):
229 """
230 概要: メッセージを表示し、プログラムを終了します。
231
232 詳細説明:
233 オプションで終了メッセージを表示し、usage()関数を呼び出して使用方法を提示した後、
234 プログラムを終了します。
235
236 :param message: 終了時に表示するメッセージ。デフォルトはNone。
237 :type message: str, optional
238 :returns: なし (プログラムが終了するため)
239 :rtype: None
240 """
241 if message is not None:
242 print("")
243 print(message)
244
245 usage()
246 print("")
247 exit()
248
249def updatevars():
250 """
251 概要: コマンドライン引数に基づいてグローバル変数を更新します。
252
253 詳細説明:
254 sys.argvからプログラム起動時の引数を取得し、mode, ELabel, ka, Z, Ne
255 などのグローバル変数を更新します。これにより、ユーザーはコマンドラインから計算パラメータを
256 指定できます。ELabelはmodeに'e'が含まれるかどうかに応じて設定されます。
257
258 :returns: なし
259 :rtype: None
260 """
261 global mode, ELabel
262 global ka, Z, Ne, n, l, m, Ne, Rmax, Rstep
263
264 argv = sys.argv
265 if len(argv) == 1:
266 terminate()
267
268 mode = getarg( 1, mode)
269 Z = getfloatarg( 2, Z)
270 ka = getfloatarg( 3, ka)
271 Ne = getfloatarg( 4, Ne)
272
273 if 'e' in mode:
274 ELabel = 'Etot'
275 else:
276 ELabel = 'E 1s'
277
278# Total charge inside r
279yRr = [] # Raidal distributuion function
280yQr = [] # Integrated charge inside r: integ_rm(4pi * rm * rm * rho(rm))_[rm = 0, r]
281
282def Rr(ka, Z, n, l, m, r):
283 """
284 概要: H-like 1s軌道の動径関数 R_nl(r) を計算します。
285
286 詳細説明:
287 この関数は、水素様原子の1s軌道に対する動径関数を計算します。
288 指数係数 ka と原子番号 Z に依存します。
289 正規化条件は integ(4pi*r*r*Rr(r)*Rr(r))[r=0, inf] = 1 です。
290 内部でグローバル変数 R1s0 を使用しますが、この変数はこのスクリプト内で定義されていません。
291
292 :param ka: 動径関数の指数部分の係数。
293 :type ka: float
294 :param Z: 原子番号。
295 :type Z: float
296 :param n: 主量子数 (1s軌道なので常に1)。
297 :type n: int
298 :param l: 方位量子数 (1s軌道なので常に0)。
299 :type l: int
300 :param m: 磁気量子数 (1s軌道なので常に0)。
301 :type m: int
302 :param r: 核からの距離。
303 :type r: float
304 :returns: 指定された距離におけるH-like 1s軌道の動径関数の値。
305 :rtype: float
306 """
307 global R1s0
308
309 return R1s0 * pow(ka * Z, 1.5) * exp(-ka * Z * r)
310
311def rho(ka, Z, n, l, m, r):
312 """
313 概要: H-like 1s軌道の電子密度関数 ρ(r) を計算します。
314
315 詳細説明:
316 動径関数 Rr(r) の二乗として電子密度を計算します。
317 ρ(r) = Rr(r)^2 です。
318
319 :param ka: 動径関数の指数部分の係数。
320 :type ka: float
321 :param Z: 原子番号。
322 :type Z: float
323 :param n: 主量子数 (1s軌道なので常に1)。
324 :type n: int
325 :param l: 方位量子数 (1s軌道なので常に0)。
326 :type l: int
327 :param m: 磁気量子数 (1s軌道なので常に0)。
328 :type m: int
329 :param r: 核からの距離。
330 :type r: float
331 :returns: 指定された距離における電子密度 ρ(r) の値。
332 :rtype: float
333 """
334 psi = Rr(ka, Z, n, l, m, r)
335 return psi * psi
336
337def calQ(R):
338 """
339 概要: 核からの距離Rの内側に存在する総電荷 (Q(R)) を計算します。
340
341 詳細説明:
342 0からRまでの範囲で電子密度 ρ(r) を積分することにより、
343 距離Rの内側の電子が形成する電荷を求めます。
344 この関数は build_Qr で構築された補間関数 qfunc を使用します。
345 qfuncが未構築の場合や、指定されたRが有効範囲外の場合はエラー処理または0を返します。
346
347 :param R: 核からの距離。
348 :type R: float
349 :returns: 距離Rの内側に存在する総電荷。
350 :rtype: float
351 """
352 global Rmin, Rmaxdata, r, Qr
353
354 if R < Rmin:
355 print("Error in Q(r): Given r={} exceeds the R range [{}, {}]".format(R, Rmin, Rmax))
356 exit()
357 if R > Rmaxdata:
358 return 0.0
359
360 return qfunc(R)
361
362def build_Qr(ka, Z, n, l, m):
363 """
364 概要: 距離r内側の総電荷分布 Q(r) の補間関数を構築します。
365
366 詳細説明:
367 rの各点に対して Rr(r) と rho(r) を計算し、
368 4pi * r*r * rho(r) を0から r まで積分することで Q(r) を求めます。
369 求めた Q(r) のデータポイント yQr を使用して、
370 scipy.interpolate.interp1d により三次スプライン補間関数 qfunc を構築し、
371 calQ 関数で利用できるようにします。
372
373 :param ka: 動径関数の指数部分の係数。
374 :type ka: float
375 :param Z: 原子番号。
376 :type Z: float
377 :param n: 主量子数 (1s軌道なので常に1)。
378 :type n: int
379 :param l: 方位量子数 (1s軌道なので常に0)。
380 :type l: int
381 :param m: 磁気量子数 (1s軌道なので常に0)。
382 :type m: int
383 :returns: なし。グローバル変数yRr, yQr, qfuncを更新します。
384 :rtype: None
385 """
386 global yRr, yQr, qfunc
387
388 yRr = []
389 yQr = []
390 for i in range(len(r)):
391 yRr.append(Rr(ka, Z, n, l, m, r[i]))
392 if r[i] == 0.0:
393 Q = 0.0
394 else:
395 Q, errQ = integrate.quad(lambda r: pi4 * r * r * rho(ka, Z, n, l, m, r), 0, r[i], limit = nmaxdiv, epsrel = eps)
396 yQr.append(Ne * Q)
397 qfunc = interp1d(r, yQr, kind = 'cubic')
398
399def calTanal(Z = 1.0, ka = 1.0):
400 """
401 概要: H様原子の動径関数における運動エネルギーの解析解を計算します。
402
403 詳細説明:
404 この関数は、原子番号Zと指数係数kaを持つH様原子の1s軌道に対する運動エネルギーの
405 解析的な近似値をハートリー単位で計算します。
406 T = (ka*Z)^2 / 2 という関係に基づいています。
407
408 :param Z: 原子番号。デフォルトは1.0。
409 :type Z: float, optional
410 :param ka: 動径関数の指数部分の係数。デフォルトは1.0。
411 :type ka: float, optional
412 :returns: 運動エネルギーの解析解 (ハートリー単位)。
413 :rtype: float
414 """
415# T = e^2 / 8pi / e0 / a0
416 Tanal = Z * Z * ka * ka * e / 8.0 / pi / e0 / (a0*1.0e-10)
417 return Tanal
418
419def calUanal(Z = 1.0, ka = 1.0):
420 """
421 概要: H様原子の動径関数における核電子相互作用ポテンシャルエネルギーの解析解を計算します。
422
423 詳細説明:
424 この関数は、原子番号Zと指数係数kaを持つH様原子の1s軌道に対する
425 核と電子の間のポテンシャルエネルギーの解析的な近似値をハートリー単位で計算します。
426 U = -(ka*Z)^2 という関係に基づいています。
427
428 :param Z: 原子番号。デフォルトは1.0。
429 :type Z: float, optional
430 :param ka: 動径関数の指数部分の係数。デフォルトは1.0。
431 :type ka: float, optional
432 :returns: 核電子相互作用ポテンシャルエネルギーの解析解 (ハートリー単位)。
433 :rtype: float
434 """
435# U = -e^2 / 4pi / e0 / a0
436 Uanal = -Z * Z * ka * ka * e / 4.0 / pi / e0 / (a0*1.0e-10)
437 return Uanal
438
439
440def integrate_trapezoidal(func, E0, E1, h):
441 """
442 概要: 台形公式を用いて数値積分を行います。
443
444 詳細説明:
445 指定された関数 func を E0 から E1 までの範囲で、
446 ステップサイズ h を用いて台形公式で数値積分します。
447 この関数は現在使用されていませんが、将来的な高速化のために残されています。
448
449 :param func: 積分する関数。引数を一つ取る関数を想定。
450 :type func: callable
451 :param E0: 積分範囲の下限。
452 :type E0: float
453 :param E1: 積分範囲の上限。
454 :type E1: float
455 :param h: 積分ステップサイズ。
456 :type h: float
457 :returns: [積分の結果, エラー値 (ここでは常に-1.0)]
458 :rtype: list of float
459 """
460 n = int((E1 - E0) / h + 1.000001)
461 h = (E1 - E0) / n
462 y = [func(E0 + i * h) for i in range(n)]
463
464 S = 0.5 * (y[0] + y[n-1]) + sum(y[1:n-1])
465 return [h * S, -1.0]
466
467def integrate3DR(func, rmin, rmax, limit = 15, epsrel = 1.0e-8):
468 """
469 概要: 3次元空間における動径方向の積分 (4πr^2 func(r) dr) を行います。
470
471 詳細説明:
472 scipy.integrate.quad を使用して、球座標における体積要素 4pi * r*r を考慮した
473 動径方向の積分を実行します。
474
475 :param func: 積分する動径関数。引数を一つ取る関数を想定。
476 :type func: callable
477 :param rmin: 積分範囲の下限。
478 :type rmin: float
479 :param rmax: 積分範囲の上限。
480 :type rmax: float
481 :param limit: quad関数の最大サブインターバル数。デフォルトは15。
482 :type limit: int, optional
483 :param epsrel: quad関数の相対許容誤差。デフォルトは1.0e-8。
484 :type epsrel: float, optional
485 :returns: [積分の結果, 積分の絶対誤差]
486 :rtype: tuple of (float, float)
487 """
488 I, err = integrate.quad(lambda r: pi4 * r * r * func(r), rmin, rmax, limit, epsrel)
489 return I, err
490
491def calUZ(r, Z):
492 """
493 概要: 核電荷Zによって生成される静電ポテンシャル U_Z(r) を計算します。
494
495 詳細説明:
496 点電荷としての核が距離rに生成するクーロンポテンシャル -Z/r を計算します。
497 rが非常に小さい場合 (1.0e-3より小さい場合) は、数値的な安定性のために
498 -Z/1.0e-3を返します。
499
500 :param r: 核からの距離。
501 :type r: float
502 :param Z: 原子番号 (核電荷)。
503 :type Z: float
504 :returns: 核電荷Zによって生成される静電ポテンシャル。
505 :rtype: float
506 """
507 if r < 1.0e-3:
508 return -Z / 1.0e-3
509 else:
510 return -Z / r
511
512def calUrho(r, ka, Z, n, l, m):
513 """
514 概要: 電子密度 ρ(r) によって距離rに形成される静電ポテンシャル U_ee(r) を計算します。
515
516 詳細説明:
517 電子密度 ρ(r) が自身によって生成するポテンシャルを計算します。
518 これは以下の2つの部分から構成されます。
519 1. 距離rの内側にある電荷 Q(r) によるポテンシャル (Q(r)/r)。
520 2. 距離rの外側にある電荷が距離rに生成するポテンシャル (4pi * integ(rm * ρ(rm) drm, rから∞))。
521
522 :param r: 核からの距離。
523 :type r: float
524 :param ka: 動径関数の指数部分の係数。
525 :type ka: float
526 :param Z: 原子番号。
527 :type Z: float
528 :param n: 主量子数。
529 :type n: int
530 :param l: 方位量子数。
531 :type l: int
532 :param m: 磁気量子数。
533 :type m: int
534 :returns: 電子密度 ρ(r) によって距離rに形成される静電ポテンシャル。
535 :rtype: float
536 """
537# Uerho(r) = integ(rho(m) / |r-rm|)_[rm=0, inf] [r, rm are vectors]
538# = Q(r) / r + integ[4pi * rm * rm * rho(rm) / rm]_[rm = r, inf]) [r is vector]
539 if r == 0.0:
540 Uee1 = 0.0
541 else:
542 Uee1 = calQ(r) / r
543
544 Rmaxint = Rmax
545# Rmaxint = min(-log(eps) / Z / ka, Rmax)
546 Uee2, errUee2 = integrate.quad(lambda rm: pi4 * rm * rho(ka, Z, n, l, m, rm), r, Rmaxint, limit = nmaxdiv, epsrel = eps)
547 return Uee1 + Uee2
548# return Uee1 + Ne * Uee2
549
550def calT(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
551 """
552 概要: 電子系の運動エネルギーを計算します。
553
554 詳細説明:
555 シュレーディンガー方程式の運動エネルギー演算子 (-1/2)∇^2 に基づいて、
556 H-like 1s軌道の電子の運動エネルギーを数値積分によって計算します。
557 積分の範囲は Rmin から Rmaxint (実質的には∞) です。
558 内部でグローバル変数 R1s0 を使用しますが、この変数はこのスクリプト内で定義されていません。
559
560 :param ka: 動径関数の指数部分の係数。
561 :type ka: float
562 :param Z: 原子番号。
563 :type Z: float
564 :param n: 主量子数。
565 :type n: int
566 :param l: 方位量子数。
567 :type l: int
568 :param m: 磁気量子数。
569 :type m: int
570 :param Ne: 電子数。
571 :type Ne: float
572 :param Rmin: 積分範囲の最小半径。
573 :type Rmin: float
574 :param Rmax: 積分範囲の最大半径(上限)。
575 :type Rmax: float
576 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
577 :type nmaxdiv: int
578 :param eps: scipy.integrate.quad の相対許容誤差。
579 :type eps: float
580 :returns: [運動エネルギー, 積分の絶対誤差]
581 :rtype: tuple of (float, float)
582 """
583 Rmaxint = min(-log(eps) / Z / ka, Rmax)
584 T, errT = integrate.quad(lambda r: r * (2.0 - Z * ka * r) * exp(-2.0 * Z * ka * r),
585 Rmin, Rmaxint, limit = nmaxdiv, epsrel = eps)
586 T *= 1.0 / 2.0 * pi4 * Z * ka * R1s0 * R1s0 * pow(ka * Z, 3.0)
587 return T, errT
588
589def calUeZ(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
590 """
591 概要: 電子と原子核間の引力ポテンシャルエネルギー U_eZ を計算します。
592
593 詳細説明:
594 電子密度 ρ(r) と核電荷 Z の間のクーロン引力によるポテンシャルエネルギーを
595 数値積分によって計算します。積分は Rmin から Rmaxint (実質的には∞) です。
596
597 :param ka: 動径関数の指数部分の係数。
598 :type ka: float
599 :param Z: 原子番号。
600 :type Z: float
601 :param n: 主量子数。
602 :type n: int
603 :param l: 方位量子数。
604 :type l: int
605 :param m: 磁気量子数。
606 :type m: int
607 :param Ne: 電子数。
608 :type Ne: float
609 :param Rmin: 積分範囲の最小半径。
610 :type Rmin: float
611 :param Rmax: 積分範囲の最大半径(上限)。
612 :type Rmax: float
613 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
614 :type nmaxdiv: int
615 :param eps: scipy.integrate.quad の相対許容誤差。
616 :type eps: float
617 :returns: [電子と原子核間の引力ポテンシャルエネルギー, 積分の絶対誤差]
618 :rtype: tuple of (float, float)
619 """
620 Rmaxint = min(-log(eps) / Z / ka, Rmax)
621 UeZ, errUeZ = integrate.quad(lambda r: pi4 * r * rho(ka, Z, n, l, m, r),
622 Rmin, Rmaxint, limit = nmaxdiv, epsrel = eps)
623 UeZ *= -Z
624 return UeZ, errUeZ
625
626def calUee(mode, ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
627 """
628 概要: 電子間のクーロン反発ポテンシャルエネルギー U_ee を計算します。
629
630 詳細説明:
631 電子密度 ρ(r) によって生成される静電ポテンシャル U_rho(r) と ρ(r) の積を
632 全空間で積分することにより、電子間のクーロン反発エネルギーを計算します。
633 mode に 'e' が含まれる場合、全エネルギー計算モードとして Ne*Ne 倍、
634 それ以外の場合は Ne 倍します。
635
636 :param mode: 現在の実行モードを示す文字列('e'が含まれるかでスケールが変わる)。
637 :type mode: str
638 :param ka: 動径関数の指数部分の係数。
639 :type ka: float
640 :param Z: 原子番号。
641 :type Z: float
642 :param n: 主量子数。
643 :type n: int
644 :param l: 方位量子数。
645 :type l: int
646 :param m: 磁気量子数。
647 :type m: int
648 :param Ne: 電子数。
649 :type Ne: float
650 :param Rmin: 積分範囲の最小半径。
651 :type Rmin: float
652 :param Rmax: 積分範囲の最大半径(上限)。
653 :type Rmax: float
654 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
655 :type nmaxdiv: int
656 :param eps: scipy.integrate.quad の相対許容誤差。
657 :type eps: float
658 :returns: [電子間のクーロン反発ポテンシャルエネルギー, 積分の絶対誤差]
659 :rtype: tuple of (float, float)
660 """
661 Rmaxint = min(-log(eps) / Z / ka, Rmax)
662 Uee, errUee = integrate.quad(lambda r: pi4 * r * r * calUrho(r, ka, Z, n, l, m) * rho(ka, Z, n, l, m, r),
663 Rmin, Rmaxint, limit = nmaxdiv, epsrel = eps)
664 if 'e' in mode:
665 Uee *= Ne * Ne
666 else:
667 Uee *= Ne
668
669 return Uee, errUee
670
671def calLocalUXa(r, ka, Z, n, l, m, Ne):
672 """
673 概要: スレーターのX-α交換ポテンシャル (局所形式) を計算します。
674
675 詳細説明:
676 距離rにおけるスレーターのX-α交換ポテンシャルの局所形式 -3.0 * alpha * (3/(4pi) * ρ(r))^(1/3)
677 を計算します。
678
679 :param r: 核からの距離。
680 :type r: float
681 :param ka: 動径関数の指数部分の係数。
682 :type ka: float
683 :param Z: 原子番号。
684 :type Z: float
685 :param n: 主量子数。
686 :type n: int
687 :param l: 方位量子数。
688 :type l: int
689 :param m: 磁気量子数。
690 :type m: int
691 :param Ne: 電子数 (この関数では直接使用されないが引数として存在)。
692 :type Ne: float
693 :returns: 距離rにおけるX-α交換ポテンシャルの値。
694 :rtype: float
695 """
696 return -3.0 * alpha * pow(3.0/pi4 * rho(ka, Z, n, l, m, r), 1.0/3.0)
697
698def calUXa(mode, ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
699 """
700 概要: X-α交換エネルギーを計算します。
701
702 詳細説明:
703 スレーターのX-α交換ポテンシャル calLocalUXa(r) と電子密度 rho(r) の積を
704 全空間で積分することにより、X-α交換エネルギーを計算します。
705 mode に 'e' が含まれる場合、全エネルギー計算モードとして Ne^(4/3) 倍、
706 それ以外の場合は Ne^(1/3) 倍します。
707
708 :param mode: 現在の実行モードを示す文字列('e'が含まれるかでスケールが変わる)。
709 :type mode: str
710 :param ka: 動径関数の指数部分の係数。
711 :type ka: float
712 :param Z: 原子番号。
713 :type Z: float
714 :param n: 主量子数。
715 :type n: int
716 :param l: 方位量子数。
717 :type l: int
718 :param m: 磁気量子数。
719 :type m: int
720 :param Ne: 電子数。
721 :type Ne: float
722 :param Rmin: 積分範囲の最小半径。
723 :type Rmin: float
724 :param Rmax: 積分範囲の最大半径(上限)。
725 :type Rmax: float
726 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
727 :type nmaxdiv: int
728 :param eps: scipy.integrate.quad の相対許容誤差。
729 :type eps: float
730 :returns: [X-α交換エネルギー, 積分の絶対誤差]
731 :rtype: tuple of (float, float)
732 """
733 Rmaxint = min(-log(eps) / Z / ka, Rmax)
734 UXa, errUXa = integrate.quad(lambda r: pi4 * r * r * calLocalUXa(r, ka, Z, n, l, m, Ne) * rho(ka, Z, n, l, m, r),
735 Rmin, Rmaxint, limit = nmaxdiv, epsrel = eps)
736 if 'e' in mode:
737 UXa *= pow(Ne, 4.0/3.0)
738 else:
739 UXa *= pow(Ne, 1.0/3.0)
740
741 return UXa, errUXa
742
743def calTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
744 """
745 概要: H-like 1s軌道の全エネルギーを計算します。
746
747 詳細説明:
748 運動エネルギー (T)、核電子引力エネルギー (UeZ)、電子間反発エネルギー (Uee)、
749 およびX-α交換エネルギー (UXa) の各項を計算し、それらを合計して全エネルギーを求めます。
750 build_Qr を呼び出して Q(r) 分布を事前に構築します。
751
752 :param ka: 動径関数の指数部分の係数。
753 :type ka: float
754 :param Z: 原子番号。
755 :type Z: float
756 :param n: 主量子数。
757 :type n: int
758 :param l: 方位量子数。
759 :type l: int
760 :param m: 磁気量子数。
761 :type m: int
762 :param Ne: 電子数。
763 :type Ne: float
764 :param Rmin: 積分範囲の最小半径。
765 :type Rmin: float
766 :param Rmax: 積分範囲の最大半径(上限)。
767 :type Rmax: float
768 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
769 :type nmaxdiv: int
770 :param eps: scipy.integrate.quad の相対許容誤差。
771 :type eps: float
772 :returns: [運動エネルギーT, 核電子引力エネルギーUeZ, 電子間反発エネルギーUee, X-α交換エネルギーUXa, 全エネルギーEtot]
773 :rtype: tuple of (float, float, float, float, float)
774 """
775 build_Qr(ka, Z, n, l, m)
776
777#def calT(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
778 T, errT = calT(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
779 UeZ, errUeZ = calUeZ(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
780 Uee, errUee = calUee(mode, ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
781 UXa, errUXa = calUXa(mode, ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
782 Etot = T + UeZ + Uee + UXa
783
784 return T, UeZ, Uee, UXa, Etot
785
786def calTotalEnergyOnly(kav, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
787 """
788 概要: 変分計算のために、特定のka値におけるH-like 1s軌道の全エネルギーを計算します。
789
790 詳細説明:
791 この関数は calTotalEnergy と同様に全エネルギーを計算しますが、
792 最適化ルーチン (minimize) から呼び出されることを想定し、
793 引数として与えられた kav を使用し、最終的な全エネルギー値のみを返します。
794 また、電子間反発エネルギー (Uee) とX-α交換エネルギー (UXa) の計算モードは
795 常に全エネルギー計算 ('e'モード) として扱われます。
796
797 :param kav: 変分パラメータとして使用される動径関数の指数部分の係数。
798 :type kav: float
799 :param Z: 原子番号。
800 :type Z: float
801 :param n: 主量子数。
802 :type n: int
803 :param l: 方位量子数。
804 :type l: int
805 :param m: 磁気量子数。
806 :type m: int
807 :param Ne: 電子数。
808 :type Ne: float
809 :param Rmin: 積分範囲の最小半径。
810 :type Rmin: float
811 :param Rmax: 積分範囲の最大半径(上限)。
812 :type Rmax: float
813 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
814 :type nmaxdiv: int
815 :param eps: scipy.integrate.quad の相対許容誤差。
816 :type eps: float
817 :returns: 計算された全エネルギー。
818 :rtype: float
819 """
820 build_Qr(kav, Z, n, l, m)
821
822 T, errT = calT(kav, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
823 UeZ, errUeZ = calUeZ(kav, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
824 Uee, errUee = calUee('e', kav, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
825 UXa, errUXa = calUXa('e', kav, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
826 Etot = T + UeZ + Uee + UXa
827
828 return Etot
829
830def calOptimizedTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps):
831 """
832 概要: 変分法を用いて全エネルギーを最小化するka値を探索し、そのときの全エネルギーと各エネルギー成分を計算します。
833
834 詳細説明:
835 scipy.optimize.minimize 関数を使用して、動径関数の指数係数 ka を変分パラメータとして、
836 calTotalEnergyOnly で計算される全エネルギーを最小化します。
837 指定された最適化手法 (method) とパラメータ (tol, maxiter) に基づいて探索を行い、
838 最小化された ka とそのときの各エネルギー成分、および全エネルギーを返します。
839
840 :param ka: 最適化の初期値となる動径関数の指数部分の係数。
841 :type ka: float
842 :param Z: 原子番号。
843 :type Z: float
844 :param n: 主量子数。
845 :type n: int
846 :param l: 方位量子数。
847 :type l: int
848 :param m: 磁気量子数。
849 :type m: int
850 :param Ne: 電子数。
851 :type Ne: float
852 :param Rmin: 積分範囲の最小半径。
853 :type Rmin: float
854 :param Rmax: 積分範囲の最大半径(上限)。
855 :type Rmax: float
856 :param nmaxdiv: scipy.integrate.quad の最大サブインターバル数。
857 :type nmaxdiv: int
858 :param eps: scipy.integrate.quad の相対許容誤差。
859 :type eps: float
860 :returns: [運動エネルギーT, 核電子引力エネルギーUeZ, 電子間反発エネルギーUee, X-α交換エネルギーUXa, 最小化された全エネルギーEtot, 最適化されたka値]
861 :rtype: tuple of (float, float, float, float, float, float)
862 """
863 xa = [ka]
864 ret = minimize(lambda xa: calTotalEnergyOnly(xa[0], Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps),
865 xa, method = method, jac = diff1, tol = tol,
866 callback = lambda xa: callback(xa),
867 options = {'maxiter':maxiter, "disp":True})
868# print("ret=", ret)
869 if method == 'nelder-mead':
870 simplex = ret['final_simplex']
871 ai = simplex[0][0]
872 Emin = ret['fun']
873 elif method == 'cg':
874 ai = ret['x']
875 Emin = ret['fun']
876 elif method == 'powell':
877 ai = ret['x']
878 Emin = ret['fun']
879 elif method == 'bfgs':
880 ai = ret['x']
881 ka = xa[0]
882 Emin = calTotalEnergyOnly(xa[0], Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
883
884 ka = ai[0]
885 T, UeZ, Uee, UXa, Etot = calTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
886
887 return T, UeZ, Uee, UXa, Etot, ka
888
889
890def diff1(ai):
891 """
892 概要: 1変数関数の勾配 (1次導関数) を中心差分法で近似します。
893
894 詳細説明:
895 scipy.optimize.minimize の勾配情報が必要なメソッド (cgなど) のために、
896 パラメータ ai (ここでは ka) の微小変化 h_diff を用いて、
897 calTotalEnergyOnly 関数に対する1次導関数を数値的に計算します。
898
899 :param ai: 最適化される変数の現在の値 (ここでは ka の配列)。
900 :type ai: numpy.ndarray
901 :returns: 各変数に対する1次導関数の配列。
902 :rtype: numpy.ndarray
903 """
904 global Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps
905
906 n = len(ai)
907 f0 = calTotalEnergyOnly(ai[0], Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
908 df = np.empty(n)
909 for i in range(n):
910 aii = ai
911 aii[i] = ai[i] + h_diff
912 f1 = calTotalEnergyOnly(aii[0], Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
913 df[i] = (f1 - f0) / h_diff
914 return df
915
916iter = 0
917def callback(xk):
918 """
919 概要: 最適化の各イテレーションで呼び出され、進行状況を表示します。
920
921 詳細説明:
922 scipy.optimize.minimize 関数の callback オプションとして使用されます。
923 各イテレーションで現在のパラメータ xk (ここでは ka) と
924 それに対応する全エネルギー Etot を表示します。
925
926 :param xk: 現在のイテレーションでの最適化変数の値 (ここでは ka の配列)。
927 :type xk: numpy.ndarray
928 :returns: なし
929 :rtype: None
930 """
931 global iter
932 global Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps
933
934 ka = xk[0]
935 Etot = calTotalEnergyOnly(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
936
937# パラメータと残差二乗和を表示
938 print("callback {}: ka={:14.4g} Emin={} eV".format(iter, ka, Etot * HartreeToeV))
939 iter += 1
940
941
942def sweep_Ne(Eanal):
943 """
944 概要: 電子数Neを掃引し、非最適化および最適化された全エネルギーの変化を評価・プロットします。
945
946 詳細説明:
947 Nearray に定義された様々な電子数Neに対して、固定された ka での全エネルギー、
948 および変分法で ka を最適化した上での全エネルギーを計算します。
949 また、Ne=0.5付近での放物線近似も行い、結果を表形式で出力し、グラフとしてプロットします。
950 特に 'v' モードが有効な場合、ka の最適化も行います。
951
952 :param Eanal: 比較のための解析解エネルギー値。
953 :type Eanal: float
954 :returns: なし
955 :rtype: None
956 """
957 global Rmin, Rstep, nR, Rmaxdata, r
958 global ka
959 global qfunc
960
961 print("")
962 print("Not optimized")
963
964 print(" Parabolic expantion around Ne = 0.5")
965 Tp, UeZp, Ueep, UXap, Etotp = calTotalEnergy(ka, Z, n, l, m, 0.5 + hparab, Rmin, Rmax, nmaxdiv, eps)
966 T0, UeZ0, Uee0, UXa0, Etot0 = calTotalEnergy(ka, Z, n, l, m, 0.5 , Rmin, Rmax, nmaxdiv, eps)
967 Tm, UeZm, Ueem, UXam, Etotm = calTotalEnergy(ka, Z, n, l, m, 0.5 - hparab, Rmin, Rmax, nmaxdiv, eps)
968 Etotp *= HartreeToeV
969 Etot0 *= HartreeToeV
970 Etotm *= HartreeToeV
971 print(" Ne={}: E={} eV".format(0.5 + hparab, Etotp))
972 print(" Ne={}: E={} eV".format(0.5 , Etot0))
973 print(" Ne={}: E={} eV".format(0.5 - hparab, Etotm))
974 a2 = (Etotp - 2.0 * Etot0 + Etotm) / hparab / hparab
975 a1 = (Etotp - Etotm) / 2.0 / hparab
976 print(" E = {} + {} * Ne + {} * Ne^2".format(Etot0, a1, a2))
977
978 xNe = []
979 yE1s = []
980 yE1sparab = []
981 print("")
982 print("{:6s}\t{:6s}\t{:6s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}"
983 .format('ka', 'Z', 'Ne', 'T in eV', 'U(e-Z)', 'U(e-e)', 'U(Xa)',
984 ELabel, ELabel + ' (parabolic)'))
985 for Ne in Nearray:
986 T, UeZ, Uee, UXa, Etot = calTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
987 Eparab = Etot0 + a1 * (Ne - 0.5) + a2 * pow(Ne - 0.5, 2)
988 print("{:6.4f}\t{:6.4f}\t{:6.4f}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}"
989 .format(ka, Z, Ne,
990 T * HartreeToeV, UeZ * HartreeToeV, Uee * HartreeToeV, UXa * HartreeToeV,
991 Etot * HartreeToeV, Eparab))
992 xNe.append(Ne)
993 yE1s.append(Etot * HartreeToeV)
994 yE1sparab.append(Eparab)
995
996 if 'v' in mode:
997 yE1sOpt = []
998 yE1sOptparab = []
999 ykaOpt = []
1000 print("")
1001 print("Optimized for ka by variational principle")
1002
1003 print(" Parabolic expantion around Ne = 0.5")
1004 Tp, UeZp, Ueep, UXap, Etotp, kap = calOptimizedTotalEnergy(ka, Z, n, l, m, 0.5 + hparab, Rmin, Rmax, nmaxdiv, eps)
1005 T0, UeZ0, Uee0, UXa0, Etot0, ka0 = calOptimizedTotalEnergy(ka, Z, n, l, m, 0.5 , Rmin, Rmax, nmaxdiv, eps)
1006 Tm, UeZm, Ueem, UXam, Etotm, kam = calOptimizedTotalEnergy(ka, Z, n, l, m, 0.5 - hparab, Rmin, Rmax, nmaxdiv, eps)
1007 Etotp *= HartreeToeV
1008 Etot0 *= HartreeToeV
1009 Etotm *= HartreeToeV
1010 print(" Ne={}: E={} eV".format(0.5 + hparab, Etotp))
1011 print(" Ne={}: E={} eV".format(0.5 , Etot0))
1012 print(" Ne={}: E={} eV".format(0.5 - hparab, Etotm))
1013 a2 = (Etotp - 2.0 * Etot0 + Etotm) / hparab / hparab
1014 a1 = (Etotp - Etotm) / 2.0 / hparab
1015 print(" E = {} + {} * Ne + {} * Ne^2".format(Etot0, a1, a2))
1016
1017 print("{:6s}\t{:6s}\t{:6s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}"
1018 .format('ka', 'Z', 'Ne', 'T in eV', 'U(e-Z)', 'U(e-e)', 'U(Xa)', ELabel, ELabel + ' (parabolic)'))
1019 for Ne in Nearray:
1020 T, UeZ, Uee, UXa, Etot, ka = calOptimizedTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
1021 Eparab = Etot0 + a1 * (Ne - 0.5) + a2 * pow(Ne - 0.5, 2)
1022 print("{:6.4f}\t{:6.4f}\t{:6.4g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}t{:10.6g}"
1023 .format(ka, Z, Ne,
1024 T * HartreeToeV, UeZ * HartreeToeV, Uee * HartreeToeV, UXa * HartreeToeV,
1025 Etot * HartreeToeV, Eparab))
1026
1027 yE1sOpt.append(Etot * HartreeToeV)
1028 yE1sOptparab.append(Eparab)
1029 ykaOpt.append(ka)
1030
1031#=============================
1032# Plot graphs
1033#=============================
1034 if 'g' not in mode:
1035 terminate()
1036
1037 fig = plt.figure(figsize = (12, 8))
1038
1039 ax1 = fig.add_subplot(1, 2, 1)
1040 ax2 = fig.add_subplot(1, 2, 2)
1041# ax3 = fig.add_subplot(2, 3, 3)
1042# ax4 = fig.add_subplot(2, 3, 4)
1043# ax5 = fig.add_subplot(2, 3, 5)
1044 ax1.plot(xNe, yE1s, label = ELabel + ' (non-optimized)', color = 'black', linewidth = 1.5, marker = 'o', markersize = 1.0)
1045 ax1.plot(xNe, yE1sparab, label = ELabel + ' (non-opt,parabolic)', color = 'black', linestyle = 'dashed', linewidth = 0.5)
1046 if 'v' in mode:
1047 ax1.plot(xNe, yE1sOpt, label = ELabel + ' (optimized)', color = 'red', linewidth = 1.5, marker = 'o', markersize = 1.0)
1048 ax1.plot(xNe, yE1sOptparab, label = ELabel + ' (opt,parabolic)', color = 'red', linewidth = 0.5)
1049 ax1.plot([min(xNe), max(xNe)], [Eanal, Eanal], color = 'red', linestyle = 'dashed')
1050 ax1.plot([0.5, 0.5], [min(yE1s), max(yE1s)], color = 'red', linestyle = 'dashed')
1051 ax1.set_xlabel("Ne")
1052 ax1.set_ylabel(ELabel + " (eV)")
1053 ax1.legend()
1054 if 'v' in mode:
1055 ax2.plot(xNe, ykaOpt, label = 'ka (optimized)', color = 'black', linewidth = 0.5, marker = 'o', markersize = 1.0)
1056 ax2.plot([min(xNe), max(xNe)], [1.0, 1.0], color = 'red', linestyle = 'dashed')
1057 if 'v' in mode:
1058 ax2.plot([0.5, 0.5], [min(ykaOpt), max(ykaOpt)], color = 'red', linestyle = 'dashed')
1059 ax2.set_xlabel("Ne")
1060 ax2.set_ylabel("ka (optimized)")
1061 ax2.legend()
1062
1063 plt.tight_layout()
1064 plt.pause(0.1)
1065
1066 print("Press ENTER to exit>>", end = '')
1067 input()
1068
1069
1070def sweep_ka(Eanal):
1071 """
1072 概要: 動径関数の指数係数kaを掃引し、全エネルギーの変化を評価・プロットします。
1073
1074 詳細説明:
1075 kaarray に定義された様々な ka の値に対して、
1076 H-like 1s軌道の全エネルギーとその各成分を計算します。
1077 結果を表形式で出力し、'g' モードが有効な場合はグラフとしてプロットします。
1078
1079 :param Eanal: 比較のための解析解エネルギー値。
1080 :type Eanal: float
1081 :returns: なし
1082 :rtype: None
1083 """
1084 global Rmin, Rstep, nR, Rmaxdata, r
1085 global qfunc
1086 global nmaxdiv, eps
1087
1088 xka = []
1089 yE1s = []
1090 print("")
1091 print("{:6s}\t{:6s}\t{:6s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}"
1092 .format('ka', 'Z', 'Ne', 'T in eV', 'U(e-Z)', 'U(e-e)', 'U(Xa)', ELabel))
1093 for kav in kaarray:
1094 T, UeZ, Uee, UXa, Etot = calTotalEnergy(kav, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
1095 print("{:6.4f}\t{:6.4f}\t{:6.4f}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}"
1096 .format(kav, Z, Ne,
1097 T * HartreeToeV, UeZ * HartreeToeV, Uee * HartreeToeV, UXa * HartreeToeV, Etot * HartreeToeV))
1098 xka.append(kav)
1099 yE1s.append(Etot * HartreeToeV)
1100
1101#=============================
1102# Plot graphs
1103#=============================
1104 if 'g' not in mode:
1105 terminate()
1106
1107 fig = plt.figure(figsize = (12, 8))
1108
1109 ax1 = fig.add_subplot(2, 3, 1)
1110 ax2 = fig.add_subplot(2, 3, 2)
1111 ax3 = fig.add_subplot(2, 3, 3)
1112 ax4 = fig.add_subplot(2, 3, 4)
1113 ax5 = fig.add_subplot(2, 3, 5)
1114 ax1.plot(xka, yE1s, label = ELabel, color = 'black', marker = 'o')
1115 ax1.plot([min(xka), max(xka)], [Eanal, Eanal], color = 'red', linestyle = 'dashed')
1116 ax1.set_xlabel("ka")
1117 ax1.set_ylabel(ELabel + " (eV)")
1118 ax1.legend()
1119
1120 plt.tight_layout()
1121 plt.pause(0.1)
1122
1123 print("Press ENTER to exit>>", end = '')
1124 input()
1125
1126def debug(Eanal):
1127 """
1128 概要: デバッグモードで、H-like 1s軌道の計算結果と関連するグラフを表示します。
1129
1130 詳細説明:
1131 現在のパラメータ (ka, Z, Ne など) における運動エネルギー、核電子引力エネルギー、
1132 電子間反発エネルギー、X-α交換エネルギー、および全エネルギーを計算し、表形式で出力します。
1133 'v' モードが有効な場合は、ka を最適化した結果も表示します。
1134 また、'g' モードが有効な場合は、動径関数 Rr(r)、電荷分布 Q(r)、および各種ポテンシャル
1135 (U(Z), U(Z-rho), U(rho), U(Xa)) のグラフをプロットします。
1136
1137 :param Eanal: 比較のための解析解エネルギー値。
1138 :type Eanal: float
1139 :returns: なし
1140 :rtype: None
1141 """
1142 global ka, Z, n, l, m, Ne
1143 global Rmin, Rstep, nR, Rmaxdata, r
1144
1145 ka0, Z0 = ka, Z
1146
1147 print("")
1148 print("{:6s}\t{:6s}\t{:6s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}"
1149 .format('ka', 'Z', 'Ne', 'T in eV', 'U(e-Z)', 'U(e-e)', 'U(Xa)', ELabel))
1150 T, UeZ, Uee, UXa, Etot = calTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
1151 print("{:6.4f}\t{:6.4f}\t{:6.4f}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}"
1152 .format(ka, Z, Ne,
1153 T * HartreeToeV, UeZ * HartreeToeV, Uee * HartreeToeV, UXa * HartreeToeV, Etot * HartreeToeV))
1154
1155 if 'v' in mode:
1156 print("")
1157 print("Optimized for ka by variational principle")
1158
1159 print("{:6s}\t{:6s}\t{:6s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}\t{:10s}"
1160 .format('ka', 'Z', 'Ne', 'T in eV', 'U(e-Z)', 'U(e-e)', 'U(Xa)', ELabel))
1161 T, UeZ, Uee, UXa, Etot, ka = calOptimizedTotalEnergy(ka, Z, n, l, m, Ne, Rmin, Rmax, nmaxdiv, eps)
1162 print("{:6.4f}\t{:6.4f}\t{:6.4f}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}\t{:10.6g}"
1163 .format(ka, Z, Ne,
1164 T * HartreeToeV, UeZ * HartreeToeV, Uee * HartreeToeV, UXa * HartreeToeV, Etot * HartreeToeV))
1165
1166#=============================
1167# Plot graphs
1168#=============================
1169 if 'g' not in mode:
1170 terminate()
1171
1172 build_Qr(ka0, Z, n, l, m)
1173
1174 ypotZ = [] # U(Z) = -Z/r
1175 ypotZrho = [] # U(e-Z) for Z = 1
1176 ypotXa = [] # Xa potential
1177 ypotrho = [] # Electrostatic potential by rho(r)
1178 for i in range(len(r)):
1179 if r[i] == 0.0:
1180 phi = 0.0
1181 else:
1182 phi, errpot = integrate.quad(lambda r: pi4 * r * rho(ka, Z, n, l, m, r),
1183 Rmin, r[i], limit = nmaxdiv, epsrel = eps)
1184 potZ = -Z / r[i]
1185 ypotZ.append(calUZ(r[i], Z))
1186 ypotZrho.append(-Z * Ne * phi)
1187 ypotrho.append(Ne * calUrho(r[i], ka, Z, n, l, m))
1188 ypotXa.append(calLocalUXa(r[i], ka, Z, n, l, m, 1.0))
1189
1190 fig = plt.figure(figsize = (12, 8))
1191
1192 ax1 = fig.add_subplot(2, 3, 1)
1193 ax2 = fig.add_subplot(2, 3, 2)
1194 ax3 = fig.add_subplot(2, 3, 3)
1195 ax1.plot(r, yRr, label = 'Rr(r)', color = 'black')
1196 ax1.set_xlim([Rmin, Rmax])
1197 ax1.set_ylim([0, max(yRr)*1.1])
1198 ax1.set_xlabel("r (bohr)")
1199 ax1.set_ylabel("Rr(r)")
1200 ax1.legend()
1201 ax2.plot(r, yQr, label = 'Q(r)', color = 'black')
1202 ax2.set_xlabel("r (bohr)")
1203 ax2.set_ylabel("Q(r)")
1204 ax2.legend()
1205 ax3.plot(r, ypotZ, label = 'U(Z)', color = 'black')
1206 ax3.plot(r, ypotZrho, label = 'U(Z-rho)', color = 'red')
1207 ax3.plot(r, -np.array(ypotrho), label = '-U(rho)', color = 'blue')
1208 ax3.plot(r, ypotXa, label = 'U(Xa)', color = 'green')
1209 ax3.set_ylim([min(ypotXa) * 5.0, 0.0])
1210 ax3.set_xlabel("r (bohr)")
1211 ax3.set_ylabel("Potential / Energy (Hartree)")
1212 ax3.legend()
1213
1214 plt.tight_layout()
1215 plt.pause(0.1)
1216
1217 print("Press ENTER to exit>>", end = '')
1218 input()
1219
1220
1221def main():
1222 """
1223 概要: プログラムのメインエントリポイントです。
1224
1225 詳細説明:
1226 コマンドライン引数を解析し、グローバル変数を更新します。
1227 水素様原子の解析解エネルギーを計算した後、
1228 指定されたモードに基づいて異なる計算(デバッグ、ka掃引、Ne掃引)を実行します。
1229 最後に、動径関数の正規化チェックも行います。
1230
1231 :returns: なし
1232 :rtype: None
1233 """
1234 global mode
1235 global ka, Z, n, l, m, Ne
1236 global Rmin, Rstep, nR, Rmaxdata, r
1237 global qfunc
1238
1239 updatevars()
1240
1241 Rstep = (Rmax - Rmin) / (nR - 1)
1242 r = [Rmin + i * Rstep for i in range(nR+100)]
1243 Rmaxdata = max(r)
1244
1245 print("")
1246 print("mode: ", mode)
1247 print("")
1248 print("Orbital: ka={} Z={} n={} l={} m={}".format(ka, Z, n, l, m))
1249 print("Ne: ", Ne)
1250 print("Integration: Rmax=", Rmax)
1251 print(" Rmax: epsR={} Rmaxinteg={}".format(epsR, -log(epsR) / Z / ka))
1252
1253 print("")
1254 print("Analytical solution")
1255
1256 Tanal = calTanal(Z, ka)
1257 Uanal = calUanal(Z, ka)
1258 Eanal = Tanal + Uanal
1259 print("T(analytical) = {} eV".format(Tanal))
1260 print("U(analytical) = {} eV".format(Uanal))
1261 print(" Etotl(analytical) = {} eV".format(Eanal))
1262
1263 print("")
1264 print("Numerical integration")
1265 Rr2tot, err = integrate.quad(lambda r: r * r * rho(ka, Z, n, l, m, r), Rmin, Rmax, limit = nmaxdiv, epsrel = eps)
1266 Rr2tot *= pi4
1267 print("R(r) normalization check: 2pi * integ(r*r * Rr*2)dr = ", Rr2tot)
1268
1269 if 'd' in mode:
1270 debug(Eanal)
1271 if 'k' in mode:
1272 sweep_ka(Eanal)
1273 if 'n' in mode:
1274 sweep_Ne(Eanal)
1275
1276 terminate()
1277
1278
1279if __name__ == '__main__':
1280 usage()
1281 main()