LoginSignup
68
45

More than 5 years have passed since last update.

水素原子のシュレディンガー方程式解の波動関数から電子雲の可視化

Last updated at Posted at 2018-02-01

水素原子のシュレディンガー方程式解の波動関数から電子雲の可視化

を元に、水素原子のシュレディンガー方程式の解析解から、

ソースコード

import numpy as np
import os
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


# 動径関数 R_nl (A=a0=1, 規格化因子は省略, nは主量子数, lは軌道角運動量量子数) 
# https://ja.wikipedia.org/wiki/%E6%B0%B4%E7%B4%A0%E5%8E%9F%E5%AD%90%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%82%B7%E3%83%A5%E3%83%AC%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%AC%E3%83%BC%E6%96%B9%E7%A8%8B%E5%BC%8F%E3%81%AE%E8%A7%A3

def R_10(r):
    return np.exp(-r)

def R_20(r):
    return (2 - r) * np.exp(-r/2)

def R_21(r):
    return r * np.exp(-r/2)

def R_30(r):
    return (27 - 18*r + r**2) * np.exp(-r/3)

def R_31(r):
    return (6 - r) * r * np.exp(-r/3)

def R_32(r):
    return r**2 * np.exp(-r/3)

# 動径方向関数 Y_lm (規格化因子は省略。lは軌道角運動量量子数、mは磁気量子数。)

def Y_00(theta, phi):
    return 1

def Y_11(theta, phi):
    return np.sin(theta) * np.cos(phi)

def Y_10(theta, phi):
    return np.cos(theta)

def Y_1_1(theta, phi):
    return np.sin(theta) * np.sin(phi)

def Y_22(theta, phi):
    return np.sin(theta)**2 * np.cos(2*phi)

def Y_21(theta, phi):
    return np.sin(theta) * np.cos(theta) * np.cos(phi)

def Y_20(theta, phi):
    return (3*np.cos(theta)**2 - 1)

def Y_2_1(theta, phi):
    return np.sin(theta) * np.cos(theta) * np.sin(phi)

def Y_2_2(theta, phi):
    return np.sin(theta)**2 * np.sin(2*phi)

def Y_33(theta, phi):
    return np.sin(theta)**3 * np.cos(3*phi)

def Y_32(theta, phi):
    return np.cos(theta) * np.sin(theta)**2 * np.cos(2*phi)

def Y_31(theta, phi):
    return (5*np.cos(theta)**2 -1) * np.sin(theta) * np.cos(phi)

def Y_30(theta, phi):
    return (5*np.cos(theta)**3 - 3*np.cos(theta))

def Y_3_1(theta, phi):
    return (5*np.cos(theta)**2 -1) * np.sin(theta) * np.sin(phi)

def Y_3_2(theta, phi):
    return np.cos(theta) * np.sin(theta)**2 * np.sin(2*phi)

def Y_3_3(theta, phi):
    return np.sin(theta)**3 * np.sin(3*phi)


def generate_hydrogen_orbital_func(nlm, r_range=np.arange(0, 20, 0.1)):
    """
    nlm軌道のR(r)(1次元配列)とY(theta,phi)(2次元配列)の値を計算する。
    Parameter
    ---------
    nlm : 軌道
    ---------
    Returns
    ---------
    R_data : R(r), len(r_range)長の1次元配列
    R_args : R(r)の引数リスト, len(r_range)長の1次元配列
    Y_data : Y(theta, phi), len(theta_range)×len(phi_range)の2次元配列
    Y_args : Y(theta, phi)の引数リスト,  len(theta_range)×len(phi_range)の2次元配列
    ----------
    """

    if nlm == '100':
        R = R_10
        Y = Y_00
    elif nlm == '200':
        R = R_20
        Y = Y_00
    elif nlm == '211':
        R = R_21
        Y = Y_11
    elif nlm == '210':
        R = R_21
        Y = Y_10
    elif nlm == '21-1':
        R = R_21
        Y = Y_1_1
    elif nlm == '300':
        R = R_30
        Y = Y_00
    elif nlm == '311':
        R = R_31
        Y = Y_11
    elif nlm == '310':
        R = R_31
        Y = Y_10
    elif nlm == '31-1':
        R = R_31
        Y = Y_1_1
    elif nlm == '322':
        R = R_32
        Y = Y_22
    elif nlm == '321':
        R = R_32
        Y = Y_21
    elif nlm == '320':
        R = R_32
        Y = Y_20
    elif nlm == '32-1':
        R = R_32
        Y = Y_2_1
    elif nlm == '32-2':
        R = R_32
        Y = Y_2_2
    else:
        raise ValueError('!!!!')

    # R_nl(r)のデータ生成
    R_data = np.array([R(r) for r in r_range])
    R_args = np.array([r for r in r_range])
    # Y_lm(θ, φ)のデータ生成
    Y_data = np.array([[Y(theta, phi) for theta in np.arange(0, np.pi, 0.1)] for phi in np.arange(0, 2*np.pi, 0.1)])
    Y_args = np.array([[(phi, theta) for theta in np.arange(0, np.pi, 0.1)] for phi in np.arange(0, 2*np.pi, 0.1)])

    return R_data, R_args, Y_data, Y_args


