1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.algorithms.commands.test;
39
40 import ffx.algorithms.cli.AlgorithmsCommand;
41 import ffx.algorithms.cli.MinimizeOptions;
42 import ffx.algorithms.optimize.Minimize;
43 import ffx.algorithms.optimize.Minimize.MinimizationEngine;
44 import ffx.potential.ForceFieldEnergy;
45 import ffx.potential.MolecularAssembly;
46 import ffx.potential.bonded.Atom;
47 import ffx.potential.bonded.Polymer;
48 import ffx.potential.bonded.Residue;
49 import ffx.potential.bonded.ResidueState;
50 import ffx.potential.bonded.Rotamer;
51 import ffx.potential.bonded.RotamerLibrary;
52 import ffx.potential.bonded.RotamerLibrary.ProteinLibrary;
53 import ffx.utilities.FFXBinding;
54 import org.apache.commons.io.FilenameUtils;
55 import picocli.CommandLine.Command;
56 import picocli.CommandLine.Mixin;
57 import picocli.CommandLine.Option;
58 import picocli.CommandLine.Parameters;
59
60 import java.io.BufferedWriter;
61 import java.io.File;
62 import java.io.FileWriter;
63 import java.io.IOException;
64 import java.util.ArrayList;
65 import java.util.List;
66 import java.util.stream.Collectors;
67
68
69
70
71
72
73
74
75 @Command(description = " Creates a set of conformation dependent rotamers.", name = "test.CreateRotamers")
76 public class CreateRotamers extends AlgorithmsCommand {
77
78 @Mixin
79 private MinimizeOptions minimizeOptions;
80
81
82
83
84
85
86
87 @Option(names = {"-L", "--library"}, paramLabel = "2",
88 description = "Ponder and Richards (1) or Richardson (2) rotamer library.")
89 private String library = "2";
90
91
92
93
94
95
96 @Option(names = {"-d", "--rmsd"}, paramLabel = "0.1",
97 description = "RMSD cut off for rotamer exclusion: only rotamers with an RMSD greater than this cut off value to all previously saved rotamers will be kept")
98 private double rmsdCutoff = 0.1;
99
100
101
102
103 @Parameters(arity = "1..*", paramLabel = "files", description = "Atomic coordinate file in PDB or XYZ format.")
104 private List<String> filenames = null;
105
106 public ForceFieldEnergy forceFieldEnergy = null;
107
108
109
110
111 public CreateRotamers() {
112 super();
113 }
114
115
116
117
118
119 public CreateRotamers(FFXBinding binding) {
120 super(binding);
121 }
122
123
124
125
126
127 public CreateRotamers(String[] args) {
128 super(args);
129 }
130
131
132
133
134 @Override
135 public CreateRotamers run() {
136
137 if (!init()) {
138 return this;
139 }
140
141 if (filenames != null && !filenames.isEmpty()) {
142 MolecularAssembly[] assemblies = new MolecularAssembly[]{algorithmFunctions.open(filenames.get(0))};
143 activeAssembly = assemblies[0];
144 } else if (activeAssembly == null) {
145 logger.info(helpString());
146 return this;
147 }
148
149 String filename = activeAssembly.getFile().getAbsolutePath();
150 logger.info(" Running CreateRotamers on " + filename);
151
152 Atom[] atoms = activeAssembly.getAtomArray();
153 int nAtoms = atoms.length;
154
155
156 for (int i = 0; i < nAtoms; i++) {
157 atoms[i].setActive(false);
158 }
159
160
161 boolean useOriginalRotamers = true;
162
163
164 RotamerLibrary rotamerLibrary = new RotamerLibrary(ProteinLibrary.getProteinLibrary(library),
165 useOriginalRotamers);
166
167
168 Polymer[] polymers = activeAssembly.getChains();
169 RotamerLibrary.initializeDefaultAtomicCoordinates(polymers);
170
171
172 List<Residue> residues = activeAssembly.getResidueList().stream()
173 .filter(r -> {
174 Rotamer[] rots = r.setRotamers(rotamerLibrary);
175 return rots != null && rots.length > 1;
176 })
177 .collect(Collectors.toList());
178
179 logger.info(String.format(" Number of residues: %d\n", residues.size()));
180
181
182 for (Residue residue : residues) {
183 for (Atom atom : residue.getVariableAtoms()) {
184 atom.setUse(false);
185 }
186 }
187
188
189 String rotFileName = String.format("%s.rot", FilenameUtils.removeExtension(filename));
190
191 try (BufferedWriter bw = new BufferedWriter(new FileWriter(new File(rotFileName)))) {
192
193
194 bw.write("ALGORITHM:GLOBAL:1");
195 bw.newLine();
196
197
198 for (Residue residue : residues) {
199
200 StringBuilder resLine = new StringBuilder(" RES:");
201 resLine.append(residue.getChainID()).append(":");
202 resLine.append(residue.getSegID()).append(":");
203 resLine.append(residue.getName()).append(":");
204 resLine.append(residue.getResidueNumber()).append("\n");
205 bw.write(resLine.toString());
206
207
208 Rotamer[] rotamers = residue.getRotamers();
209
210 assert rotamers != null && rotamers.length > 1;
211
212
213
214
215 List<Atom> sideChainAtoms = residue.getVariableAtoms();
216 for (Atom atom : sideChainAtoms) {
217 atom.setActive(true);
218 atom.setUse(true);
219 }
220
221
222 ArrayList<ResidueState> keptRotamers = new ArrayList<>();
223 int keptRotamersCount = 0;
224
225
226 for (int i = 0; i < rotamers.length; i++) {
227 Rotamer rotamer = rotamers[i];
228
229
230 RotamerLibrary.applyRotamer(residue, rotamer);
231
232 if (i > 0 || !useOriginalRotamers) {
233
234 MinimizationEngine engine =
235 Minimize.defaultEngine(activeAssembly, activeAssembly.getPotentialEnergy());
236 Minimize minimize = Minimize.minimizeFactory(activeAssembly,
237 activeAssembly.getPotentialEnergy(), algorithmListener, engine);
238
239 minimize.minimize(minimizeOptions.getNBFGS(), minimizeOptions.getEps(), minimizeOptions.getIterations());
240 } else {
241 logger.info(" Skipping minimization of original-coordinates rotamer.");
242 }
243
244
245
246
247
248 ResidueState newResState = new ResidueState(residue);
249
250 if (i == 0) {
251
252 keptRotamers.add(newResState);
253
254
255 bw.write(String.format(" ROT:%d\n", keptRotamersCount));
256 for (Atom atom : sideChainAtoms) {
257 double x = atom.getX();
258 double y = atom.getY();
259 double z = atom.getZ();
260 logger.info(String.format(" %s %16.8f %16.8f %16.8f", atom.toString(), x, y, z));
261 StringBuilder atomLine = new StringBuilder(" ATOM:");
262 atomLine.append(atom.getName()).append(":");
263 atomLine.append(x).append(":");
264 atomLine.append(y).append(":");
265 atomLine.append(z).append("\n");
266 bw.write(atomLine.toString());
267 }
268 bw.write(" ENDROT\n");
269 keptRotamersCount++;
270 } else {
271
272
273 logger.info("Number of rotamers kept for this residue: " + keptRotamers.size());
274
275
276 boolean withinRange = false;
277
278
279
280 for (int k = 0; k < keptRotamers.size(); k++) {
281 double RMSD = newResState.compareTo(keptRotamers.get(k));
282 logger.info("RMSD: " + RMSD + "\n");
283 if (RMSD <= rmsdCutoff) {
284 withinRange = true;
285 }
286 }
287
288
289
290
291 if (withinRange) {
292
293
294 logger.info("Rotamer not kept");
295 } else {
296
297 bw.write(String.format(" ROT:%d\n", keptRotamersCount));
298 for (Atom atom : sideChainAtoms) {
299 double x = atom.getX();
300 double y = atom.getY();
301 double z = atom.getZ();
302 logger.info(String.format(" %s %16.8f %16.8f %16.8f", atom.toString(), x, y, z));
303 StringBuilder atomLine = new StringBuilder(" ATOM:");
304 atomLine.append(atom.getName()).append(":");
305 atomLine.append(x).append(":");
306 atomLine.append(y).append(":");
307 atomLine.append(z).append("\n");
308 bw.write(atomLine.toString());
309 }
310 bw.write(" ENDROT\n");
311
312
313 keptRotamers.add(newResState);
314 keptRotamersCount++;
315 }
316
317 }
318 }
319
320
321 RotamerLibrary.applyRotamer(residue, rotamers[0]);
322
323
324 for (Atom atom : sideChainAtoms) {
325 atom.setActive(false);
326 atom.setUse(false);
327 }
328 }
329
330 } catch (IOException e) {
331 logger.severe("Error writing rotamer file: " + e.getMessage());
332 throw new RuntimeException(e);
333 }
334
335 return this;
336 }
337 }