import hfscf
from hfscf import GTO
import numpy as np
Вам дан файл с фунциями для расчёта основных матриц hfscf.py
В следующей ячейке описана функция расчёта орбиталей на основе подхода Рутана Холла.
def SCF (r = 1.4632, Z=[1,1], b1 = GTO["H"], b2 = GTO["H"], b = 3, vbs=False):
R = [0, r]
#Генерируем матрицу перекрывания S
#S показывает, насколько перекрываются рассчитанные атомные орбитали
if vbs: print("*) Генерирую матрицу перекрывания S.")
s_scf = hfscf.S(R, b1, b2, b)
if vbs: print("\n*) Генерирую гамильтониан H.")
h_scf = hfscf.H(R, Z, b1, b2, b)
#Диагонализируем матрицу S
if vbs: print("\n*) Диагонализирую матрицу S и получаю диагональную матрицу X.")
X = hfscf.diagon(m=s_scf)
#Xa - сопряжённо-траснпонированная к X (транспонирование + замена каждого элемента на комплексно-сопряжённый)
Xa = X.getH()
#Создаём матрицу электронной плотности P
if vbs: print("\n*) Создаю матрицу плотности P.")
p_scf = np.matrix([[0,0],[0,0]], dtype=np.float64) # Referencia (7) p. 148
#Начинаем итерации
if vbs: print("\n*)Обращаемся к функции SCF.")
#В ходе каждой итерации пытаемся приблизиться к таким значениям коэффициентов C, чтобы энергия молекулы была
#минимальной. Всякий раз пересчитываем матрицу Фока (~энергия, хотим минимизировать), матрицу
#коэффициентов перед одноатомными орбиталями C и электронную плотность.
#Если в какой-то момент электронная плотность перестаёт сильно меняться, считаем, что сошлись.
for iteracion in range(50):
# Конструируем матрицу Фока F
# F = H + G
if vbs: print("\n**) Конструируем матрицу Фока F")
g_scf = hfscf.G(r, p_scf, b1, b2, b) #двухэлектронная часть матрицы F
f_scf = h_scf + g_scf # Referencia (7) p. 141 eq. (3.154)
# Конструируем матрицу F'
# F' = X_adj * F * X
if vbs: print("**) Меняю базис F.")
f_tra = Xa * f_scf * X
# Диагонализируем матрицу F и конструируем матрицу C'
if vbs: print("**) Диагонализирую F' и генерирую C'.")
c_tra = hfscf.diagon2(m=f_tra)
# Конструируем матрицу C
# C = X * C'
if vbs: print("**) Конструирую матрицу коэффициентов C.")
c_scf = X * c_tra
# Пересчитываем P на основе коэффициентов C
if vbs: print("**) Пересчитываю матрицу плотности P.")
p_temp = hfscf.P(C=c_scf)
print("\nЗаканчиваю " + str(iteracion + 1) + " итерацию.\n")
#Проверка сходимости
if np.linalg.norm(p_temp - p_scf) < 1E-4: # Referencia (7) p. 148
print("\n\n-->Ура, сошлось!")
return {"S":s_scf,"H":h_scf,"X": X,"F":f_scf,"C":c_scf,"P":p_temp}
else:
p_scf = p_temp
print("\n\n-->Не сошлось!\n")
return {"S":s_scf,"H":h_scf,"X": X,"F":f_scf,"C":c_scf,"P":p_temp}
S - матрица перекрывания орбиталей. От того, насколько они перекрываются, зависит энергия системы.
F - матрица Фока. Некоторое приближение гамильтониана (в расчётах берём усреднённое взаимодействие электрона со всеми остальными электронами вместо того, чтобы учитывать взаимодействие каждой пары электронов отдельно)
X - диагонализированная матрица Фока
H - гамильтониан (~энергия)
C - матрица коэффициентов перед одноатомными орбиталями (складывая волновые функции для одноатомных орбиталей с этими коэффициентами получаем волновую функцию для молекулы)
my_orbitals = SCF()
my_orbitals
#1D графики волновых функций орбиталей атомов в молекуле водорода и квадратов волновых функций
hfscf.orbital(my_orbitals['C'])
#Соответствующие 2D графики
hfscf.orbital2D(my_orbitals['C'], my_orbitals['X'], my_orbitals['F'])
#Можем посчитать энергии
electron_energy = hfscf.ener_elec(my_orbitals['P'], my_orbitals['H'], my_orbitals['F'])
total_energy = hfscf.ener_tot()
#Электронная энергия молекулы
electron_energy
#Полная энергия молекулы
total_energy