Skip to content

Commit 5b7c6cd

Browse files
authored
Merge pull request #74 from wehs7661/bug-fix
Increase flexibility of default coordinate swap function and fix minor bugs
2 parents b39d7e1 + 9ba891b commit 5b7c6cd

File tree

10 files changed

+498
-597
lines changed

10 files changed

+498
-597
lines changed

ensemble_md/cli/run_REXEE.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def main():
104104
os.mkdir(f'{REXEE.working_dir}/sim_{i}')
105105
os.mkdir(f'{REXEE.working_dir}/sim_{i}/iteration_0')
106106
MDP = REXEE.initialize_MDP(i)
107-
MDP.write(f"{REXEE.working_dir}/sim_{i}/iteration_0/expanded.mdp", skipempty=True)
107+
MDP.write(f"{REXEE.working_dir}/sim_{i}/iteration_0/{REXEE.mdp}", skipempty=True)
108108
if REXEE.modify_coords == 'default' and (not os.path.exists('residue_connect.csv') or not os.path.exists('residue_swap_map.csv')): # noqa: E501
109109
REXEE.process_top()
110110

@@ -262,8 +262,8 @@ def main():
262262
os.mkdir(f'{REXEE.working_dir}/sim_{j}/iteration_{i}')
263263
if REXEE.fixed_weights is True:
264264
counts = None # So that this should work also for GROMACS version < 2022.5
265-
MDP = REXEE.update_MDP(f"sim_{j}/iteration_{i - 1}/expanded.mdp", j, i, states, wl_delta, weights, counts) # modify with a new template # noqa: E501
266-
MDP.write(f"{REXEE.working_dir}/sim_{j}/iteration_{i}/expanded.mdp", skipempty=True)
265+
MDP = REXEE.update_MDP(f"sim_{j}/iteration_{i - 1}/{REXEE.mdp}", j, i, states, wl_delta, weights, counts) # modify with a new template # noqa: E501
266+
MDP.write(f"{REXEE.working_dir}/sim_{j}/iteration_{i}/{REXEE.mdp}", skipempty=True)
267267
# In run_REXEE(i, swap_pattern), where the tpr files will be generated, we use the top file at the
268268
# level of the simulation (the file that will be shared by all simulations). For the gro file, we
269269
# pass swap_pattern to the function to figure it out internally.

ensemble_md/replica_exchange_EE.py

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,7 @@ def default_coords_fn(self, molA_file_name, molB_file_name):
15441544
# Load the coordinate swapping map
15451545
connection_map = pd.read_csv('residue_connect.csv')
15461546
swap_map = pd.read_csv('residue_swap_map.csv')
1547+
atom_mapping = pd.read_csv('atom_name_mapping.csv')
15471548

15481549
# Step 1: Read the GRO input coordinate files and open temporary Output files
15491550
molA_file = open(molA_file_name, 'r').readlines() # open input file
@@ -1557,7 +1558,7 @@ def default_coords_fn(self, molA_file_name, molB_file_name):
15571558
residue_options = swap_map['Swap A'].to_list() + swap_map['Swap B'].to_list()
15581559
nameA = coordinate_swap.identify_res(molA.topology, residue_options)
15591560
nameB = coordinate_swap.identify_res(molB.topology, residue_options)
1560-
df_atom_swap = coordinate_swap.find_common(molA_file, molB_file, nameA, nameB)
1561+
df_atom_swap = coordinate_swap.extract_missing(nameA, nameB, swap_map)
15611562

15621563
# Step 3: Fix break if present for solvated systems only
15631564
if len(molA.topology.select('water')) != 0:
@@ -1567,30 +1568,46 @@ def default_coords_fn(self, molA_file_name, molB_file_name):
15671568
molB = coordinate_swap.fix_break(molB, nameB, B_dimensions, connection_map[connection_map['Resname'] == nameB]) # noqa: E501
15681569

