%matplotlib inline
import subprocess
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
import math
Зададим общий вид матрицы, в которой будет возможно изменять три позиции:
* длину связи (length)
* угол связи (angle)
* торсионный угол (torsion)
И запишем их начальные значения для дальнейшего использования
inp = '''!HF RHF 6-31G
* int 0 1
C 0 0 0 0 0 0
C 1 0 0 {length} 0 0
H 1 2 0 1.08439 {angle} 0
H 1 2 3 1.08439 {angle} 120
H 1 2 3 1.08439 {angle} -120
H 2 1 3 1.08439 {angle} {torsion1}
H 2 1 5 1.08439 {angle} {torsion2}
H 2 1 5 1.08439 {angle} {torsion3}
*
'''
#length=1.52986
#angle=111.2
#torsion1=180
#torsion2=120
#torsion3=-120
def run_orca(inp):
with open('orca.inp', 'w') as outfile:
outfile.write(inp)
p = subprocess.Popen("/home/shad/progs/bin/orca orca.inp",
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out=p.communicate()[0]
for i in out.splitlines():
if i.startswith("FINAL SINGLE POINT ENERGY"):
return(float(i[len("FINAL SINGLE POINT ENERGY"):]))
# extract energy: FINAL SINGLE POINT ENERGY'
# and return it as float
return out.splitlines()
length_energies = []
lengths = np.arange(-10, 10+1)*0.02 + 1.52986
print lengths
for length in lengths:
length_energies.append(run_orca(inp.format(
length = length,
angle = 111.2,
torsion1 = 180,
torsion2 = 120,
torsion3 = -120,
)))
Энергия, соответствующая дефолтным значениям углов и различным значениям длины связи:
print length_energies
angle_energies = []
angles = np.arange(-10, 10+1)*0.2 + 111.2
print angles
for angle in angles:
angle_energies.append(run_orca(inp.format(
length = 1.52986,
angle = angle,
torsion1 = 180,
torsion2 = 120,
torsion3 = -120,
)))
Энергия, соответствующая различным значениям валентного угла, но дефолтным значениям длины и торсионных углов:
print angle_energies
torsion_energies = []
torsions = np.arange(-180, 180+1, 12)
print torsions
for torsion in torsions:
torsion_energies.append(run_orca(inp.format(
length = 1.52986,
angle = 111.2,
torsion1 = torsion,
torsion2 = torsion - 60,
torsion3 = torsion + 60,
)))
Энергия, соответствующая различным знаечниям торсионного угла, при дефолтных значениях длины связи и валентного угла:
print torsion_energies
1) Зависимость энергии от длины связи
x_o=lengths
y_o=length_energies
#function is 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=(x_o, y_o))
print "Optimized params:", p1
print 'Function of approximation f(x)=k(b-x)^2 + a '
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Length vs Energie')
plt.xlabel('length')
plt.ylabel('energie')
plt.show()
2) Зависимость энергии от валентного угла
x_o=angles
y_o=angle_energies
#function is 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=(x_o, y_o))
print "Optimized params:", p1
print 'Function of approximation f(x)=k(b-x)^2 + a '
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Angle vs Energie')
plt.xlabel('angle')
plt.ylabel('energie')
plt.show()
3) Зависимость энергии от торсионного угла
x_o=torsions
y_o=torsion_energies
#function is 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=(x_o, y_o))
print "Optimized params:", p1
print 'Function of approximation f(x)=k(b-x)^2 + a '
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Torsion vs Energie')
plt.xlabel('torsion')
plt.ylabel('energie')
plt.show()
Можно попробовать провести аппроксимацию линейной комбинацией тригонометрических функций с константой:
$ f(x)=\alpha_0*\sin(\alpha_1x)+\alpha_2*\cos(\alpha_3x)+\alpha_4 $
x_o=torsions
y_o=torsion_energies
fitfunc = lambda p, x: p[0]*(np.sin(p[1]*x))+p[2]*(np.cos(p[3]*x))+p[4] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [1,1,1,1, -79] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_o, y_o))
print "Optimized params:", p1
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Torsion vs Energie')
plt.xlabel('torsion')
plt.ylabel('energie')
plt.show()
new_energies = []
news = np.arange(-10, 10+1)*0.1 + 1.52986
news
for new in news:
new_energies.append(run_orca(inp.format(
length = new,
angle = 111.2,
torsion1 = 180,
torsion2 = 120,
torsion3 = -120,
)))
print new_energies
Посмотрим на расположение точек
x_o=news
y_o=new_energies
plt.plot(x_o, y_o, "ro",c='blue',alpha=0.5)
plt.title('New length vs Energie')
plt.xlabel('new length')
plt.ylabel('energie')
plt.show()
Попробуем аппроксимацию гиперболой:
$ f(x)=\frac{\alpha_0}{\alpha_1 + x }+\alpha_2 $
x_o=news
y_o=new_energies
fitfunc = lambda p, x: p[0]*(1/(x+p[1]))+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=(x_o, y_o))
print "Optimized params:", p1
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('New length vs Energie')
plt.xlabel('new length')
plt.ylabel('energie')
plt.show()
Попробуем усложнить аппроксимирующую функцию:
$ f(x)=\frac{\alpha_0}{\exp(\alpha_1 * x +\alpha_2)}+\alpha_3 $
x_o=news
y_o=new_energies
fitfunc = lambda p, x: p[0]*1/(np.exp(p[1]*x+p[2]))+p[3] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [1,1,1, -79] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_o, y_o))
print "Optimized params:", p1
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('New length vs Energie')
plt.xlabel('new length')
plt.ylabel('energie')
plt.show()
1Eh=627,5 ккал/моль 0.63991924 Eh=401.5493231
Константа из статьи: 311 ккал/моль
Несмотря на то, что константы одного порядка, все равно отличие сильное. Возможно это отличие обусловлено импользованием различных методов для подсчета. Приближение, полученное в данной работе хоть и неплохое, но далеко от идеала. Возможно orca не учитывает какие-то уникальные свойства молекулы