tkWavefunction_H.py ダウンロード/コピー
tkWavefunction_H.py
tkWavefunction_H.py
1"""
2水素原子の波動関数とエネルギー準位の計算モジュール
3
4関連リンク:
5:doc:`tkWavefunction_H_usage`
6"""
7
8#https://zenn.dev/shittoku_xxx/articles/061ad99166afcc
9
10import re
11import math
12import numpy as np
13from numpy import abs, exp, sqrt, cos, sin, arccos, arctan2, angle, pi
14from scipy.special import factorial
15try:
16 from scipy.special import sph_harm_y as sph_harm
17except ImportError:
18 from scipy.special import sph_harm
19from scipy.constants import physical_constants
20
21
22# 定数
23a0 = physical_constants['Bohr radius'][0] * 1e10 # Bohr半径。オングストローム単位に変換
24#a_0 = 4 * np.pi * epsilon_0 * h_bar**2 / (m_e * e**2) # ボーア半径 (m)
25h = 6.62607015e-34 # プランク定数 (J·s)
26h_bar = h / (2.0 * pi) # ディラック定数 (J·s)
27m_e = 9.10938356e-31 # 電子の質量 (kg)
28e = 1.602176634e-19 # 電子の電荷 (C)
29e0 = 8.854187817e-12 # 真空の誘電率 (F/m)
30pi = np.pi
31
32# エネルギー準位を計算する関数
33def En(n):
34 """
35 主量子数に対する水素原子のエネルギー準位を計算する。
36
37 :param n: int, 主量子数
38 :returns: float, エネルギー準位 (eV)
39 """
40 E = - (m_e * e**4) / (8 * e0**2 * h**2) / n**2
41 return E / e
42
43def get_orb_name(n, l, m):
44 """
45 量子数から軌道の名前(例: '1s', '2px'など)を取得する。
46
47 :param n: int, 主量子数
48 :param l: int または str, 方位量子数
49 :param m: int または str, 磁気量子数
50 :returns: str, 軌道名
51 """
52 print(n,l,m)
53 names1 = ['s'] # for l=0
54 names2 = ['py', 'pz', 'px'] # for l=1, m=-1, 0, 1
55 names3 = ['dxy', 'dyz', 'd3z2-r2', 'dzx', 'dx2-y2'] # for l=2, m=-2,-1,0,1,2
56 names4 = ['fy(3x2-y2)', 'fxyz', 'fy(5z2-r2)', 'fz(5z2-3r2)',
57 'fx(5z2-r2)', 'fz(x2-y2)', 'fx(x2-3y2)'] # for l=3, m=-3,-2,-1,0,1,2,3
58 names = [names1, names2, names3, names4]
59
60 if type(l) is str:
61 pNames = l
62 else:
63 pNames = names[l]
64
65 if type(m) == str:
66 name = l + m
67 else:
68 name = pNames[m + l]
69
70 return f"{n}{name}"
71
72def get_qnumbers(n, l, m):
73 """
74 軌道を表す文字列または数値から量子数(n, l, m)の組を取得する。
75
76 :param n: int, 主量子数
77 :param l: int または str, 方位量子数
78 :param m: int または str, 磁気量子数
79 :returns: tuple, (n, l, m) の量子数の組
80 """
81 qnumber_l = {"s": 0, "p": 1, "d": 2, "f": 3, "g": 4}
82 qnumber_m = {"": 0,
83 "x": 1, "y": -1, "z": 0,
84 "xy+": 1, "xy-": -1,
85 "xy": -2, "yz": -1, "z2": 0, "zx": 1, "x2-y2": 2,
86 "y(3x2-y2)": -3, "xyz": -2, "y(5z2-r2)": -1,
87 "z(5z2-3r2)": 0, "x(5z2-r2)": 1, "z(x2-y2)": 2, "x(x2-3y2)": 3}
88
89 if type(l) is str:
90 l = qnumber_l.get(l, None)
91 if type(m) is str:
92 m = qnumber_m.get(m, None)
93 return n, l, m
94
95def analyze_function(s):
96 """
97 文字列表現を解析し、波動関数のタイプとパラメータを取得する。
98
99 :param s: str, 解析対象の文字列 (例: '3dxy', '210r')
100 :returns: tuple, (type_str, list_of_params) の形式で返す
101 """
102#数字だけ
103 match = re.match(r"^([+-]?\d)([+-]?\d)([+-]?\d)([cria2]+)?$", s)
104 if match:
105 n = int(match.group(1))
106 l = int(match.group(2))
107 m = int(match.group(3))
108 t = match.group(4)
109 if t is None: t = 'r'
110 return 'c', [n, l, m, t]
111
112# 3dxyのような文字列形式
113 match = re.match(r"^(\d)([a-z])([a-z]+[\-\+]?)([cria2]+)?$", s)
114 if match:
115 n = int(match.group(1))
116 l = match.group(2)
117 m = match.group(3)
118 t = match.group(4)
119 if t is None: t = 'r'
120 return 'r', [n, l, m, t]
121
122#その他
123 return 'f', [s]
124
125def get_by_type(f, rettype = 'c'):
126 """
127 指定された戻り値の型に応じて複素数の成分を返す。
128
129 :param f: complex, 評価する複素数
130 :param rettype: str, 戻り値のタイプ ('r': 実部, 'i': 虚部, 'a': 絶対値, 'a2': 絶対値の2乗, 'c': 実部と虚部)
131 :returns: tuple, 要求された成分と位相、または実部と虚部のタプル
132 """
133 if rettype == 'r':
134 return f.real, angle(f)
135 elif rettype == 'i':
136 return f.imag, angle(f)
137 elif rettype == 'a':
138 return abs(f), angle(f)
139 elif rettype == 'a2':
140 fnorm = abs(f)
141 return fnorm**2, angle(f)
142 else:
143 return f.real, f.imag
144
145#動径波動関数:
146#kRnl = 1.0
147kRnl = 1.0 / sqrt(4.0 * pi) # integ(4 * pi * r**2 * Rnl(r)**2)で規格化
148def Rnl_if(r, n, l, Z = 1.0):
149 """
150 条件分岐による解析的な動径波動関数を計算する。
151
152 :param r: float または ndarray, 距離
153 :param n: int, 主量子数
154 :param l: int, 方位量子数
155 :param Z: float, 原子番号 (デフォルトは 1.0)
156 :returns: float または ndarray, 動径波動関数の値。サポート外の場合は None
157 """
158 rho = 2 * Z * r / n / a0
159 if n == 1 and l == 0: # 1s
160 Rr = 2 * (Z / a0)**(3/2) * np.exp(-rho / 2)
161 elif n == 2 and l == 0: # 2s
162 Rr = (1 / (2 * np.sqrt(2))) * (Z / a0) ** (3/2) * (2 - rho) * np.exp(-rho / 2)
163 elif n == 2 and l == 1: # 2p
164 Rr = (1 / (2 * np.sqrt(6))) * (Z / a0) ** (3/2) * rho * np.exp(-rho / 2)
165 elif n == 3 and l == 0: # 3s
166 Rr = (1 / (9 * np.sqrt(3))) * (Z / a0) ** (3/2) * (6 - 6 * rho + rho ** 2) * np.exp(-rho / 2)
167 elif n == 3 and l == 1: # 3p
168 Rr = (1 / (9 * np.sqrt(6))) * (Z / a0) ** (3/2) * (4 - rho) * rho * np.exp(-rho / 2)
169 elif n == 3 and l == 2: # 3d
170 Rr = (1 / (9 * np.sqrt(30))) * (Z / a0) ** (3/2) * rho ** 2 * np.exp(-rho / 2)
171 elif n == 4 and l == 0: # 4s
172 Rr = 1/768 * (1/a0)**(3/2) * (192 - 144*r/a0 + 24*r**2/a0**2 - r**3/a0**3)*np.exp(-r/4/a0)
173 else:
174 Rr = None
175# print(f"\nError in tkWavefunctin_H.Rnl_if(): Unsuport (n,l)=({n}, {l})\n")
176# exit()
177
178 if Rr is None: return None
179 return kRnl * Rr
180
181def Rnl(r, n, l):
182 """
183 ラゲールの陪多項式を用いて動径波動関数を計算する。
184
185 :param r: float または ndarray, 距離
186 :param n: int, 主量子数
187 :param l: int, 方位量子数
188 :returns: float または ndarray, 動径波動関数の値
189 """
190 zeta = 2.0 * r / n / a0
191 L_coff = (-1)**(2 * l + 1) * factorial(n + l)
192 f_coff = - ((2.0 / n / a0)**3 * factorial(n - l - 1) / 2.0 / n / factorial(n + l)**3)**(1.0 / 2.0)
193 K = f_coff * np.exp(-zeta / 2.0) * zeta**l * L_coff
194
195 return kRnl * K * assoc_laguerre(zeta, n - l - 1, 2 * l + 1)
196
197# 球面調和関数
198KPhi = 1.0 / sqrt(2.0 * pi)
199def Ylm_phi_r(phi, m):
200 """
201 球面調和関数の実数型の方位角成分を計算する。
202
203 :param phi: float または ndarray, 方位角
204 :param m: int, 磁気量子数
205 :returns: float または ndarray, 方位角成分の値
206 """
207 if m >= 0:
208 return KPhi * exp(1j * m * phi).real
209 else:
210 return KPhi * exp(-1j * m * phi).imag
211
212def Ylm_phi(phi, m):
213 """
214 球面調和関数の複素数型の方位角成分を計算する。
215
216 :param phi: float または ndarray, 方位角
217 :param m: int, 磁気量子数
218 :returns: complex または ndarray, 方位角成分の値
219 """
220 return KPhi * exp(1j * m * phi)
221
222KYlm = sqrt(4.0 * pi)
223def Ylm_theta(theta, l, m):
224 """
225 ルジャンドルの陪関数を用いて球面調和関数の極角成分を計算する。
226
227 :param theta: float または ndarray, 極角
228 :param l: int, 方位量子数
229 :param m: int, 磁気量子数
230 :returns: float または ndarray, 極角成分の値
231 """
232 ma = m if m >= 0 else -m
233 KTheta = sqrt((2 * l + 1) / 2 * factorial(l - ma) / factorial(l + ma))
234# KTheta = sqrt((2 * l + 1) / (4 * pi) * factorial(l - m) / factorial(l + m))
235# KTheta /= KPhi
236 if m >= 1 and m % 2 == 1:
237 KTheta *= -1.0
238
239 return KYlm * KTheta * lpmv(m, l, cos(theta))
240
241def Ylm(theta, phi, l, m, phase_m = 0.0):
242 """
243 複素数型の球面調和関数を計算する。
244
245 :param theta: float または ndarray, 極角
246 :param phi: float または ndarray, 方位角
247 :param l: int, 方位量子数
248 :param m: int, 磁気量子数
249 :param phase_m: float, 位相シフト (デフォルトは 0.0)
250 :returns: complex または ndarray, 球面調和関数の値
251 """
252# return exp(-1.0j * phase_m) * sph_harm(m, l, phi, theta)
253 return exp(-1.0j * phase_m) * Ylm_phi(phi, m) * Ylm_theta(theta, l, m)
254
255def Ylm_r(theta, phi, l, m, phase_m = 0.0):
256 """
257 実数型の球面調和関数を計算する。
258
259 :param theta: float または ndarray, 極角
260 :param phi: float または ndarray, 方位角
261 :param l: int, 方位量子数
262 :param m: int, 磁気量子数
263 :param phase_m: float, 位相シフト (デフォルトは 0.0)
264 :returns: float または ndarray, 実数型の球面調和関数の値
265 """
266# return exp(-1.0j * phase_m) * sph_harm(m, l, phi, theta)
267 return exp(-1.0j * phase_m) * Ylm_phi_r(phi, m) * Ylm_theta(theta, l, m)
268
269def Ylm_xyz(x, y, z, l, m, phase_m = 0.0):
270 """
271 直交座標系から実数型の球面調和関数を計算する。
272
273 :param x: float または ndarray, x座標
274 :param y: float または ndarray, y座標
275 :param z: float または ndarray, z座標
276 :param l: int, 方位量子数
277 :param m: int, 磁気量子数
278 :param phase_m: float, 位相シフト (デフォルトは 0.0)
279 :returns: float または ndarray, 球面調和関数の値
280 """
281 r2 = x**2 + y**2 + z**2
282 r = sqrt(r2)
283 theta = arccos(z / r)
284 phi = arctan2(y, x)
285
286 return Ylm_r(theta, phi, l, m, phase_m)
287
288def Ylm_real(theta, phi, l, m, phase_m = 0.0):
289 """
290 複素数型の球面調和関数から実関数表現(実部・虚部の組み合わせ)を計算する。
291
292 :param theta: float または ndarray, 極角
293 :param phi: float または ndarray, 方位角
294 :param l: int, 方位量子数
295 :param m: int, 磁気量子数
296 :param phase_m: float, 位相シフト (デフォルトは 0.0)
297 :returns: float または ndarray, 実関数表現の球面調和関数の値
298 """
299 if m >= 0:
300 return Ylm(theta, phi, l, m, phase_m).real
301 elif m < 0:
302 return Ylm(theta, phi, l, -m, phase_m).imag
303
304def Ylm_xyz_real(x, y, z, l, m, phase_m = 0.0):
305 """
306 直交座標系から実関数表現の球面調和関数を計算する。
307
308 :param x: float または ndarray, x座標
309 :param y: float または ndarray, y座標
310 :param z: float または ndarray, z座標
311 :param l: int, 方位量子数
312 :param m: int, 磁気量子数
313 :param phase_m: float, 位相シフト (デフォルトは 0.0)
314 :returns: float または ndarray, 実関数表現の球面調和関数の値
315 """
316 r2 = x**2 + y**2 + z**2
317 r = sqrt(r2)
318 theta = arccos(z / r)
319 phi = arctan2(y, x)
320
321 return Ylm_real(theta, phi, l, m, phase_m)
322
323def psi_r(r, theta, phi, n, l, m, phase = 0.0):
324 """
325 球座標系での水素原子の複素波動関数を計算する。
326
327 :param r: float または ndarray, 距離
328 :param theta: float または ndarray, 極角
329 :param phi: float または ndarray, 方位角
330 :param n: int, 主量子数
331 :param l: int, 方位量子数
332 :param m: int, 磁気量子数
333 :param phase: float, 位相シフト (デフォルトは 0.0)
334 :returns: complex または ndarray, 波動関数の値
335 """
336 return exp(-1.0j * phase) * Rnl(r, n, l) * Ylm(theta, phi, l, m)
337
338def psi_xyz(x, y, z, n, l, m, phase = 0.0):
339 """
340 直交座標系での水素原子の複素波動関数を計算する。
341
342 :param x: float または ndarray, x座標
343 :param y: float または ndarray, y座標
344 :param z: float または ndarray, z座標
345 :param n: int, 主量子数
346 :param l: int, 方位量子数
347 :param m: int, 磁気量子数
348 :param phase: float, 位相シフト (デフォルトは 0.0)
349 :returns: complex または ndarray, 波動関数の値
350 """
351 r2 = x**2 + y**2 + z**2
352 r = sqrt(r2)
353 theta = arccos(z / r)
354 phi = arctan2(y, x)
355 return psi_r(r, theta, phi, n, l, m, phase)
356
357def psi_r_real(r, theta, phi, n, l, m, phase = 0.0):
358 """
359 球座標系での水素原子の実関数表現の波動関数を計算する。
360
361 :param r: float または ndarray, 距離
362 :param theta: float または ndarray, 極角
363 :param phi: float または ndarray, 方位角
364 :param n: int, 主量子数
365 :param l: int, 方位量子数
366 :param m: int, 磁気量子数
367 :param phase: float, 位相シフト (デフォルトは 0.0)
368 :returns: float または ndarray, 実関数表現の波動関数の値
369 """
370 if m >= 0:
371 f = psi_r(r, theta, phi, n, l, m)
372 return f.real
373 else:
374 f = psi_r(r, theta, phi, n, l, -m)
375 return f.imag
376
377def psi_xyz_real(x, y, z, n, l, m, phase = 0.0):
378 """
379 直交座標系での水素原子の実関数表現の波動関数を計算する。
380
381 :param x: float または ndarray, x座標
382 :param y: float または ndarray, y座標
383 :param z: float または ndarray, z座標
384 :param n: int, 主量子数
385 :param l: int, 方位量子数
386 :param m: int, 磁気量子数
387 :param phase: float, 位相シフト (デフォルトは 0.0)
388 :returns: float または ndarray, 実関数表現の波動関数の値
389 """
390 r2 = x**2 + y**2 + z**2
391 r = sqrt(r2)
392 theta = arccos(z / r)
393 phi = arctan2(y, x)
394 if m >= 0:
395 f = psi_r(r, theta, phi, l, m, phase_m)
396 return f.real
397 else:
398 f = psi_r(r, theta, phi, l, -m, phase_m)
399 return f.imag