15691570
# Step 4: Determine coordinates of atoms which need to be reconstructed as we swap coordinates between molecules # noqa: E501
1570-
miss_B = df_atom_swap[(df_atom_swap['Swap'] == 'B2A') & (df_atom_swap['Direction'] == 'miss')]['Name'].to_list() # noqa: E501
1571-
miss_A = df_atom_swap[(df_atom_swap['Swap'] == 'A2B') & (df_atom_swap['Direction'] == 'miss')]['Name'].to_list() # noqa: E501
1572-
if len(miss_B) != 0:
1573-
df_atom_swap = coordinate_swap.get_miss_coord(molB, molA, nameB, nameA, df_atom_swap, 'B2A', swap_map[(swap_map['Swap A'] == nameB) & (swap_map['Swap B'] == nameA)]) # noqa: E501
1574-
if len(miss_A) != 0:
1575-
df_atom_swap = coordinate_swap.get_miss_coord(molA, molB, nameA, nameB, df_atom_swap, 'A2B', swap_map[(swap_map['Swap A'] == nameA) & (swap_map['Swap B'] == nameB)]) # noqa: E501
1571+
df_atom_swap = coordinate_swap.get_miss_coord(molB, molA, nameB, nameA, df_atom_swap, 'A2B', swap_map[(swap_map['Swap A'] == nameB) & (swap_map['Swap B'] == nameA)]) # noqa: E501
1572+
df_atom_swap = coordinate_swap.get_miss_coord(molA, molB, nameA, nameB, df_atom_swap, 'B2A', swap_map[(swap_map['Swap A'] == nameA) & (swap_map['Swap B'] == nameB)]) # noqa: E501
15761573

15771574
# Step 5: Parse Current file to ensure atoms are added in the correct order
15781575
atom_order_A = gmx_parser.deter_atom_order(molA_file, nameA)
15791576
atom_order_B = gmx_parser.deter_atom_order(molB_file, nameB)
15801577

15811578
# Step 6: Write the new file
15821579
# Reprint preamble text
1583-
line_start = coordinate_swap.print_preamble(molA_file, molB_new, len(miss_B), len(miss_A))
1580+
line_start = coordinate_swap.print_preamble(molA_file, molB_new, len(df_atom_swap[df_atom_swap['Swap'] == 'A2B']), len(df_atom_swap[df_atom_swap['Swap'] == 'B2A'])) # noqa: E501
1581+
1582+
# Print up until we reach the residue to modify
1583+
line_restart, atom_num_restart = coordinate_swap.write_unmodified(line_start, molA_file, molB_new, nameA, 1, line_start, copy.deepcopy(molA.xyz[0])) # noqa: E501
15841584

15851585
# Print new coordinates to file for molB
1586-
coordinate_swap.write_new_file(df_atom_swap, 'A2B', 'B2A', line_start, molA_file, molB_new, nameA, nameB, copy.deepcopy(molA.xyz[0]), miss_A, atom_order_B) # noqa: E501
1586+
line_restart, atom_num_restart = coordinate_swap.write_modified(df_atom_swap, 'A2B', line_start, molA_file, molB_new, atom_num_restart, nameA, nameB, copy.deepcopy(molA.xyz[0]), atom_mapping, atom_order_B, atom_order_A) # noqa: E501
1587+
1588+
if line_restart is not None:
1589+
# Print rest of file after modified residue
1590+
coordinate_swap.write_unmodified(line_restart, molA_file, molB_new, nameA, atom_num_restart, line_start, copy.deepcopy(molA.xyz[0])) # noqa: E501
1591+
1592+
# Print box size
1593+
molB_new.write(molA_file[-1])
15871594

