4. Ab initio вычисления орбиталей водорода¶
import numpy
import scipy.special
import scipy.misc
import npy2cube
def w(n, l, m, d):
# Создаем 3D-сетку точек по x, y, z в пределах от -d до d
x, y, z = numpy.mgrid[-d:d:30j, -d:d:30j, -d:d:30j]
# Функция для вычисления расстояния от начала координат до точки (x, y, z):
# r = sqrt(x^2 + y^2 + z^2)
r = lambda x, y, z: numpy.sqrt(x**2 + y**2 + z**2)
# Функция для вычисления полярного угла theta:
# theta = arccos(z / r)
theta = lambda x, y, z: numpy.arccos(z / r(x, y, z))
# Функция для вычисления азимутального угла phi:
# phi = arctan(y / x)
phi = lambda x, y, z: numpy.arctan(y / x)
# Боровский радиус; здесь для простоты принят равным 1
a0 = 1.
# Радиальная часть водородоподобной волновой функции:
# зависит от расстояния r и квантовых чисел n и l
R = lambda r, n, l: (2 * r / n / a0)**l * numpy.exp(-r / n / a0) * scipy.special.genlaguerre(n - l - 1, 2 * l + 1)(2 * r / n / a0)
# Полная волновая функция:
# произведение радиальной части R(r) на сферическую гармонику Y_l^m(phi, theta)
WF = lambda r, theta, phi, n, l, m: R(r, n, l) * scipy.special.sph_harm(m, l, phi, theta)
# Электронная плотность:
# квадрат модуля волновой функции |psi|^2
absWF = lambda r, theta, phi, n, l, m: numpy.absolute(WF(r, theta, phi, n, l, m))**2
return WF(r(x, y, z), theta(x, y, z), phi(x, y, z), n, l, m)
такая версия кода не рабоатет, тк у меня сейчас установлена более новая версия SciPy. Поэтому я просто немного модернизирую версию кода.
import numpy
import scipy.special
def w(n, l, m, d):
x, y, z = numpy.mgrid[-d:d:61j, -d:d:61j, -d:d:61j]
r = lambda x, y, z: numpy.sqrt(x**2 + y**2 + z**2)
theta = lambda x, y, z: numpy.arccos(
numpy.divide(z, r(x, y, z), out=numpy.zeros_like(z), where=r(x, y, z) != 0)
)
phi = lambda x, y, z: numpy.arctan2(y, x)
a0 = 1.0
R = lambda r, n, l: (2 * r / n / a0)**l * numpy.exp(-r / n / a0) * \
scipy.special.genlaguerre(n - l - 1, 2 * l + 1)(2 * r / n / a0)
WF = lambda r, theta, phi, n, l, m: R(r, n, l) * scipy.special.sph_harm_y(l, m, theta, phi)
absWF = lambda r, theta, phi, n, l, m: numpy.absolute(WF(r, theta, phi, n, l, m))**2
return absWF(r(x, y, z), theta(x, y, z), phi(x, y, z), n, l, m)
pwd
d = 10
step = 2 * d / 60
for n in range(1, 4):
for l in range(0, n):
for m in range(0, l + 1):
grid = w(n, l, m, d)
name = '%s-%s-%s' % (n, l, m)
npy2cube.npy2cube(grid, (-d, -d, -d), (step, step, step), name + '.cube')
Проверка того, что файлы и вправду скачаались
import os
files = [f for f in os.listdir() if f.endswith(".cube")]
print(files)
['1-0-0.cube', '2-0-0.cube', '2-1-0.cube', '2-1-1.cube', '3-0-0.cube', '3-1-0.cube', '3-1-1.cube', '3-2-0.cube', '3-2-1.cube', '3-2-2.cube']
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('1-0-0.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.01,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
Для состояния 1s получена почти сферическая изоповерхность электронной плотности. Небольшая угловатость связана с дискретной расчетной сеткой и численным построением поверхности.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('2-0-0.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.01,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('2-1-0.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.01,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
Для состояния 2-1-0 после поворота модели наблюдаются две симметричные области электронной плотности, разделённые узловой плоскостью, что соответствует p-орбитальному состоянию. Для состояний 1-0-0 и 2-0-0 сохраняется сферическая симметрия, характерная для s-состояний.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('2-1-1.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.01,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
d = 15
step = 2 * d / 60
for n in range(3, 4):
for l in range(0, n):
for m in range(0, l + 1):
grid = w(n, l, m, d)
name = f'{n}-{l}-{m}_d15'
npy2cube.npy2cube(grid, (-d, -d, -d), (step, step, step), name + '.cube')
import os
files = [f for f in os.listdir() if f.endswith(".cube")]
print(files)
['1-0-0.cube', '2-0-0.cube', '2-1-0.cube', '2-1-1.cube', '3-0-0.cube', '3-0-0_d15.cube', '3-1-0.cube', '3-1-0_d15.cube', '3-1-1.cube', '3-1-1_d15.cube', '3-2-0.cube', '3-2-0_d15.cube', '3-2-1.cube', '3-2-1_d15.cube', '3-2-2.cube', '3-2-2_d15.cube']
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('3-0-0_d15.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.01,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('3-1-0_d15.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.02,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('3-1-1_d15.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.02,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
Для состояния 3-0-0 получена сферически симметричная электронная плотность, что соответствует s-состоянию. По сравнению с 1s и 2s, состояние 3s имеет более сложную радиальную структуру, поскольку для него характерны два радиальных узла. При выбранном значении изоповерхности в визуализации в первую очередь наблюдается внешняя сферическая оболочка. Для состояния 3-1-1 электронная плотность имеет кольцеобразную симметрию. В отличие от состояния 3-1-0, где наблюдаются две лопасти, здесь форма определяется выбором магнитного квантового числа m = 1 и использованием комплексных сферических гармоник. Наличие внутренней и внешней областей плотности связано с радиальным узлом на третьем энергетическом уровне.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('3-2-0_d15.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.025,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
Для состояния 3-2-0 наблюдается форма, соответствующая d-состоянию типа d_z²: две осевые лопасти и кольцевая область вокруг центра. Небольшая неоднородность поверхности и дополнительные отверстия связаны с дискретностью расчетной сетки и особенностями построения изоповерхности.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('3-2-1_d15.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.025,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
Для состояния 3-2-1 получена форма, характерная для d-состояния с m = 1: две симметричные области электронной плотности. Вид распределения отличается от 3-2-0, что связано с другой угловой зависимостью волновой функции.
import py3Dmol
view = py3Dmol.view(width=500, height=500)
with open('3-2-2_d15.cube', 'r') as f:
alpha = f.read()
view.addVolumetricData(alpha, "cube", {
'isoval': 0.025,
'color': "red",
'opacity': 0.5
})
view.zoomTo()
view.render()
view.show()
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
Для состояния 3-2-2 электронная плотность имеет тороидальную симметрию: максимальная плотность располагается в виде кольцевой области вокруг оси. Такая форма соответствует d-состоянию с m = 2 при использовании комплексных сферических гармоник. Наблюдаемые при визуализации дополнительные отверстия связаны с дискретностью расчетной сетки, прозрачностью поверхности и особенностями построения изоповерхности.
import os
pml = '''
# volume ramp: каждое число задает
# value, R, G, B, alpha
# value = уровень плотности
# R,G,B = цвет
# alpha = прозрачность
bg_color white
set orthoscopic, on
set ray_opaque_background, off
cmd.volume_ramp_new('ramp007', [
0.005, 0.00, 0.00, 1.00, 0.00,
0.010, 0.00, 1.00, 1.00, 0.20,
0.015, 0.00, 0.00, 1.00, 0.35,
0.020, 1.00, 0.00, 0.00, 0.50,
])
'''
for n in range(1, 4):
for l in range(0, n):
for m in range(0, l + 1):
base_name = f'{n}-{l}-{m}'
cube_name = base_name + '.cube'
# для n=3 берем более удачные d15-файлы, если они есть
if n == 3 and os.path.exists(base_name + '_d15.cube'):
cube_name = base_name + '_d15.cube'
obj_name = base_name.replace('-', '_')
map_name = 'map_' + obj_name
vol_name = 'vol_' + obj_name
pml += f'load {cube_name}, {map_name}\n'
pml += f'volume {vol_name}, {map_name}, ramp007\n'
pml += f'disable {map_name}\n'
pml += f'set volume_mode, 0, {vol_name}\n'
pml += '\n'
with open('all_volumes.pml', 'w', encoding='utf-8') as v:
v.write(pml)
print('Скрипт all_volumes.pml записан')
Скрипт all_volumes.pml записан
В скрипте была изменена цветовая шкала volume_ramp_new для более наглядного отображения областей разной электронной плотности. Для состояний третьего уровня использованы .cube-файлы, пересчитанные при большем размере расчетной области (d = 15), что позволило избежать обрезания внешних частей распределения.
from IPython.display import display, Image
#1-0-0
display(Image(filename=r'C:\Users\Tata\Documents\jupyter_pol\orbital_1s.png'))
from IPython.display import display, Image
#2-1-0
display(Image(filename=r'C:\Users\Tata\Documents\jupyter_pol\orbital_2p.png'))
from IPython.display import display, Image
#3-2-2
display(Image(filename=r'C:\Users\Tata\Documents\jupyter_pol\orbital_3d.png'))
import base64
from pathlib import Path
from IPython.display import HTML
def img_to_base64(path):
data = Path(path).read_bytes()
return base64.b64encode(data).decode("utf-8")
img1_jupyter = img_to_base64(r"C:\Users\Tata\Documents\jupyter_pol\jupyter_1s.png")
img1_pymol = img_to_base64(r"C:\Users\Tata\Documents\jupyter_pol\orbital_1s.png")
img2_jupyter = img_to_base64(r"C:\Users\Tata\Documents\jupyter_pol\jupyter_2p.png")
img2_pymol = img_to_base64(r"C:\Users\Tata\Documents\jupyter_pol\orbital_2p.png")
img3_jupyter = img_to_base64(r"C:\Users\Tata\Documents\jupyter_pol\jupyter_3d.png")
img3_pymol = img_to_base64(r"C:\Users\Tata\Documents\jupyter_pol\orbital_3d.png")
HTML(f'''
<h3>Сравнение для 1-0-0</h3>
<div style="display:flex; gap:30px; align-items:flex-start; margin-bottom:30px;">
<div>
<p><b>Jupyter / py3Dmol</b></p>
<img src="data:image/png;base64,{img1_jupyter}" width="320">
</div>
<div>
<p><b>PyMOL</b></p>
<img src="data:image/png;base64,{img1_pymol}" width="320">
</div>
</div>
<h3>Сравнение для 2-1-0</h3>
<div style="display:flex; gap:30px; align-items:flex-start; margin-bottom:30px;">
<div>
<p><b>Jupyter / py3Dmol</b></p>
<img src="data:image/png;base64,{img2_jupyter}" width="320">
</div>
<div>
<p><b>PyMOL</b></p>
<img src="data:image/png;base64,{img2_pymol}" width="320">
</div>
</div>
<h3>Сравнение для 3-2-2</h3>
<div style="display:flex; gap:30px; align-items:flex-start;">
<div>
<p><b>Jupyter / py3Dmol</b></p>
<img src="data:image/png;base64,{img3_jupyter}" width="320">
</div>
<div>
<p><b>PyMOL</b></p>
<img src="data:image/png;base64,{img3_pymol}" width="320">
</div>
</div>
''')
Сравнение для 1-0-0
Jupyter / py3Dmol
PyMOL
Сравнение для 2-1-0
Jupyter / py3Dmol
PyMOL
Сравнение для 3-2-2
Jupyter / py3Dmol
PyMOL
Генерация cube-файлов в Psi4¶
import psi4
import numpy as np
psi4.core.set_output_file('output.dat', False)
g = '''
0 1
C 0.000000 0.000000 0.000000
'''
m = psi4.geometry(g)
psi4.set_options({
"basis": "cc-pvtz",
"maxiter": 200,
"fail_on_maxiter": True,
"cubeprop_tasks": ["orbitals"]
})
ener, wfn = psi4.energy('scf', molecule=m, return_wfn=True)
print("SCF energy =", ener)
psi4.cubeprop(wfn)
SCF energy = -37.60218711612772
import psi4
import numpy as np
import os
psi4.core.set_output_file('output.dat', False)
g = '''
0 1
C 0.000000 0.000000 0.000000
'''
m = psi4.geometry(g)
psi4.set_options({
"basis": "cc-pvtz",
"maxiter": 200,
"fail_on_maxiter": True,
"cubeprop_tasks": ["orbitals"], # можно и не писать: это и так default
"cubic_grid_spacing": [0.2, 0.2, 0.2],
"cubic_grid_overage": [4.0, 4.0, 4.0]
})
ener, wfn = psi4.energy('scf', molecule=m, return_wfn=True)
print("SCF energy =", ener)
psi4.cubeprop(wfn)
print([f for f in os.listdir() if f.endswith(".cube")])
SCF energy = -37.60218711612772 ['1-0-0.cube', '2-0-0.cube', '2-1-0.cube', '2-1-1.cube', '3-0-0.cube', '3-0-0_d15.cube', '3-1-0.cube', '3-1-0_d15.cube', '3-1-1.cube', '3-1-1_d15.cube', '3-2-0.cube', '3-2-0_d15.cube', '3-2-1.cube', '3-2-1_d15.cube', '3-2-2.cube', '3-2-2_d15.cube', 'Psi_a_10_1-B1g.cube', 'Psi_a_11_4-Ag.cube', 'Psi_a_12_1-B3g.cube', 'Psi_a_13_1-B2g.cube', 'Psi_a_14_5-Ag.cube', 'Psi_a_15_3-B3u.cube', 'Psi_a_16_3-B2u.cube', 'Psi_a_17_3-B1u.cube', 'Psi_a_18_4-B3u.cube', 'Psi_a_19_4-B2u.cube', 'Psi_a_1_1-Ag.cube', 'Psi_a_20_4-B1u.cube', 'Psi_a_21_1-Au.cube', 'Psi_a_22_5-B2u.cube', 'Psi_a_23_5-B3u.cube', 'Psi_a_24_5-B1u.cube', 'Psi_a_25_2-B1g.cube', 'Psi_a_26_6-Ag.cube', 'Psi_a_27_2-B2g.cube', 'Psi_a_28_2-B3g.cube', 'Psi_a_29_7-Ag.cube', 'Psi_a_2_2-Ag.cube', 'Psi_a_30_8-Ag.cube', 'Psi_a_3_1-B1u.cube', 'Psi_a_4_1-B2u.cube', 'Psi_a_5_1-B3u.cube', 'Psi_a_6_2-B1u.cube', 'Psi_a_7_2-B3u.cube', 'Psi_a_8_2-B2u.cube', 'Psi_a_9_3-Ag.cube', 'Psi_b_10_1-B1g.cube', 'Psi_b_11_4-Ag.cube', 'Psi_b_12_1-B3g.cube', 'Psi_b_13_1-B2g.cube', 'Psi_b_14_5-Ag.cube', 'Psi_b_15_3-B3u.cube', 'Psi_b_16_3-B2u.cube', 'Psi_b_17_3-B1u.cube', 'Psi_b_18_4-B3u.cube', 'Psi_b_19_4-B2u.cube', 'Psi_b_1_1-Ag.cube', 'Psi_b_20_4-B1u.cube', 'Psi_b_21_1-Au.cube', 'Psi_b_22_5-B2u.cube', 'Psi_b_23_5-B3u.cube', 'Psi_b_24_5-B1u.cube', 'Psi_b_25_2-B1g.cube', 'Psi_b_26_6-Ag.cube', 'Psi_b_27_2-B2g.cube', 'Psi_b_28_2-B3g.cube', 'Psi_b_29_7-Ag.cube', 'Psi_b_2_2-Ag.cube', 'Psi_b_30_8-Ag.cube', 'Psi_b_3_1-B1u.cube', 'Psi_b_4_1-B2u.cube', 'Psi_b_5_1-B3u.cube', 'Psi_b_6_2-B1u.cube', 'Psi_b_7_2-B3u.cube', 'Psi_b_8_2-B2u.cube', 'Psi_b_9_3-Ag.cube']
import py3Dmol
def show_psi4_orbital(filename, iso=0.03):
view = py3Dmol.view(width=500, height=500)
with open(filename, 'r') as f:
data = f.read()
# положительная часть орбитали
view.addVolumetricData(data, "cube", {
'isoval': iso,
'color': "red",
'opacity': 0.5
})
# отрицательная часть орбитали
view.addVolumetricData(data, "cube", {
'isoval': -iso,
'color': "blue",
'opacity': 0.5
})
view.zoomTo()
view.render()
return view.show()
show_psi4_orbital('Psi_a_1_1-Ag.cube', iso=0.05) # 1s-подобная
show_psi4_orbital('Psi_a_2_2-Ag.cube', iso=0.02) # 2s-подобная
show_psi4_orbital('Psi_a_3_1-B1u.cube', iso=0.02) # p-подобная
show_psi4_orbital('Psi_a_4_1-B2u.cube', iso=0.02) # p-подобная
show_psi4_orbital('Psi_a_5_1-B3u.cube', iso=0.02) # p-подобная
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
import py3Dmol
def show_psi4_orbital(filename, iso=0.02):
view = py3Dmol.view(width=500, height=500)
with open(filename, 'r') as f:
data = f.read()
# положительная фаза
view.addVolumetricData(data, "cube", {
'isoval': iso,
'color': "red",
'opacity': 0.5
})
# отрицательная фаза
view.addVolumetricData(data, "cube", {
'isoval': -iso,
'color': "blue",
'opacity': 0.5
})
view.zoomTo()
view.render()
return view.show()
show_psi4_orbital('Psi_a_10_1-B1g.cube', iso=0.02)
show_psi4_orbital('Psi_a_12_1-B3g.cube', iso=0.02)
show_psi4_orbital('Psi_a_13_1-B2g.cube', iso=0.02)
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
import base64
from pathlib import Path
from IPython.display import HTML
def img_to_base64(path):
data = Path(path).read_bytes()
return base64.b64encode(data).decode("utf-8")
folder = Path(r"C:\Users\Tata\Documents\jupyter_pol")
imgs = {
"jupyter_s": img_to_base64(folder / "jupyter_1s.png"),
"pymol_s": img_to_base64(folder / "orbital_1s.png"),
"psi_s": img_to_base64(folder / "psi_1s.png"),
"jupyter_p": img_to_base64(folder / "jupyter_2p.png"),
"pymol_p": img_to_base64(folder / "orbital_2p.png"),
"psi_p": img_to_base64(folder / "psi_2p.png"),
"jupyter_d": img_to_base64(folder / "jupyter_3d.png"),
"pymol_d": img_to_base64(folder / "orbital_3d.png"),
"psi_d": img_to_base64(folder / "psi_3d.png"),
}
HTML(f'''
<h2>Сравнение визуализаций</h2>
<h3>s-орбиталь</h3>
<div style="display:flex; gap:30px; align-items:flex-start; margin-bottom:35px;">
<div>
<p><b>Jupyter / py3Dmol</b></p>
<img src="data:image/png;base64,{imgs["jupyter_s"]}" width="260">
</div>
<div>
<p><b>PyMOL</b></p>
<img src="data:image/png;base64,{imgs["pymol_s"]}" width="260">
</div>
<div>
<p><b>Psi4</b></p>
<img src="data:image/png;base64,{imgs["psi_s"]}" width="260">
</div>
</div>
<h3>p-орбиталь</h3>
<div style="display:flex; gap:30px; align-items:flex-start; margin-bottom:35px;">
<div>
<p><b>Jupyter / py3Dmol</b></p>
<img src="data:image/png;base64,{imgs["jupyter_p"]}" width="260">
</div>
<div>
<p><b>PyMOL</b></p>
<img src="data:image/png;base64,{imgs["pymol_p"]}" width="260">
</div>
<div>
<p><b>Psi4</b></p>
<img src="data:image/png;base64,{imgs["psi_p"]}" width="260">
</div>
</div>
<h3>d-орбиталь</h3>
<div style="display:flex; gap:30px; align-items:flex-start;">
<div>
<p><b>Jupyter / py3Dmol</b></p>
<img src="data:image/png;base64,{imgs["jupyter_d"]}" width="260">
</div>
<div>
<p><b>PyMOL</b></p>
<img src="data:image/png;base64,{imgs["pymol_d"]}" width="260">
</div>
<div>
<p><b>Psi4</b></p>
<img src="data:image/png;base64,{imgs["psi_d"]}" width="260">
</div>
</div>
''')
Сравнение визуализаций
s-орбиталь
Jupyter / py3Dmol
PyMOL
Psi4
p-орбиталь
Jupyter / py3Dmol
PyMOL
Psi4
d-орбиталь
Jupyter / py3Dmol
PyMOL
Psi4
Визуальное сравнение орбиталей, полученных вручную в Jupyter, визуализированных в PyMOL и рассчитанных в программе Psi4, показывает качественное совпадение по типу симметрии. Для s-состояний во всех случаях наблюдается сферически симметричное распределение. Для p-состояний форма имеет двухлопастный характер, соответствующий наличию узловой плоскости. Для d-состояний форма становится более сложной и зависит от способа представления орбитали. В ручном расчете и при визуализации в PyMOL отображалась электронная плотность ∣𝜓∣^2, поэтому для d-состояния получалась тороидальная или иная форма распределения плотности без учета знака волновой функции. В расчете Psi4 визуализировалась сама орбиталь 𝜓, поэтому были видны положительная и отрицательная фазы, что приводило к четырехлепестковой d-форме. Таким образом, несмотря на различия во внешнем виде отдельных изображений, все три подхода согласованно воспроизводят основные типы орбитальной симметрии.