Вычисление параметров для молекулярной механики

Суть задания состоит в определении констант ковалентных взаимодействий для молекулярной механики на основе квантово-химических расчётов. Считать будем для молекулы этана.

Это оптимизированная структура этана в виде z-matrix. Нужно сделать 20 значений связи С-С с шагом +-0.02 (по 10 в разные стороны). Запишем в 20 файлов ethaneXX.txt, где ХХ - номер от 0 до 20.

In [1]:
def gen_inp():
    for i in range(-10,10):
        bond = 1.52986 + i*0.02

        inp = '''!HF RHF 6-31G
        * int 0 1
        C 0 0 0 0 0 0 
        C 1 0 0 %f 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
        *
        ''' % bond
        output_name = 'ethane_%i.txt' %(i+10)
        output_file = open(output_name,"w")
        output_file.writelines(inp)
        output_file.close()
        

Будем запускать ORCA с этими параметрами. На выходе - значение энергии структуры (FINAL SINGLE POINT ENERGY).

In [8]:
import subprocess
def run_orca(num):
    cmd1 = '/srv/databases/orca/orca ethane_%d.txt > orca_temp.txt' %num
    cmd2 = 'grep "FINAL SINGLE POINT ENERGY" orca_temp.txt'
    subprocess.call(cmd1, shell=True)
    p = subprocess.Popen(cmd2, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p_status = p.wait()
    out=iter(p.stdout.readline, b'')
    for line in out:
        energy = line.strip(None).strip('FINAL SINGLE POINT ENERGY').strip()

    return float(energy)

Получим значения энергии для каждой длины С-С связи:

In [3]:
for i in range(0,21): 
    print run_orca(i)
    
-79.0459655919
-79.0536030492
-79.0600949345
-79.0655448563
-79.0700475248
-79.073689506
-79.0765499172
-79.0787010621
-79.0802089959
-79.0811340769
-79.0815314323
-79.0814514061
-79.0809399644
-79.0800390642
-79.0787869926
-79.077218678
-79.0753659752
-79.0732579217
-79.0709209862
-79.0683792826
-79.0814176838

Нарисуем полученную зависимость энергии от длины С-С связи.

In [11]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize 
from scipy.fftpack import fft, ifft
import math 
In [40]:
# x array , lengths of C-C bonds
x_o=[]
# y array, energies
y_o=[]

for i in range(-10,10):
    bond = 1.52986 + i*0.02
    x_o.append(bond) 
    energy = run_orca(i+10)
    y_o.append(energy)
In [42]:
x_o=np.array(x_o)
y_o=np.array(y_o)
print x_o
print y_o
#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

#Plot it
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.xlim(1,2)
plt.show()
[ 1.32986  1.34986  1.36986  1.38986  1.40986  1.42986  1.44986  1.46986
  1.48986  1.50986  1.52986  1.54986  1.56986  1.58986  1.60986  1.62986
  1.64986  1.66986  1.68986  1.70986]
[-79.04596559 -79.05360305 -79.06009493 -79.06554486 -79.07004752
 -79.07368951 -79.07654992 -79.07870106 -79.080209   -79.08113408
 -79.08153143 -79.08145141 -79.08093996 -79.08003906 -79.07878699
 -79.07721868 -79.07536598 -79.07325792 -79.07092099 -79.06837928]
Optimized params: [  0.66824637   1.55389273 -79.08233322]

Смотрим на строку Optimized params: [ 0.66824637 1.55389273 -79.08233322]

Первое число - это коэффициент жесткости связи как пружинки: 0.66824637 эВ = 15.41 ккал/моль = 64.48 кДж/моль. Для пересчета я использовала конвертер: http://www.colby.edu/chemistry/PChem/Hartree.html

Парабола не точно совпадает с точками, т.к. межатомный потенциал на самом деле не является параболическим, а описывается более сложными функциями.

Теперь проведем аналогичные операции для валентного угла HCС. Его значения должны изменяться от 109.2 до 113.2. Аналогично, запишем в 20 файлов ethaneXX.txt, где ХХ - номер от 20 до 40.

In [34]:
def gen_inp2():
    for i in range(0,21):
        angle = 109.2 + i*0.2

        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 %f 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
        *
        ''' % angle
        output_name = 'ethane_%i.txt' %(i+20)
        output_file = open(output_name,"w")
        output_file.writelines(inp)
        output_file.close()
gen_inp2()        
In [12]:
ls
ethane_0.gbw    ethane_13.ges   ethane_18.prop  ethane_28.txt  ethane_5.ges
ethane_0.ges    ethane_13.prop  ethane_18.txt   ethane_29.txt  ethane_5.prop
ethane_0.prop   ethane_13.txt   ethane_19.gbw   ethane_3.gbw   ethane_5.txt
ethane_0.txt    ethane_14.gbw   ethane_19.ges   ethane_3.ges   ethane_6.gbw
ethane_1.gbw    ethane_14.ges   ethane_19.prop  ethane_3.prop  ethane_6.ges
ethane_1.ges    ethane_14.prop  ethane_19.txt   ethane_3.txt   ethane_6.prop
ethane_1.prop   ethane_14.txt   ethane_2.gbw    ethane_30.txt  ethane_6.txt
ethane_1.txt    ethane_15.gbw   ethane_2.ges    ethane_31.txt  ethane_7.gbw
ethane_10.gbw   ethane_15.ges   ethane_2.prop   ethane_32.txt  ethane_7.ges
ethane_10.ges   ethane_15.prop  ethane_2.txt    ethane_33.txt  ethane_7.prop
ethane_10.prop  ethane_15.txt   ethane_20.gbw   ethane_34.txt  ethane_7.txt
ethane_10.txt   ethane_16.gbw   ethane_20.ges   ethane_35.txt  ethane_8.gbw
ethane_11.gbw   ethane_16.ges   ethane_20.prop  ethane_36.txt  ethane_8.ges
ethane_11.ges   ethane_16.prop  ethane_20.txt   ethane_37.txt  ethane_8.prop
ethane_11.prop  ethane_16.txt   ethane_21.txt   ethane_38.txt  ethane_8.txt
ethane_11.txt   ethane_17.gbw   ethane_22.txt   ethane_39.txt  ethane_9.gbw
ethane_12.gbw   ethane_17.ges   ethane_23.txt   ethane_4.gbw   ethane_9.ges
ethane_12.ges   ethane_17.prop  ethane_24.txt   ethane_4.ges   ethane_9.prop
ethane_12.prop  ethane_17.txt   ethane_25.txt   ethane_4.prop  ethane_9.txt
ethane_12.txt   ethane_18.gbw   ethane_26.txt   ethane_4.txt   orca_temp.txt
ethane_13.gbw   ethane_18.ges   ethane_27.txt   ethane_5.gbw   pr6.ipynb
In [36]:
for i in range(20,41): 
    print run_orca(i)
-79.0814176838
-79.081443973
-79.0814669357
-79.0814865764
-79.0815028998
-79.0815159105
-79.0815256131
-79.0815320122
-79.0815351121
-79.0815349173
-79.0815314323
-79.0815246614
-79.0815146089
-79.0815012792
-79.0814846764
-79.0814648048
-79.0814416686
-79.0814152719
-79.0813856188
-79.0813527134
-79.0813165588
In [37]:
# x array , HCC angles
x_o=[]
# y array, energies
y_o=[]

for i in range(0,21):
    angle = 109.2 + i*0.2
    x_o.append(angle) 
    energy = run_orca(i+20)
    y_o.append(energy)
In [38]:
x_o=np.array(x_o)
y_o=np.array(y_o)
print x_o
print y_o
#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

#Plot it
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Energy(angle)')
plt.xlim(108,115)
plt.show()
[ 109.2  109.4  109.6  109.8  110.   110.2  110.4  110.6  110.8  111.
  111.2  111.4  111.6  111.8  112.   112.2  112.4  112.6  112.8  113.
  113.2]
[-79.08141768 -79.08144397 -79.08146694 -79.08148658 -79.0815029
 -79.08151591 -79.08152561 -79.08153201 -79.08153511 -79.08153492
 -79.08153143 -79.08152466 -79.08151461 -79.08150128 -79.08148468
 -79.0814648  -79.08144167 -79.08141527 -79.08138562 -79.08135271
 -79.08131656]
Optimized params: [  4.10774432e-05   1.10890767e+02  -7.90815354e+01]

Здесь коэффициент жесткости равен 0.00397 кДж/моль.

Проделаем аналогичные операции для торсионного угла HCCH, его значения должны изменяться от -180 до 180 c шагом 12. Аналогично, запишем в 30 файлов ethaneXX.txt, где ХХ - номер от 41 до 72.

In [17]:
def gen_inp3():
    x_o=[]
    for i in range(0,31):
        dihedral = -180 + i*12
        x_o.append(dihedral)
        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 %f
        H 2 1 6 1.08439 111.200 120
        H 2 1 6 1.08439 111.200 -120
        *
        ''' % dihedral
        output_name = 'ethane_%i.txt' %(i+41)
        output_file = open(output_name,"w")
        output_file.writelines(inp)
        output_file.close()
    return x_o

print gen_inp3()
x_o = gen_inp3()
[-180, -168, -156, -144, -132, -120, -108, -96, -84, -72, -60, -48, -36, -24, -12, 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180]
In [7]:
y_o=[]
for i in range(41,72): 
    energy = run_orca(i)
    print energy
    y_o.append(energy)
-79.1975724044
-79.1971377109
-79.1959965234
-79.1945797241
-79.1934285682
-79.192987718
-79.1934285683
-79.194579724
-79.1959965233
-79.1971377108
-79.1975724044
-79.1971377107
-79.1959965232
-79.194579724
-79.1934285682
-79.192987718
-79.1934285682
-79.1945797241
-79.1959965234
-79.1971377109
-79.1975724044
-79.1971377109
-79.1959965234
-79.1945797241
-79.1934285682
-79.192987718
-79.1934285682
-79.1945797241
-79.1959965234
-79.1971377109
-79.1975724044
In [23]:
x_o=np.array(x_o)
y_o=np.array(y_o)
print x_o
print y_o

#former 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

#and what if function is k*cos(nx) + a?
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, -79] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_o, y_o))
yfft = fft(y_o)
print "Optimized params:", p1