def sample_from_accum_Y(accum_Y):
    """
    Y(θ, φ)^2の累積分布関数accum_Yから1点サンプリングしインデックス(i, j)を返す。
    """

    row_num = accum_Y.shape[0]
    col_num = accum_Y.shape[1]

    # 規格化
    normed_accum = accum_Y / accum_Y[row_num-1, col_num-1]
    rand = np.random.rand()
    for i in range(row_num):
        for j in range(col_num):
            if rand < normed_accum[i, j]:
                return (i, j)


def sample_from_accum_R(accum_R):
    """
    R(r)^2の累積分布関数accum_Rから1点サンプリングしインデックスiを返す。
    """

    # 規格化
    normed_accum = accum_R / accum_R[-1]
    return len(*np.where(normed_accum < np.random.rand()))


OUT_DIR = 'ElectronCloud'
if not os.path.exists(OUT_DIR):
    os.makedirs(OUT_DIR)

# 計算する軌道(nml)リスト
ORBITS = ['100', '200', '211', '210', '21-1', '300', '311', '310', '31-1', '322', '321', '320', '32-1', '32-2']

# 各軌道に対して電子雲を計算する。
for orbit in ORBITS:
    # 軌道orbitのR(r)とY(θ, φ)のデータを生成
    R_data, R_args, Y_data, Y_args = generate_hydrogen_orbital_func(nlm=orbit)
    R_data **= 2
    Y_data **= 2
    # R^2とY^2の累積分布関数を求める。
    accum_R = np.array([R_data[:i+1].sum() for i in range(len(R_data))])
    accum_Y = np.array([Y_data.flatten()[:i+1].sum() for i in range(len(Y_data.flatten()))]).reshape(Y_data.shape[0], Y_data.shape[1])

    if not os.path.exists(OUT_DIR + '/' + orbit):
        os.makedirs(OUT_DIR + '/' + orbit)

    x = []
    y = []
    z = []
    # 確率分布に従って9000点生成する。
    for _ in range(9000):
        # Y(θ, φ)^2の累積分布関数から(θ,φ)を1組サンプリングする。
        ind_phi, ind_theta = sample_from_accum_Y(accum_Y)
        phi, theta = Y_args[ind_phi, ind_theta]
        # R(r)^2の累積分布関数から1点rをサンプリングする。
        r_ind = sample_from_accum_R(accum_R)
        r = R_args[r_ind]
        x.append(r*np.sin(theta) * np.cos(phi))
        y.append(r*np.sin(theta) * np.sin(phi))
        z.append(r*np.cos(theta))

    fig = plt.figure()
    ax = Axes3D(fig)
    ax.plot(x, y, z, "o", ms=1.5, mew=0.5)

    # 360度回転。10度回転毎に画像を保存
    for i in range(0, 360, 10):
        ax.view_init(elev=10., azim=i)
        plt.savefig(OUT_DIR + '/' + orbit + "/{}.png".format(i))

可視化

nlm = 100

100.gif

nlm = 200

200.gif

nlm = 211

211.gif

nlm = 210

210.gif

nlm = 21-1

21-1.gif

nlm = 300

300.gif

nlm = 311

311.gif

nlm = 310

310.gif

nlm = 31-1

31-1.gif

nlm = 322

322.gif

nlm = 321

321.gif

nlm = 320

320.gif

nlm = 32-1

32-1.gif

nlm = 32-2

32-2.gif

68
45
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
68
45