15881595
# Print new coordinates to file
15891596
# Reprint preamble text
1590-
line_start = coordinate_swap.print_preamble(molB_file, molA_new, len(miss_A), len(miss_B))
1597+
line_start = coordinate_swap.print_preamble(molB_file, molA_new, len(df_atom_swap[df_atom_swap['Swap'] == 'B2A']), len(df_atom_swap[df_atom_swap['Swap'] == 'A2B'])) # noqa: E501
1598+
1599+
# Print up until we reach the residue to modify
1600+
line_restart, atom_num_restart = coordinate_swap.write_unmodified(line_start, molB_file, molA_new, nameB, 1, line_start, copy.deepcopy(molB.xyz[0])) # noqa: E501
1601+
1602+
# Print new coordinates to file for molA
1603+
line_restart, atom_num_restart = coordinate_swap.write_modified(df_atom_swap, 'B2A', line_start, molB_file, molA_new, atom_num_restart, nameB, nameA, copy.deepcopy(molB.xyz[0]), atom_mapping, atom_order_A, atom_order_B) # noqa: E501
15911604

1592-
# Print new coordinates for molA
1593-
coordinate_swap.write_new_file(df_atom_swap, 'B2A', 'A2B', line_start, molB_file, molA_new, nameB, nameA, copy.deepcopy(molB.xyz[0]), miss_B, atom_order_A) # noqa: E501
1605+
if line_restart is not None:
1606+
# Print rest of file after modified residue
1607+
coordinate_swap.write_unmodified(line_restart, molB_file, molA_new, nameB, atom_num_restart, line_start, copy.deepcopy(molB.xyz[0])) # noqa: E501
1608+
1609+
# Print box size
1610+
molA_new.write(molB_file[-1])
15941611