#Plot it
#plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",x_o, yfft,"r-",c='blue',alpha=0.5)
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Energy(dihedral)')
plt.xlim(-200,200)
plt.show()
[-180 -168 -156 -144 -132 -120 -108  -96  -84  -72  -60  -48  -36  -24  -12
    0   12   24   36   48   60   72   84   96  108  120  132  144  156  168
  180]
[-79.1975724  -79.19713771 -79.19599652 -79.19457972 -79.19342857
 -79.19298772 -79.19342857 -79.19457972 -79.19599652 -79.19713771
 -79.1975724  -79.19713771 -79.19599652 -79.19457972 -79.19342857
 -79.19298772 -79.19342857 -79.19457972 -79.19599652 -79.19713771
 -79.1975724  -79.19713771 -79.19599652 -79.19457972 -79.19342857
 -79.19298772 -79.19342857 -79.19457972 -79.19599652 -79.19713771
 -79.1975724 ]
Optimized params: [  2.29204886e-03   9.94834578e-01  -7.91952843e+01]

Таким образом, полученную зависимость энергии от торсионного угла можно хорошо аппроксимировать функцией 0,002*cos(0,99x)-79.

Наблюдаем три минимума энергии при изменении торсионного угла HCCH от -180 до 180. Это соответствует трем заторможенным конформациям молекулы этана.

