Наша цель состоит в том, что бы рассчитать 20 разных длинн связи с шагом 0.02 ангстрема для расчёта энергии в ORCA с разными значениями по длине одной из связей (C-C)
%matplotlib inline
import subprocess
import matplotlib.pyplot as plt
import numpy as np
from scipy import optimize
#Для расчета разных значений длин связи испортируем функцию orca
def run_orca(inp):
with open('orca.inp', 'w') as outfile:
outfile.write(inp)
with subprocess.Popen("/srv/databases/orca/orca orca.inp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
out=p.communicate()[0].decode()
for l in out.splitlines():
if 'FINAL SINGLE POINT' in l:
return float(l.strip().split()[4])
return None
inp = '''!HF RHF 6-31G
* int 0 1
C 0 0 0 0 0 0
C 1 0 0 1.52986 0 0
H 1 2 0 1.08439 111.200 0
H 1 2 3 1.08439 111.200 120
H 1 2 3 1.08439 111.200 -120
H 2 1 3 1.08439 111.200 180
H 2 1 5 1.08439 111.200 120
H 2 1 5 1.08439 111.200 -120
*
'''
run_orca(inp)
Сделаем шаблоны
bond = '''!HF RHF 6-31G
* int 0 1
C 0 0 0 0 0 0
C 1 0 0 {:.5f} 0 0
H 1 2 0 1.08439 111.200 0
H 1 2 3 1.08439 111.200 120
H 1 2 3 1.08439 111.200 -120
H 2 1 3 1.08439 111.200 180
H 2 1 5 1.08439 111.200 120
H 2 1 5 1.08439 111.200 -120
*
'''
angle = '''!MP2 6-31G*
* int 0 1
C 0 0 0 0 0 0
C 1 0 0 1.52986 0 0
H 1 2 0 1.08439 {:.3f} 0
H 1 2 3 1.08439 111.200 120
H 1 2 3 1.08439 111.200 -120
H 2 1 3 1.08439 111.200 180
H 2 1 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*'''
tors = '''!MP2 6-311G**
* int 0 1
C 0 0 0 0 0 0
C 1 0 0 1.52986 0 0
H 1 2 0 1.08439 111.200 0
H 1 2 3 1.08439 111.200 120
H 1 2 3 1.08439 111.200 -120
H 2 1 3 1.08439 111.200 {:d}
H 2 1 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*'''
#сделаем массив с шагом по длине связи
bonds = np.arange(1.3, 1.7, 0.02)
bonds
bond_energies = np.array([run_orca(bond.format(value))
for value in bonds])
bond_energies
Отрисуем зависимость длины связи от энергии
#функция f(x)=k(b-x)^2 + a
fitfunc = lambda p, x: p[0] * pow(p[1] - x, 2) + p[2] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [1, 1, -79] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(bonds, bond_energies))
print("Optimized params:", p1)
#Plot it
plt.plot(bonds, bond_energies, 'ro',color='blue', alpha=0.5)
plt.plot(bonds, fitfunc(p1, bonds), "r-", c='red')
#plt.xlim(1,2)
plt.show()
Orca рассчитал связь в 1.54783147 ангстрем. В статье о разработке поля GAFF указана длина C-C 1.526. Разница довольно заметная, но тут вклад еще вносит неточность в фите - по результатам минимум приходится на меньшее значение, которое ближе к статье.
#сделаем массив с шагом по величине валентного угла HCС
angles = np.arange(109.2,113.3,0.2)
angles
angle_energies = np.array([run_orca(angle.format(value))
for value in angles])
angle_energies
Отрисуем зависимость величины угла от энергии
#функция f(x)=k(b-x)^2 + a
fitfunc = lambda p, x: p[0] * pow(p[1] - x, 2) + p[2] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [1, 1, -79] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(angles, angle_energies))
print("Optimized params:", p1)
#Plot it
plt.plot(angles, angle_energies, 'ro',color='blue', alpha=0.5)
plt.plot(angles, fitfunc(p1, angles), "r-", c='red')
#plt.xlim(1,2)
plt.show()
Оптимизация прошла на порядок лучше. Данных в статье не нашла(
#сделаем массив с шагом по величине торсионного угла CС
torses = np.arange(-180, 181, 12)
torses
tors_energies = np.array([run_orca(tors.format(value))
for value in torses])
tors_energies
fitfunc = lambda p, x: p[0] * (1 + np.cos(p[1] * np.pi * np.radians(x) - p[2])) + p[3] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [0, 1, -1, -1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(torses, tors_energies))
print("Optimized params:", p1)
#Plot it
plt.plot(torses, tors_energies, "ro", c='blue', alpha=0.5)
good_torses = np.linspace(-180, 180, 361)
plt.plot(good_torses, fitfunc(p1, good_torses), "r-", c='red')
#plt.xlim(1,2)
plt.show()
Минимумы находятся на отметках -180, -60, 60, 180 — с периодом в 120. Это описывает заторможенную конформацию этана.