3# program that reads in a water box and solute xyz (or pdb), merges
4# the two systems, and deletes overlapping molecules
6__author__ = "Chris Fennell and Dan Gezelter"
7__copyright__ = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
14d2tolerance = 7.5625 # distance to start cutting
15fileName = 'solvatedSystem.omd'
23# Argument parser setup
24parser = argparse.ArgumentParser(description='Carves a solute void in an OpenMD water box',
25 formatter_class=argparse.RawDescriptionHelpFormatter,
29 solvator -i myWater.omd -p mySolute.pdb -o mySystem.omd
31parser.add_argument('-f', '--flexible=', type=bool, dest='f',
32 action=argparse.BooleanOptionalAction, default=False,
33 help='include a flexible solute model description in the output file rather than the rigid body solute model description')
34parser.add_argument('-d', action='store', dest='d',
35 type=float, default=2.75, required=False,
36 help='Overlap removal distance (in angstroms)')
37parser.add_argument('-i', type=str, required=True, action='store', dest='i',
38 help='Solvent input file (OpenMD .omd file)')
39parser.add_argument('-n', type=str, help='Name for the solute',
40 required=False, dest='n', action='store',
42parser.add_argument('-o', '--output=', action='store', dest='o',
43 required=False, default='solvatedSystem.omd',
44 help='Carved solvent output file (OpenMD .omd format)')
45parser.add_argument('-p', type=str, help='Solute input file (pdb)',
46 action='store', dest='p')
47parser.add_argument('-x', type=str, help='Solute input file (xyz)',
48 action='store', dest='x')
49args = parser.parse_args()
51# Set variables from arguments
55 sys.exit("Error: No solvent box specified\nPlease select a solvent box using the -i flag")
57soluteFileName = args.p if args.p else args.x
58fileName = args.o if args.o else fileName
59soluteName = args.n if args.n else soluteName
61if not (args.p or args.x):
62 sys.exit("Error: No solute file specified\nPlease select a solute file with the -p or -x flags (pdb or xyz respectively)")
66 d2tolerance = dval * dval
72 with open(soluteFileName, 'r') as solute_file:
73 solute_data = solute_file.readlines()
74except FileNotFoundError:
75 sys.exit(f"Error: Can't open file {soluteFileName}")
77solute_names, solute_x, solute_y, solute_z = [], [], [], []
81 for line in solute_data:
86 solute_names.append(parts[0])
87 solute_x.append(float(parts[1]))
88 solute_y.append(float(parts[2]))
89 solute_z.append(float(parts[3]))
92 for line in solute_data:
94 if parts[0] == 'ATOM' or parts[0] == 'HETATM':
95 solute_names.append(parts[2])
96 solute_x.append(float(parts[5]))
97 solute_y.append(float(parts[6]))
98 solute_z.append(float(parts[7]))
100# Remap solute to the center of the box
101xSol = sum(solute_x) / len(solute_x)
102ySol = sum(solute_y) / len(solute_y)
103zSol = sum(solute_z) / len(solute_z)
105solute_x = [x - xSol for x in solute_x]
106solute_y = [y - ySol for y in solute_y]
107solute_z = [z - zSol for z in solute_z]
109soluteCount = len(solute_x) if args.f else 1
110solventCount = soluteCount
112# Process solvent file and write output
114 with open(solventName, 'r') as solvent_file, open(fileName, 'w') as out_file:
115 startSnap = startFrame = startStunts = startMeta = 0
116 frameData, metaLines, goodSolventMolecules = [], [], []
118 for line in solvent_file:
119 if "</Snapshot" in line:
121 if "</FrameData" in line:
123 if "</StuntDoubles" in line:
125 if "</MetaData" in line:
127 if "</OpenMD" in line:
131 metaLines.append(line)
135 frameData.append(line)
138 hxx, hyy, hzz = float(parts[2][:-1]), float(parts[8][:-1]), float(parts[14])
141 x_val = float(parts[2]) - (hxx * round(float(parts[2]) / hxx))
142 y_val = float(parts[3]) - (hyy * round(float(parts[3]) / hyy))
143 z_val = float(parts[4]) - (hzz * round(float(parts[4]) / hzz))
146 for i in range(len(solute_x)):
147 diff_x = x_val - solute_x[i]
148 diff_y = y_val - solute_y[i]
149 diff_z = z_val - solute_z[i]
150 dist2 = diff_x * diff_x + diff_y * diff_y + diff_z * diff_z
151 if dist2 < d2tolerance:
156 saveLine = f"{solventCount}\t{parts[1]}\t{parts[2]}"
157 saveLine += ''.join([f" {p}" for p in parts[3:]])
158 goodSolventMolecules.append(saveLine)
161 if "<Snapshot" in line:
163 if "<FrameData" in line:
165 if "<StuntDoubles" in line:
167 if "<MetaData" in line:
170 nSolvent = len(goodSolventMolecules)
173 out_file.write("<OpenMD version=2>\n")
174 out_file.write(" <MetaData>\n")
175 out_file.write("\nmolecule{{\n name = \"{}\";\n\n".format(soluteName))
178 for i in range(len(solute_x)):
179 out_file.write(f" atom[{i}]{{\n type = \"{solute_names[i]}\";\n }}\n")
180 out_file.write("}\n")
182 for i in range(len(solute_x)):
183 out_file.write(f" atom[{i}]{{\n type = \"{solute_names[i]}\";\n")
184 out_file.write(f" position({solute_x[i]}, {solute_y[i]}, {solute_z[i]});\n }}\n")
185 out_file.write("\n rigidBody[0]{\n members(")
186 out_file.write(", ".join(str(i) for i in range(len(solute_x))))
187 out_file.write(");\n }\n}\n")
189 out_file.write(f"\ncomponent{{\n type = \"{soluteName}\";\n nMol = 1;\n}}\n")
190 for line in metaLines:
192 out_file.write(f" nMol = {nSolvent};\n")
196 out_file.write(" </MetaData>\n")
197 out_file.write(" <Snapshot>\n")
198 out_file.write(" <FrameData>\n")
200 for line in frameData:
203 out_file.write(" </FrameData>\n")
204 out_file.write(" <StuntDoubles>\n")
207 for i in range(len(solute_x)):
208 out_file.write(f"{i}\tp\t{solute_x[i]} {solute_y[i]} {solute_z[i]}\n")
210 out_file.write("0\tpq\t0.0 0.0 0.0 1.0 0.0 0.0 0.0\n")
212 for molecule in goodSolventMolecules:
213 out_file.write(f"{molecule}\n")
215 out_file.write(" </StuntDoubles>\n")
216 out_file.write(" </Snapshot>\n")
217 out_file.write("</OpenMD>\n")
219 print(f"The solvated system \"{fileName}\" was generated.")
221except FileNotFoundError:
222 sys.exit(f"Error: Can't open file {solventName}")