Увеличим шаг до 0,1 при расчете связи. Полученная зависимость плохо аппроксимируется параболой и хорошо - потенциалом Морзе.

In [7]:
def gen_inp4():
    x_o=[]
    for i in range(-10,10):
        bond = 1.52986 + i*0.1
        x_o.append(bond)
        inp = '''!HF RHF 6-31G
        * int 0 1
        C 0 0 0 0 0 0 
        C 1 0 0 %f 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
        *
        ''' % bond
        output_name = 'ethane_%i.txt' %(i+100)
        output_file = open(output_name,"w")
        output_file.writelines(inp)
        output_file.close()
    return x_o

print gen_inp4()
x_o = gen_inp4()        
[0.52986, 0.62986, 0.72986, 0.8298599999999999, 0.9298599999999999, 1.02986, 1.1298599999999999, 1.22986, 1.32986, 1.42986, 1.52986, 1.62986, 1.72986, 1.82986, 1.9298600000000001, 2.02986, 2.12986, 2.22986, 2.32986, 2.42986]
In [9]:
y_o=[]
for i in range(90,110): 
    energy = run_orca(i)
    print energy
    y_o.append(energy)
-73.547449091
-75.7731892721
-77.1455639552
-77.9863168367
-78.5009745754
-78.8137249075
-79.0002303742
-79.1073691788
-79.164631076
-79.1907314599
-79.197572401
-79.1927077525
-79.180908516
-79.1651648824
-79.1473362559
-79.1285768829
-79.1096103388
-79.0908991001
-79.0727437633
-79.0553382591
In [12]:
x_o=np.array(x_o)
y_o=np.array(y_o)
print x_o
print y_o
#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

