%matplotlib inline
import matplotlib.pyplot as plt
from scipy import optimize
import subprocess
import numpy as np
inp = '''!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 %.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 %.1f
H 2 1 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*
'''
ref_bond = 1.52986
ref_angle = 111.2
ref_dihed = 180
def run_orca(inp):
with open('orca.inp', 'w') as outfile:
outfile.write(inp)
p = subprocess.Popen("/srv/databases/orca/orca orca.inp",
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out=p.communicate()[0]
O = out.splitlines()
result = None
for line in O:
if 'FINAL SINGLE POINT ENERGY' in line:
result = line
# extract energy: FINAL SINGLE POINT ENERGY'
# and return it as float
return result
def fitparam(my_x,my_y,xlim=(0,3)):
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=(my_x,my_y))
print "Optimized params:", p1
#Plot it
plt.plot(my_x,my_y, "ro", my_x ,fitfunc(p1,my_x),"r-",c='blue',alpha=0.5)
plt.xlim(xlim)
plt.show()
res = []
ref = 1.52986
delta = 0.04
points = 70
if ref-(points/2*delta) < 0:
print("Negative bond length! You are idiot!")
L = np.arange(ref-delta*points/2,ref+delta*points/2,delta)
for i in L:
inpstr = inp % (i, ref_angle, ref_dihed)
res.append(run_orca(inpstr))
res = [float(x.split()[-1]) for x in res]
plt.scatter(L[3:],res[3:])
plt.show()
Похоже на потенциал Морзе, если присмотреться поближе
plt.scatter(L[15:],res[15:])
plt.show()
fitparam(L[15:-5],res[15:-5])
Вообще не туда
fitparam(L[18:-20],res[18:-20])
Уже поближе
fitparam(L[28:-25],res[28:-25])
Что-то похожее
Вспомним теперь о потенциале Морзе и попробуем его параметризовать. Начальная догадка для p[0] - глубина ямы, p[2] - длина связи. Хотя при фитировании это оказалась вовсе не длина связи
def fitmorse(my_x,my_y):
my_x = np.array(my_x)
my_y = np.array(my_y)
# f(x) = D*(1-e^(-a(x - x0)))^2
fitfunc = lambda p, x: p[0]*((1 - np.exp(-p[1]*(x-p[2])))**2) # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [-79, 1, -1.5] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(my_x,my_y))
print "Optimized params:", p1
#Plot it
plt.plot(my_x,my_y, "ro", my_x ,fitfunc(p1,my_x),"r-",c='blue',alpha=0.5)
plt.xlim(0,3)
plt.show()
fitmorse(L[3:],res[3:])
def angle():
res = []
ref = ref_angle
delta = 0.2
points = 20
if ref-(points/2*delta) < 0:
print("Negative bond length! You are idiot!")
L = np.arange(ref-delta*points/2,ref+delta*points/2,delta)
for i in L:
inpstr = inp % (ref_bond, i, ref_dihed)
res.append(run_orca(inpstr))
res = [float(x.split()[-1]) for x in res]
return L,res
lA, resA = angle()
plt.scatter(lA[:],resA[:])
plt.ylim([-79.082,-79.081])
plt.show()
Отличия в энергии незначительны. Опишем параболически
fitparam(lA,resA,(109,113))
def torsion():
res = []
L = np.arange(-180,181,6)
for i in L:
inpstr = inp % (ref_bond, ref_angle, i)
res.append(run_orca(inpstr))
return L,res
lT, resT = torsion()
resT = [float(x.split()[-1]) for c,x in enumerate(resT)]
plt.scatter(lT,resT)
Будем приближать косинусом
def fitcosine(my_x,my_y):
my_x = np.array(my_x)
my_y = np.array(my_y)
# f(x) = D*(1-e^(-a(x - x0)))^2
fitfunc = lambda p, x: p[0]*(np.cos(p[1]*x)) + p[2] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [1, 1, 1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(my_x,my_y))
print "Optimized params:", p1
#Plot it
plt.plot(my_x,my_y, "ro", my_x ,fitfunc(p1,my_x),"r-",c='blue',alpha=0.5)
plt.xlim(-180,180)
plt.show()
fitcosine(lT, resT)
Получилось