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

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