#Plot it
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Energy(bond)')
#plt.xlim(108,115)
plt.show()
[ 0.52986  0.62986  0.72986  0.82986  0.92986  1.02986  1.12986  1.22986
  1.32986  1.42986  1.52986  1.62986  1.72986  1.82986  1.92986  2.02986
  2.12986  2.22986  2.32986  2.42986]
[-73.54744909 -75.77318927 -77.14556396 -77.98631684 -78.50097458
 -78.81372491 -79.00023037 -79.10736918 -79.16463108 -79.19073146
 -79.1975724  -79.19270775 -79.18090852 -79.16516488 -79.14733626
 -79.12857688 -79.10961034 -79.0908991  -79.07274376 -79.05533826]
Optimized params: [  2.92138601   1.75787795 -79.67571834]
In [24]:
x_o=np.array(x_o)
y_o=np.array(y_o)
print x_o
print y_o
#function is  f(x)=(1-e^(-k(x-a)))^2
fitfunc = lambda p, x: p[0]*pow(1-np.e**(-p[1]*(x-p[2])),2) # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Error function

p0 = [-79,45,0.5] # Initial guess for the parameters
p1, success = optimize.leastsq(errfunc, p0[:], args=(x_o, y_o))
print "Optimized params:", p1

#Plot it
plt.plot(x_o, y_o, "ro", x_o,fitfunc(p1,x_o),"r-",c='blue',alpha=0.5)
plt.title('Energy(bond)')
#plt.xlim(108,115)
plt.show()
[ 0.52986  0.62986  0.72986  0.82986  0.92986  1.02986  1.12986  1.22986
  1.32986  1.42986  1.52986  1.62986  1.72986  1.82986  1.92986  2.02986
  2.12986  2.22986  2.32986  2.42986]
[-73.54744909 -75.77318927 -77.14556396 -77.98631684 -78.50097458
 -78.81372491 -79.00023037 -79.10736918 -79.16463108 -79.19073146
 -79.1975724  -79.19270775 -79.18090852 -79.16516488 -79.14733626
 -79.12857688 -79.10961034 -79.0908991  -79.07274376 -79.05533826]
Optimized params: [-79.16869674   5.32250335  -0.09264472]