15951612
# Rename temp files
15961613
os.rename('A_hybrid_swap.gro', molB_dir + '/confout.gro')
@@ -1601,6 +1618,12 @@ def process_top(self):
16011618
Processes the input topologies in order to determine the atoms for alignment in the default GRO swapping
16021619
function. Output as csv files to prevent needing to re-run this step.
16031620
"""
1621+
if not os.path.exists('atom_name_mapping.csv'):
1622+
coordinate_swap.create_atom_map(self.gro, self.resname_list, self.swap_rep_pattern)
1623+
atom_name_mapping = pd.read_csv('atom_name_mapping.csv')
1624+
else:
1625+
atom_name_mapping = pd.read_csv('atom_name_mapping.csv')
1626+
16041627
if not os.path.exists('residue_connect.csv'):
16051628
df_top = pd.DataFrame()
16061629
for f, file_name in enumerate(self.top):
@@ -1640,17 +1663,23 @@ def process_top(self):
16401663
# Determine atoms not present in both molecules
16411664
X, Y = [int(swap[0][0]), int(swap[1][0])]
16421665
lam = {X: int(swap[0][1]), Y: int(swap[1][1])}
1666+
swap_name_match = atom_name_mapping[(atom_name_mapping['resname A'].isin([self.resname_list[X], self.resname_list[Y]])) & (atom_name_mapping['resname B'].isin([self.resname_list[X], self.resname_list[Y]]))] # noqa: E501
16431667
for A, B in zip([X, Y], [Y, X]):
1668+
# Swapping coordinates from B to A
16441669
input_A = gmx_parser.read_top(self.top[A], self.resname_list[A])
16451670
start_line, A_name, A_num, state = coordinate_swap.get_names(input_A, self.resname_list[A])
16461671
input_B = gmx_parser.read_top(self.top[B], self.resname_list[B])
16471672
start_line, B_name, B_num, state = coordinate_swap.get_names(input_B, self.resname_list[B])
16481673

1649-
A_only = [x for x in A_name if x not in B_name]
1650-
B_only = [x for x in B_name if x not in A_name]
1674+
# Determine shared atom names
1675+
if len(swap_name_match[swap_name_match['resname A'] == self.resname_list[A]]) != 0:
1676+
common_atoms_A = list(swap_name_match['atom name A'].values)
1677+
else:
1678+
common_atoms_A = list(swap_name_match['atom name B'].values)
1679+
A_only = [x for x in A_name if x not in common_atoms_A]
16511680

16521681
# Seperate real to dummy switches
1653-
df = coordinate_swap.determine_connection(A_only, B_only, self.resname_list[A], self.resname_list[B], df_top, lam[A]) # noqa: E501
1682+
df = coordinate_swap.determine_connection(A_only, swap_name_match, self.resname_list[A], self.resname_list[B], df_top, lam[A]) # noqa: E501
16541683

16551684
df_map = pd.concat([df_map, df])
16561685

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
,resname A,resname B,atomid A,atom name A,atomid B,atom name B
2+
0,A2B,B2C,1,S1,1,S1
3+
1,A2B,B2C,1,S1,1,S1
4+
2,A2B,B2C,2,C2,2,C2
5+
3,A2B,B2C,2,C2,2,C2
6+
4,A2B,B2C,3,N3,3,N3
7+
5,A2B,B2C,3,N3,3,N3
8+
6,A2B,B2C,4,C4,4,C4
9+
7,A2B,B2C,4,C4,4,C4
10+
8,A2B,B2C,5,C5,5,C5
11+
9,A2B,B2C,5,C5,5,C5
12+
10,A2B,B2C,6,C6,6,C6
13+
11,A2B,B2C,6,C6,6,C6
14+
12,A2B,B2C,7,H1,8,H1
15+
13,A2B,B2C,7,H1,8,H1
16+
14,A2B,B2C,8,H2,9,H2
17+
15,A2B,B2C,8,H2,9,H2
18+
16,A2B,B2C,9,H3,10,H3
19+
17,A2B,B2C,9,H3,10,H3
20+
18,A2B,B2C,10,H4,11,H4
21+
19,A2B,B2C,10,H4,11,H4
22+
20,A2B,B2C,12,DC7,7,C7
23+
21,A2B,B2C,13,HV5,12,H5
24+
22,A2B,B2C,14,HV6,13,H6
25+
23,A2B,B2C,15,HV7,14,H7
26+
0,B2C,C2D,1,S1,1,S1
27+
1,B2C,C2D,1,S1,1,S1
28+
2,B2C,C2D,2,C2,2,C2
29+
3,B2C,C2D,2,C2,2,C2
30+
4,B2C,C2D,3,N3,3,N3
31+
5,B2C,C2D,3,N3,3,N3
32+
6,B2C,C2D,4,C4,4,C4
33+
7,B2C,C2D,4,C4,4,C4
34+
8,B2C,C2D,5,C5,5,C5
35+
9,B2C,C2D,5,C5,5,C5
36+
10,B2C,C2D,6,C6,6,C6
37+
11,B2C,C2D,6,C6,6,C6
38+
12,B2C,C2D,7,C7,7,C7
39+
13,B2C,C2D,7,C7,7,C7
40+
14,B2C,C2D,8,H1,9,H1
41+
15,B2C,C2D,8,H1,9,H1
42+
16,B2C,C2D,9,H2,10,H2
43+
17,B2C,C2D,9,H2,10,H2
44+
18,B2C,C2D,10,H3,11,H3
45+
19,B2C,C2D,10,H3,11,H3
46+
20,B2C,C2D,11,H4,12,H4
47+
21,B2C,C2D,11,H4,12,H4
48+
22,B2C,C2D,12,H5,19,HV5
49+
23,B2C,C2D,13,H6,13,H6
50+
24,B2C,C2D,13,H6,13,H6
51+
25,B2C,C2D,14,H7,14,H7
52+
26,B2C,C2D,14,H7,14,H7
53+
27,B2C,C2D,15,DC8,8,C8
54+
28,B2C,C2D,16,HV8,15,H8
55+
29,B2C,C2D,17,HV9,16,H9
56+
30,B2C,C2D,18,HV10,17,H10
57+
0,C2D,D2E,1,S1,1,S1
58+
1,C2D,D2E,1,S1,1,S1
59+
2,C2D,D2E,2,C2,2,C2
60+
3,C2D,D2E,2,C2,2,C2
61+
4,C2D,D2E,3,N3,3,N3
62+
5,C2D,D2E,3,N3,3,N3
63+
6,C2D,D2E,4,C4,4,C4
64+
7,C2D,D2E,4,C4,4,C4
65+
8,C2D,D2E,5,C5,5,C5
66+
9,C2D,D2E,5,C5,5,C5
67+
10,C2D,D2E,6,C6,6,C6
68+
11,C2D,D2E,6,C6,6,C6
69+
12,C2D,D2E,7,C7,7,C7
70+
13,C2D,D2E,7,C7,7,C7
71+
14,C2D,D2E,8,C8,18,DC8
72+
15,C2D,D2E,9,H1,9,H1
73+
16,C2D,D2E,9,H1,9,H1
74+
17,C2D,D2E,10,H2,10,H2
75+
18,C2D,D2E,10,H2,10,H2
76+
19,C2D,D2E,11,H3,11,H3
77+
20,C2D,D2E,11,H3,11,H3
78+
21,C2D,D2E,13,H6,13,H6
79+
22,C2D,D2E,13,H6,13,H6
80+
23,C2D,D2E,14,H7,14,H7
81+
24,C2D,D2E,14,H7,14,H7
82+
25,C2D,D2E,15,H8,19,HV8
83+
26,C2D,D2E,16,H9,20,HV9
84+
27,C2D,D2E,17,H10,21,HV10
85+
28,C2D,D2E,18,DC9,8,C9
86+
29,C2D,D2E,19,HV5,12,H5
87+
30,C2D,D2E,20,HV11,15,H11
88+
31,C2D,D2E,21,HV12,16,H12
89+
32,C2D,D2E,22,HV13,17,H13
90+
0,D2E,E2F,1,S1,1,S1
91+
1,D2E,E2F,1,S1,1,S1
92+
2,D2E,E2F,2,C2,2,C2
93+
3,D2E,E2F,2,C2,2,C2
94+
4,D2E,E2F,3,N3,3,N3
95+
5,D2E,E2F,3,N3,3,N3
96+
6,D2E,E2F,4,C4,4,C4
97+
7,D2E,E2F,4,C4,4,C4
98+
8,D2E,E2F,5,C5,5,C5
99+
9,D2E,E2F,5,C5,5,C5
100+
10,D2E,E2F,6,C6,6,C6
101+
11,D2E,E2F,6,C6,6,C6
102+
12,D2E,E2F,7,C7,7,C7
103+
13,D2E,E2F,7,C7,7,C7
104+
14,D2E,E2F,8,C9,9,C9
105+
15,D2E,E2F,8,C9,9,C9
106+
16,D2E,E2F,9,H1,10,H1
107+
17,D2E,E2F,9,H1,10,H1
108+
18,D2E,E2F,10,H2,11,H2
109+
19,D2E,E2F,10,H2,11,H2
110+
20,D2E,E2F,11,H3,12,H3
111+
21,D2E,E2F,11,H3,12,H3
112+
22,D2E,E2F,13,H6,13,H6
113+
23,D2E,E2F,13,H6,13,H6
114+
24,D2E,E2F,14,H7,14,H7
115+
25,D2E,E2F,14,H7,14,H7
116+
26,D2E,E2F,15,H11,18,H11
117+
27,D2E,E2F,15,H11,18,H11
118+
28,D2E,E2F,16,H12,19,H12
119+
29,D2E,E2F,16,H12,19,H12
120+
30,D2E,E2F,17,H13,20,H13
121+
31,D2E,E2F,17,H13,20,H13
122+
32,D2E,E2F,18,DC8,8,C8
123+
33,D2E,E2F,19,HV8,15,H8
124+
34,D2E,E2F,20,HV9,16,H9
125+
35,D2E,E2F,21,HV10,17,H10
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
,resname A,resname B,atomid A,atom name A,atomid B,atom name B
2+
0,I2J,J2K,1,O,1,O
3+
1,I2J,J2K,2,C1,2,C1
4+
2,I2J,J2K,3,C2,3,C2
5+
3,I2J,J2K,4,C3,4,C3
6+
4,I2J,J2K,5,C4,5,C4
7+
5,I2J,J2K,6,CV5,6,C5
8+
6,I2J,J2K,7,CV6,7,C6
9+
7,I2J,J2K,8,H1,10,H1
10+
8,I2J,J2K,9,H2,11,H2
11+
9,I2J,J2K,10,H3,12,H3
12+
10,I2J,J2K,11,H4,13,H4
13+
11,I2J,J2K,12,H5,14,H5
14+
12,I2J,J2K,13,H6,15,H6
15+
13,I2J,J2K,14,H7,16,H7
16+
14,I2J,J2K,16,HV9,17,H9
17+
15,I2J,J2K,17,HV10,18,H10
18+
16,I2J,J2K,18,HV11,19,H11
19+
17,I2J,J2K,19,HV12,20,H12
20+
18,I2J,J2K,20,HV13,21,H13
Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
,index,Name,Atom Name Number,Element,Direction,Swap,File line,Final Type,X Coordinates,Y Coordinates,Z Coordinates
2-
0,0,H5,5,H,miss,A2B,13,real,0.09260503947734833,1.6340194940567017,0.3355029225349426
3-
1,1,DC8,8,C,D2R,A2B,19,real,,,
4-
2,2,HV8,8,H,D2R,A2B,20,real,,,
5-
3,3,HV9,9,H,D2R,A2B,21,real,,,
6-
4,4,HV10,10,H,D2R,A2B,22,real,,,
7-
5,0,C8,8,C,R2D,B2A,9,dummy,,,
8-
6,1,H8,8,H,R2D,B2A,16,dummy,,,
9-
7,2,H9,9,H,R2D,B2A,17,dummy,,,
10-
8,3,H10,10,H,R2D,B2A,18,dummy,,,
11-
9,4,DC10,10,C,miss,B2A,22,dummy,2.620028495788574,1.403925895690918,2.7885396480560303
12-
10,5,HV4,4,H,miss,B2A,23,dummy,2.3651702404022217,1.4678032398223877,2.8239073753356934
13-
11,6,HV14,14,H,miss,B2A,24,dummy,2.678273916244507,1.464888095855713,2.8585944175720215
14-
12,7,HV15,15,H,miss,B2A,25,dummy,2.6814169883728027,1.340580940246582,2.7234597206115723
15-
13,8,HV16,16,H,miss,B2A,26,dummy,2.5583090782165527,1.3370134830474854,2.8496134281158447
1+
,Name,Swap,X Coordinates,Y Coordinates,Z Coordinates
2+
0,DC10,A2B,2.620028018951416,1.4039266109466553,2.7885406017303467
3+
1,HV14,A2B,2.6782684326171875,1.4648889303207397,2.8585996627807617
4+
2,HV15,A2B,2.6814215183258057,1.3405863046646118,2.723461389541626
5+
3,HV16,A2B,2.5583088397979736,1.3370097875595093,2.849609851837158
6+
4,HV4,A2B,2.3651702404022217,1.4678034782409668,2.8239071369171143
7+
5,H5,B2A,0.09260530769824982,1.6340194940567017,0.33550316095352173
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
,Name,Swap
2+
0,DC10,A2B
3+
1,HV14,A2B
4+
2,HV15,A2B
5+
3,HV16,A2B
6+
4,HV4,A2B
7+
5,H5,B2A

ensemble_md/tests/data/coord_swap/find_common.csv

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)