import numpy as np
import scipy.special
import scipy.misc
import math
from os import listdir
from IPython.display import display,Image
import pandas as pd
import matplotlib.pyplot as plt
import time
#меняем функцию авторства Андрея Демкива для записи в формате cube
def npy2cube(grid, start, step, cube_f):
'''
PARAMETERS:
grid : numpy array
3-dimentional array, containing grid data
start : tuple
format: (x, y, z), coordinates of cube start point
step: tuple
format: (x, y, z), step size on 3 axes
cube_f: string
name of output .cube file
RETURNS:
void
'''
cube_string = ""
bohr_to_angs = 0.529177210859 #const
start = list(map(lambda x: x / bohr_to_angs, start))
step = list(map(lambda x: x / bohr_to_angs, step))
with open(cube_f, "w") as cube_file:
###HEADER###
cube_file.write(" CPMD CUBE FILE.\nOUTER LOOP: X, MIDDLE LOOP: Y, INNER LOOP: Z\n")
cube_file.write(" 1 %f %f %f\n" %(start[0], start[1], start[2]))
cube_file.write(" %i %f 0.000000 0.000000\n" %(grid.shape[0], step[0]))
cube_file.write(" %i 0.000000 %f 0.000000\n" %(grid.shape[1], step[1]))
cube_file.write(" %i 0.000000 0.000000 %f\n" %(grid.shape[2], step[2]))
cube_file.write(" 1 0.000000 %f %f %f\n" %(start[0], start[1], start[2]))
###DATA###
i = 0
for x in range(grid.shape[0]):
for y in range(grid.shape[1]):
for z in range(grid.shape[2]):
if i < 5:
cube_file.write("%f " %(float(grid[x, y, z])))
i += 1
elif i == 5:
cube_file.write("%f\n" %(float(grid[x, y, z])))
i = 0
return 0
зададим волновую функцию
def w(n,l,m,d):
# n,l,m - квантовые числа (главное, орбитальное, магнитное). d - шаг
# в декартовой системе координат (30*30*30)
x,y,z = np.mgrid[-d:d:30j,-d:d:30j,-d:d:30j]
# переход в сцерические координаты
r = lambda x,y,z: np.sqrt(x**2+y**2+z**2)
theta = lambda x,y,z: -np.arcsin(z/r(x,y,z)) + math.pi/2
phi = lambda x,y,z: np.arctan2(y, x) + math.pi
a0 = 1
# полином Лагерра
R = lambda r,n,l: (2*r/n/a0)**l * np.exp(-r/n/a0) * scipy.special.genlaguerre(n-l-1,2*l+1)(2*r/n/a0)
# нормировочный коэффициент
b = lambda n,l: np.sqrt((math.factorial(n-l-1)/(2*n*math.factorial(n+l)))*(2/n/a0)**3)
# волновая функция
WF = lambda r,theta,phi,n,l,m: b(n, l) * R(r,n,l) * scipy.special.sph_harm(m,l,phi,theta)
# плотность вероятности волновой функции
absWF = lambda r,theta,phi,n,l,m: np.absolute(WF(r,theta,phi,n,l,m))**2
out = WF(r(x,y,z),theta(x,y,z),phi(x,y,z),n,l,m)
return np.real(out) + np.imag(out)
Для каждой тройки квантовых чисел применяем скрипт и рисуем орбитали
for n in range(1, 4):
d = 10 * n
# задаем шаг
step = 2 * d / 29
for l in range(0, n):
for m in range(-l, l+1):
# считается волновая функция
grid = w(n, l, m, d)
name = f'{n}_{l}_{m}'
# записываем в файл
npy2cube(grid, (-d,)*3, (step,)*3, f'{name}.cube')
#откроем pymol
import __main__
__main__.pymol_argv = [ 'pymol', '-x' ]
import pymol
pymol.finish_launching()
from pymol import cmd, stored
#напишем скрипт для Pymol, отображающий орбтали
v = open ('v.pml', 'w')
# покрасим
v.write('cmd.volume_ramp_new(\'ramp007\', \
[-0.015, 1.00, 0.00, 0.00, 0.00, \
-0.01, 1.00, 1.00, 0.00, 0.20, \
-0.005, 0.00, 0.00, 1.00, 0.00, \
0.005, 0.00, 0.00, 1.00, 0.00, \
0.01, 0.00, 1.00, 1.00, 0.20, \
0.015, 0.00, 0.00, 1.00, 0.00]) \n')
# рисуем орбитали в PyMol
for n in range(1, 4):
for l in range(0, n):
for m in range(-l, l+1):
name = '%s_%s_%s' % (n,l,m)
cube_name = name + '.cube'
volume_name = name + '_vol'
v.write('load %s, %s\n' % (cube_name, name))
v.write('volume %s, %s\n' % (volume_name, name))
v.write('volume_color %s, ramp007\n' % (volume_name))
v.close()
cmd.reinitialize()
cmd.load('v.pml')
Сохраним изображения орбиталей отдельно
slab = ['1_0_0', '2_0_0', '2_1_0', '3_0_0', '3_1_0', '3_2_0']
for n in range(1, 4):
for l in range(0, n):
for m in range(-l, l+1):
name = f'{n}_{l}_{m}'
cmd.hide()
cmd.show('volume', f'{name}_vol')
cmd.reset()
cmd.turn('x', 90)
if name in slab:
cmd.clip('slab', 0)
cmd.do(f'png {name}, width={480}, height={270}')
cmd.hide()
Выведем изображения
orbitales = {0: 's', 1: 'p', 2: 'd'}
_, axarr = plt.subplots(7, 2, figsize=(10, 21.33))
row, col = 0, 0
for n in range(1, 4):
for l in range(0, n):
for m in range(-l, l+1):
name = f'{n}_{l}_{m}'
f = plt.imread(f'{name}.png')
axarr[row, col].axis('off')
axarr[row, col].imshow(f)
axarr[row, col].set_title(f'{n}{orbitales[l]} ({name})', fontsize = 20)
col += 1
if col == 2:
row += 1
col = 0
plt.tight_layout()
#Скрипт для ORCA
with open('hydrogen.inp', 'w') as f:
f.write('''! UHF QZVPP XYZFile
%plots Format Cube
MO("H-0.cube",0,0);
MO("H-1.cube",1,0);
MO("H-2.cube",2,0);
MO("H-3.cube",3,0);
MO("H-4.cube",4,0);
MO("H-5.cube",5,0);
MO("H-6.cube",6,0);
MO("H-7.cube",7,0);
MO("H-8.cube",8,0);
MO("H-9.cube",9,0);
MO("H-10.cube",10,0);
MO("H-11.cube",11,0);
MO("H-12.cube",12,0);
MO("H-13.cube",13,0);
end
* xyz 0 2
H 0 0 0
* ''')
На сервере kodomo был запущен вышеупомянутый скрипт. Файлы H-*.cube с орбиталями были также отображены в pymol
#напишем скрипт для Pymol, отображающий орбтали
v = open ('orca.pml', 'w')
# покрасим
v.write('cmd.volume_ramp_new(\'ramp007\', \
[-0.015, 1.00, 0.00, 0.00, 0.00, \
-0.01, 1.00, 1.00, 0.00, 0.20, \
-0.005, 0.00, 0.00, 1.00, 0.00, \
0.005, 0.00, 0.00, 1.00, 0.00, \
0.01, 0.00, 1.00, 1.00, 0.20, \
0.015, 0.00, 0.00, 1.00, 0.00]) \n')
# рисуем орбитали в PyMol
for i in range(0, 14):
name = 'H-%s' % i
cube_name = name + '.cube'
volume_name = name + '_vol'
v.write('load %s, %s\n' % (cube_name, name))
v.write('volume %s, %s\n' % (volume_name, name))
v.write('volume_color %s, ramp007\n' % (volume_name))
v.close()
cmd.reinitialize()
cmd.load("orca.pml")
for n in range(14):
name = f'H-{n}'
cmd.hide()
cmd.show('volume', f'{name}_vol')
cmd.reset()
cmd.clip('slab', 0)
time.sleep(0.5)
cmd.do(f'png {name}')
cmd.hide()
_, axarr = plt.subplots(7, 2, figsize=(10, 21.33))
row, col = 0, 0
l = 0
for n in range(14):
name = f'H-{n}'
f = plt.imread(f'{name}.png')
axarr[row, col].axis('off')
axarr[row, col].imshow(f)
axarr[row, col].set_title(f'{name}',{'fontsize': 20})
col += 1
if col == 2:
row += 1
col = 0
plt.tight_layout()
Орбитали s и p уровней по форме совпадают с рассчитанными ORCA. Формы орбиталей других уровней заметно различаются, возможно дело в разных точностях рассчета.