import os
import subprocess
import numpy as np
import pandas as pd
from scipy import optimize
import matplotlib.pyplot as plt
pd.set_option('display.max_rows', 10)
def run_orca(name, path, refval, startval, step, iter_number):
result={}
init_val = refval - startval
for i in range(iter_number):
with open(os.path.join(os.getcwd(), f"{path}", '{}_{}.inp'.format(i, path)), 'w') as outfile:
value = init_val + i*step
newinp = name.format(value)
outfile.write(newinp)
p = subprocess.Popen(". ~/.bash_profile; orca {0}/{1}_{0}.inp".format(path, i), shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out = p.communicate()[0]
out = out.splitlines()
for outline in out:
if "FINAL SINGLE" in str(outline):
dict_value = float(outline.split()[-1])
result[value] = dict_value
return result
def fit_func_plot(x_0, y_0, criterium):
# Target function for dihedral angle
if criterium == "dih":
fitfunc = lambda p, x: p[0]*(np.cos(p[1]*x)) + p[2]
p0 = [1,1, 1]
errfunc = lambda p, x, y: fitfunc(p, x) - y
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_0, y_0))
print ("Optimized params:", p1)
# Target function for cc_bond with big step
elif criterium == "bond_ds":
fitfunc = lambda p, x: np.multiply(p[0],pow(x,p[1])) + np.multiply(p[2], pow(x,p[3])) - p[4]
p0 = [1, -12, -10, -2, 79]
errfunc = lambda p, x, y: fitfunc(p, x) - y
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_0, y_0))
print("Optimized params:", p1)
# Target function for hcc angle and cc_bond
else:
fitfunc = lambda p, x: p[0]*pow(p[1]-x,2) + p[2]
p0 = [1,1, -79]
errfunc = lambda p, x, y: fitfunc(p, x) - y
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_0, y_0))
print ("Optimized params:", p1)
plt.plot(x_0, y_0, "ro", x_0,fitfunc(p1,x_0),"r-",c='blue',alpha=0.5)
return plt.show()
# int 0 1 -- neutral charge (0), 1 multiplicity (2S + 1, where S -- total spin)
# S = (# of alpha electrons)(+1/2) + (# of beta electrons)(-1/2)
# Three first digits -- cartesian coordinates:
# first -- the number of the atom with which the atom forms a bond;
# second -- the number of the atom with which two atoms (they form a bond) form the angle;
# third -- the number of the atom with which three atoms (two -- common) form the dihedral angle;
# Last three values -- values of a bond, angle and dihedral angle.
orca_inp_bond = '''!HF RHF 6-31G
* int 0 1
C 0 0 0 0 0 0
C 1 0 0 {} 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
*
'''
energies_bond = run_orca(orca_inp_bond,"bond",1.52986,0.4,0.02,41)
df_bond = pd.DataFrame.from_dict(list(energies_bond.items()))
df_bond.rename(columns={0:"bond_length", 1:"energy"}, inplace=True)
df_bond
# Looks like a parabola.
x_bond = df_bond.bond_length
y_bond = df_bond.energy
fit_func_plot(x_bond, y_bond, "bond")
orca_inp_angle = '''!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 {} 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
*
'''
energies_angle = run_orca(orca_inp_angle,"angle",111.200,2,0.1,41)
df_angle = pd.DataFrame.from_dict(list(energies_angle.items()))
df_angle.rename(columns={0:"hcc_angle", 1:"energy"}, inplace=True)
df_angle
# Looks like a parabola.
x_angle = df_angle.hcc_angle
y_angle = df_angle.energy
fit_func_plot(x_angle, y_angle, "angle")
orca_inp_dih = '''!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 {}
H 2 1 6 1.08439 111.200 120
H 2 1 6 1.08439 111.200 -120
*
'''
energies_dih = run_orca(orca_inp_dih,"dih",-180,0,12,31)
df_dih = pd.DataFrame.from_dict(list(energies_dih.items()))
df_dih.rename(columns={0:"dih_angle", 1:"energy"}, inplace=True)
df_dih
# Looks like a cosinus.
x_dih = df_dih.dih_angle
y_dih = df_dih.energy
fit_func_plot(x_dih, y_dih, "dih")
energies_bond_ds = run_orca(orca_inp_bond,"bond_ds",1.52986,0.8,0.1,44)
df_bond_ds = pd.DataFrame.from_dict(list(energies_bond_ds.items()))
df_bond_ds.rename(columns={0:"bond_length", 1:"energy"}, inplace=True)
df_bond_ds
# Looks like a sum of power functions.
x_bond_ds = df_bond_ds.bond_length
y_bond_ds = df_bond_ds.energy
fit_func_plot(x_bond_ds, y_bond_ds, "bond_ds")