%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
import subprocess
!orca
orca работает
Изменяем длину связи от 1.2 до 1.7 ангстрем с шагом 0.02.
def run_orca():
with subprocess.Popen("orca orca.inp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
out=p.communicate()[0].decode()
print(out)
for line in out.splitlines():
if 'FINAL SINGLE POINT' in line:
return float(line.strip().split()[4])
return None
bond_E = []
for length in np.round(np.arange(1.2,1.7,0.02),2):
inp = f'''!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 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 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*
'''
with open('orca.inp','w') as newfile:
newfile.write(inp)
energy = run_orca()
bond_E.append(energy)
Посмотрим, как выглядит зависимость.
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.scatter(np.round(np.arange(1.2,1.7,0.02),2), bond_E)
#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,-79, 1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc,
p0[:],
args=(np.round(np.arange(1.2,1.7,0.02),2), bond_E))
print("Optimized params:", p1)
#Plot it
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.plot(np.round(np.arange(1.2,1.7,0.02),2),
bond_E,
"ro",
np.round(np.arange(1.2,1.7,0.02),2),
fitfunc(p1, np.round(np.arange(1.2,1.7,0.02),2)))
plt.xlim(1.1,1.8)
plt.show()
Зависимость не очень хорошо аппроксимируется функцией. Попробуем выкинуть несколько точек.
#function is f(x)=k(b-x)^2 + a
x = np.round(np.arange(1.2,1.7,0.02),2)[9:]
y = bond_E[9:]
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,-79, 1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc,
p0[:],args=(x,y))
print("Optimized params:", p1)
#Plot it
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.plot(x,
y,
"ro",
x,
fitfunc(p1, x))
plt.xlim(1.1,1.8)
plt.show()
Выкинули первые 9 точек, и функция стала фиттиться гораздо лучше.
Изменяем угол HCC от 109.2 до 113.4 с шагом 0.1.
angle_E = []
for angle in np.round(np.arange(109.2,113.4,0.1),1):
inp = f'''!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 {angle} 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
*
'''
with open('orca.inp','w') as newfile:
newfile.write(inp)
energy = run_orca()
angle_E.append(energy)
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.scatter(np.round(np.arange(109.2,113.4,0.1),1), angle_E)
#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,-79, 1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc,
p0[:],
args=(np.round(np.arange(109.2,113.4,0.1),1), angle_E))
print("Optimized params:", p1)
#Plot it
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.plot(np.round(np.arange(109.2,113.4,0.1),1),
angle_E,
"ro",
np.round(np.arange(109.2,113.4,0.1),1),
fitfunc(p1, np.round(np.arange(109.2,113.4,0.1),1)))
plt.xlim(108,114)
plt.show()
Хорошо зафиттилось. Точки выкидывать не будем.
Изменяем торсионный угол от -180 до 180 с шагом 12.
torsion_E = []
for torsion in np.round(np.arange(-180,181,12),1):
inp = f'''!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 {torsion}
H 2 1 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*
'''
with open('orca.inp','w') as newfile:
newfile.write(inp)
energy = run_orca()
torsion_E.append(energy)
#function is f(x)=k/2 * (1+cos(n*x - g)) + a
fitfunc = lambda p, x: p[0] / 2 * (1 + np.cos(np.radians(p[1] * np.pi * x - p[2]))) + p[3]# Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
p0 = [1,1, 1,1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc,
p0[:],
args=(np.round(np.arange(-180,
181,
12),1), torsion_E))
print("Optimized params:", p1)
#Plot it
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.plot(np.round(np.arange(-180,181,12),1),
torsion_E,
"ro",
np.round(np.arange(-180,181,12),1),
fitfunc(p1, np.round(np.arange(-180,181,12),1)))
plt.show()
Зафиттилось тоже хорошо.
Изменяем длину связи от 0.1 до 5 с шагом 0.1.
bond_E2 = []
for length in np.round(np.arange(0.1,5,0.1),2):
inp = f'''!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 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 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*
'''
with open('orca.inp','w') as newfile:
newfile.write(inp)
energy = run_orca()
bond_E2.append(energy)
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.scatter(np.round(np.arange(0.1,5,0.1),2), bond_E2)
Нужно выкинуть начальные точки, потому что из-за их очень низкого значения (непонятно, почему такого низкого) не видно, как выглядит функция. А функция должна быть похожа на потенциал Морзе, потому что именно им в данном случае ее нужно аппроксимировать.
# morze potential
fitfunc = lambda p, x: p[0] * (1 - np.exp(- p[1] * (x - p[2]))) ** 2 + p[3] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function
x = np.round(np.arange(0.1,5,0.1),2)[4:]
y = bond_E2[4:]
p0 = [1,1,1,1] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(x,y))
print("Optimized params:", p1)
#Plot it
f, ax = plt.subplots(1,1, figsize=(7, 7))
plt.plot(x, y, "ro", x, fitfunc(p1, x))
plt.show()
Гораздо лучше без первых четырёх точек.
from IPython.core.display import display, HTML
html_custom = '<h4>Файлы, полученные выше, лежат в этой <a href="https://kodomo.fbb.msu.ru/~agayeva_zarifa/term8/pr6_files">папке</a>.</h4>'
display(HTML(html_custom))