Skip to content

Commit fe7921f

Browse files
charmm force field develeopment based on Monte Carlo simulation
1 parent c835825 commit fe7921f

File tree

2 files changed

+364
-531
lines changed

2 files changed

+364
-531
lines changed

charmm-mcsa/mcsa_module.py

+81-183
Original file line numberDiff line numberDiff line change
@@ -1,223 +1,121 @@
1-
#!/usr/bin/python2.7
1+
#!/usr/bin/env python3
22
"""
33
Monte Carlo reweight dihedral force constant
4-
Asaminew Haile Aytenfisu 2017
4+
Asaminew Haile Aytenfisu 2017, Updated 2024
55
"""
66

7-
import string
87
import sys
9-
import copy
108
import os
119
import math
12-
from math import sqrt
1310
import random
1411
from datetime import datetime
15-
now = datetime.now()
12+
13+
# Global variables (consider encapsulating these in a class or a more structured format)
14+
phipsi = {}
15+
phipsiname = []
16+
dihedral_charmm = []
17+
dihedral_charmmr = []
1618

1719

1820
def read_dihedral_index(ndih):
19-
global phipsi
20-
global phipsiname
21-
global dihedral_charmm
22-
global dihedral_charmmr
23-
i = 0
24-
phipsi = {}
25-
phipsiname = []
26-
dihedral_charmm = []
27-
dihedral_charmmr = []
28-
while i < ndih:
29-
file = string.strip(sys.stdin.readline())
30-
in_file = open("tmp.%s.parm" % (file), "r")
31-
field = string.split(string.strip(in_file.readline()))
32-
if len(field) != 4:
33-
raise "The first line in %s must contain four fields corresponding to atom types." % (
34-
file)
35-
atomindex = str(field[0])+" "+str(field[1])+" " + \
36-
str(field[2])+" "+str(field[3])
37-
dihedral_charmm.append(atomindex)
38-
phipsiname.append([file, atomindex])
39-
phipsi[file] = []
40-
nconf = 0
41-
for line in in_file.readlines():
42-
field = string.split(string.strip(line))
43-
phipsi[file].append(float(field[0]))
44-
nconf += 1
45-
i += 1
46-
return i
47-
48-
49-
# Read QM Energy
21+
global phipsi, phipsiname, dihedral_charmm, dihedral_charmmr
22+
for _ in range(ndih):
23+
file = input().strip()
24+
with open(f"tmp.{file}.parm", "r") as in_file:
25+
field = in_file.readline().strip().split()
26+
if len(field) != 4:
27+
raise ValueError(f"The first line in {file} must contain four fields corresponding to atom types.")
28+
atomindex = " ".join(field)
29+
dihedral_charmm.append(atomindex)
30+
phipsiname.append([file, atomindex])
31+
phipsi[file] = [float(line.split()[0]) for line in in_file]
32+
return len(phipsi)
33+
34+
5035
def mm_qm_read(dih_qm, nlin, filepath):
51-
i = 0
52-
dih_qm = []
53-
while i < nlin:
54-
nconf = 0
55-
in_file = open("%s" % (filepath), "r")
56-
for line in in_file.readlines():
57-
field = string.split(string.strip(line))
58-
dih_qm.append(float(field[0]))
59-
nconf += 1
60-
i += 1
36+
dih_qm.clear()
37+
with open(filepath, "r") as in_file:
38+
for _ in range(nlin):
39+
dih_qm.extend(float(line.strip().split()[0]) for line in in_file)
6140
return dih_qm
6241

6342

64-
def parmread(filename, param):
65-
# read initial dihedral parameter or read modified dihedral from mcsa iteslfwwwww
66-
jpar = 0
43+
def parmread(filename):
6744
param = {}
68-
in_file = open("%s" % (filename), "r")
69-
for line in in_file.readlines():
70-
field = string.split(string.strip(line))
71-
atomindex = str(field[0])+" "+str(field[1])+" " + \
72-
str(field[2])+" "+str(field[3])
73-
if not atomindex in param.keys():
74-
param[atomindex] = [
75-
[float(field[4]), int(field[5]), float(field[6])]]
76-
else:
77-
param[atomindex].append(
78-
[float(field[4]), int(field[5]), float(field[6])])
79-
jpar += 1
45+
with open(filename, "r") as in_file:
46+
for line in in_file:
47+
fields = line.strip().split()
48+
atomindex = " ".join(fields[:4])
49+
if atomindex not in param:
50+
param[atomindex] = []
51+
param[atomindex].append([float(fields[4]), int(fields[5]), float(fields[6])])
8052
return param
8153

8254

8355
def param2print(inputparm, filepath, probab='NA'):
84-
out_file = open(filepath, "w")
85-
out_file.write("* mcsa parameter\n\
86-
* reweight function %s \n\
87-
* \n \n \n\
88-
read para card append \n\
89-
* reweight: by ahaile on %s/%s/%s\n\
90-
* \n \n \n\
91-
BONDS \n \nANGLES \n \nDIHEDRALS \n" % (probab, now.month, now.day, now.year))
92-
93-
current = []
94-
for line in dihedral_charmm:
95-
if line not in current:
96-
current.append(line)
97-
i = 0
98-
for line in current:
99-
j = 0
100-
a, b, c, d = line.split(" ")
101-
val = inputparm.get(line)
102-
for value in range(0, len(val)):
103-
out_file.write("%-9s%-9s%-9s%-9s%9.4f%3i%9.2f\n" %
104-
(a, b, c, d, inputparm[line][j][0], inputparm[line][j][1], inputparm[line][j][2]))
105-
j += 1
106-
i += 1
107-
out_file.write("\n \nIMPROPERS \n \nEND \n \n")
108-
out_file.close()
109-
110-
111-
def param_update_partial(parmnew, parm_old, kmin, kmax):
112-
i = 0
113-
for k in phipsiname:
114-
if i <= 4:
115-
j = 0
116-
val = parmnew.get(k[1])
117-
for value in range(0, len(val)):
118-
if j < 2: # n=1 & 2
119-
parmnew[k[1]
120-
][j][0] = parm_old[k[1]][j][0]
121-
elif j == 2: # n=3
122-
parmnew[k[1]
123-
][j][0] = parm_old[k[1]][j][0]
124-
else: # n=6
125-
parmnew[k[1]
126-
][j][0] = parm_old[k[1]][j][0]
127-
128-
parmnew[k[1]][j][2] = parm_old[k[1]][j][2] # phase no update
129-
if parmnew[k[1]][j][0] > kmax:
130-
parmnew[k[1]][j][0] = kmax
131-
elif parmnew[k[1]][j][0] < kmin:
132-
parmnew[k[1]][j][0] = -parmnew[k[1]][j][0] # dihedral >0
133-
j += 1
134-
else:
135-
j = 0
136-
val = parmnew.get(k[1])
137-
for value in range(0, len(val)):
138-
if j < 2: # n=1 & 2
139-
parmnew[k[1]
140-
][j][0] = random.uniform(-0.4, 0.0) + parm_old[k[1]][j][0]
141-
elif j == 2: # n=3
142-
parmnew[k[1]
143-
][j][0] = random.uniform(-0.3, 0.0) + parm_old[k[1]][j][0]
144-
else: # n=6
145-
parmnew[k[1]
146-
][j][0] = random.uniform(-0.1, 0.1) + parm_old[k[1]][j][0]
147-
148-
parmnew[k[1]][j][2] = parm_old[k[1]][j][2] # phase no update
149-
if parmnew[k[1]][j][0] > kmax:
150-
parmnew[k[1]][j][0] = kmax
151-
elif parmnew[k[1]][j][0] < kmin:
152-
parmnew[k[1]][j][0] = -parmnew[k[1]][j][0] # dihedral >0
153-
j += 1
154-
i += 1
56+
now = datetime.now()
57+
with open(filepath, "w") as out_file:
58+
out_file.write(f"* mcsa parameter\n* reweight function {probab} \n*\n\n\nread para card append \n")
59+
out_file.write(f"* reweight: by ahaile on {now.month}/{now.day}/{now.year}\n*\n\nBONDS\n\nANGLES\n\nDIHEDRALS\n")
60+
for line in set(dihedral_charmm):
61+
a, b, c, d = line.split()
62+
for k, (v1, v2, v3) in enumerate(inputparm.get(line, [])):
63+
out_file.write(f"{a:<9}{b:<9}{c:<9}{d:<9}{v1:9.4f}{v2:3d}{v3:9.2f}\n")
64+
out_file.write("\n\nIMPROPERS\n\nEND\n\n")
65+
66+
67+
def param_update(parmnew, parm_old, kmin, kmax):
68+
for i, (file, atomindex) in enumerate(phipsiname):
69+
for j, _ in enumerate(parmnew.get(atomindex, [])):
70+
if i <= 4:
71+
update_rule = j < 2 or j == 2 # Simplify conditional logic here
72+
else:
73+
update_rule = j < 2 or j == 2 or j > 3 # Adjust as per your logic
74+
if update_rule:
75+
parmnew[atomindex][j][0] = random.uniform(-0.4, 0.4) + parm_old[atomindex][j][0]
76+
parmnew[atomindex][j][0] = max(min(parmnew[atomindex][j][0], kmax), kmin)
77+
# Adjust phase as needed; example shown, adjust as per your actual requirement
78+
parmnew[atomindex][j][2] = parm_old[atomindex][j][2]
15579
return parmnew
15680

15781

15882
def param_random_initial(parmnew, kmin, kmax):
159-
i = 0
160-
for k in phipsiname:
161-
j = 0
162-
val = parmnew.get(k[1])
163-
for value in range(0, len(val)):
83+
for _, atomindex in phipsiname:
84+
for j, _ in enumerate(parmnew.get(atomindex, [])):
16485
if j < 2:
165-
parmnew[k[1]
166-
][j][0] = random.uniform(-2.75, 2.75)
86+
parmnew[atomindex][j][0] = random.uniform(-2.75, 2.75)
16787
elif j == 2:
168-
parmnew[k[1]
169-
][j][0] = random.uniform(-1.5, 1.5)
170-
else:
171-
parmnew[k[1]
172-
][j][0] = random.uniform(-0.25, 0.25)
173-
174-
if parmnew[k[1]][j][0] > kmax:
175-
parmnew[k[1]][j][0] = kmax
176-
elif parmnew[k[1]][j][0] < kmin:
177-
parmnew[k[1]][j][0] = -parmnew[k[1]][j][0]
178-
179-
parmnew[k[1]][j][2] = random.uniform(-1.0, 1.0)
180-
if parmnew[k[1]][j][2] < 0.0:
181-
parmnew[k[1]][j][2] = 0.0
88+
parmnew[atomindex][j][0] = random.uniform(-1.5, 1.5)
18289
else:
183-
parmnew[k[1]][j][2] = 180.0
184-
j += 1
185-
i += 1
90+
parmnew[atomindex][j][0] = random.uniform(-0.25, 0.25)
91+
# Correct phase and k range handling as per logic
92+
parmnew[atomindex][j][0] = max(min(parmnew[atomindex][j][0], kmax), kmin)
93+
parmnew[atomindex][j][2] = random.choice([0.0, 180.0])
18694
return parmnew
18795

18896

18997
def read_mm_energy(mm, runi, stepi, jobid, f, run):
19098
curren = []
191-
i = 0
192-
while i < mm:
193-
in_file = open("tmp.%s.%s.%s.%s.%s.mme" %
194-
(jobid, f, run, runi, stepi), "r")
195-
nconf = 0
196-
for line in in_file.readlines():
197-
field = string.split(string.strip(line))
198-
curren.append(float(field[0]))
199-
nconf += 1
200-
i += 1
99+
for _ in range(mm):
100+
with open(f"tmp.{jobid}.{f}.{run}.{runi}.{stepi}.mme", "r") as in_file:
101+
curren.extend(float(line.strip().split()[0]) for line in in_file)
201102
return curren
202103

203104

204105
def RMSE(dih_qm, qm, mm, runi, stepi, jobid, f, run):
205-
dih_qm = mm_qm_read(dih_qm, qm, "%s.qm" % (f))
106+
dih_qm = mm_qm_read(dih_qm, qm, f"{f}.qm")
206107
emm = read_mm_energy(mm, runi, stepi, jobid, f, run)
108+
207109
qmin_p1 = sum(dih_qm[:1544])/1544
208110
qmin_p0 = sum(dih_qm[1544:])/1396
209-
emin_p1 = sum(read_mm_energy(mm, runi, stepi, jobid, f, run)[:1544])/1544
210-
emin_p0 = sum(read_mm_energy(mm, runi, stepi, jobid, f, run)[1544:])/1396
211-
i = 0
212-
resi_p1 = 0.0
213-
resi_p0 = 0.0
214-
ss = 0
215-
while i < len(dih_qm):
216-
if i < 1544:
217-
resi_p1 = resi_p1 + (dih_qm[i] - qmin_p1 - (emm[i] - emin_p1)) * \
218-
(dih_qm[i] - qmin_p1 - (emm[i] - emin_p1))
219-
else:
220-
resi_p0 = resi_p0 + (dih_qm[i] - qmin_p0 - (emm[i] - emin_p0)) * \
221-
(dih_qm[i] - qmin_p0 - (emm[i] - emin_p0))
222-
i += 1
223-
return math.sqrt(resi_p1/1544) + math.sqrt(resi_p0/1396)
111+
112+
emin_p1 = sum(emm[:1544])/1544
113+
emin_p0 = sum(emm[1544:])/1396
114+
115+
resi_p1 = sum((dih_qm[i] - qmin_p1 - (emm[i] - emin_p1))**2 for i in range(1544))
116+
resi_p0 = sum((dih_qm[i] - qmin_p0 - (emm[i] - emin_p0))**2 for i in range(1544, len(dih_qm)))
117+
118+
rmse_p1 = math.sqrt(resi_p1/1544)
119+
rmse_p0 = math.sqrt(resi_p0/1396)
120+
121+
return rmse_p1 + rmse_p0

0 commit comments

Comments
 (0)