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;
39
40 import edu.rit.pj.Comm;
41 import ffx.algorithms.cli.AlgorithmsCommand;
42 import ffx.algorithms.cli.ManyBodyOptions;
43 import ffx.algorithms.optimize.RotamerOptimization;
44 import ffx.algorithms.optimize.TitrationManyBody;
45 import ffx.numerics.Potential;
46 import ffx.potential.ForceFieldEnergy;
47 import ffx.potential.MolecularAssembly;
48 import ffx.potential.bonded.Atom;
49 import ffx.potential.bonded.LambdaInterface;
50 import ffx.potential.bonded.Residue;
51 import ffx.potential.bonded.RotamerLibrary;
52 import ffx.potential.cli.AlchemicalOptions;
53 import ffx.potential.parsers.PDBFilter;
54 import ffx.utilities.FFXBinding;
55 import org.apache.commons.configuration2.CompositeConfiguration;
56 import picocli.CommandLine.Command;
57 import picocli.CommandLine.Mixin;
58 import picocli.CommandLine.Parameters;
59
60 import java.io.File;
61 import java.util.ArrayList;
62 import java.util.Collections;
63 import java.util.HashSet;
64 import java.util.List;
65 import java.util.Set;
66
67 import static ffx.potential.bonded.NamingUtils.renameAtomsToPDBStandard;
68 import static java.lang.String.format;
69
70
71
72
73
74
75
76
77 @Command(description = " Run ManyBody algorithm on a system.", name = "ManyBody")
78 public class ManyBody extends AlgorithmsCommand {
79
80 @Mixin
81 private ManyBodyOptions manyBodyOptions;
82
83 @Mixin
84 private AlchemicalOptions alchemicalOptions;
85
86
87
88
89 @Parameters(arity = "1", paramLabel = "file",
90 description = "XYZ or PDB input file.")
91 private String filename;
92
93 private ForceFieldEnergy potentialEnergy;
94 private TitrationManyBody titrationManyBody;
95
96
97
98
99 public ManyBody() {
100 super();
101 }
102
103
104
105
106
107 public ManyBody(FFXBinding binding) {
108 super(binding);
109 }
110
111
112
113
114
115 public ManyBody(String[] args) {
116 super(args);
117 }
118
119
120
121
122 @Override
123 public ManyBody run() {
124
125 if (!init()) {
126 return this;
127 }
128
129
130
131
132
133 double titrationPH = manyBodyOptions.getTitrationPH();
134
135 if (manyBodyOptions.getTitration()) {
136 System.setProperty("manybody-titration", "true");
137 }
138
139
140 boolean lambdaTerm = alchemicalOptions.hasSoftcore();
141 if (lambdaTerm) {
142
143 System.setProperty("lambdaterm", "true");
144
145 System.setProperty("elec-lambdaterm", "false");
146
147 System.setProperty("intramolecular-softcore", "true");
148 }
149
150
151 activeAssembly = getActiveAssembly(filename);
152
153
154 if (activeAssembly == null) {
155 logger.info(helpString());
156 return this;
157 }
158
159 String listResidues = "";
160 if (manyBodyOptions.getOnlyTitration() ||
161 manyBodyOptions.getInterestedResidue() != -1 && manyBodyOptions.getInclusionCutoff() != -1) {
162 listResidues = manyBodyOptions.selectInclusionResidues(activeAssembly.getResidueList(),
163 manyBodyOptions.getInterestedResidue(), manyBodyOptions.getOnlyTitration(), manyBodyOptions.getInclusionCutoff());
164 manyBodyOptions.setListResidues(listResidues);
165 }
166
167 CompositeConfiguration properties = activeAssembly.getProperties();
168
169
170 if (properties.getBoolean("standardizeAtomNames", false)) {
171 renameAtomsToPDBStandard(activeAssembly);
172 }
173
174 activeAssembly.getPotentialEnergy().setPrintOnFailure(false, false);
175 potentialEnergy = activeAssembly.getPotentialEnergy();
176
177
178 List<Residue> residues = manyBodyOptions.collectResidues(activeAssembly);
179 if (residues == null || residues.isEmpty()) {
180 logger.info(" There are no residues in the active system to optimize.");
181 return this;
182 }
183
184
185 if (manyBodyOptions.getTitration()) {
186 logger.info("\n Adding titration hydrogen to : " + filename + "\n");
187
188
189 List<Integer> resNumberList = new ArrayList<>();
190 for (Residue residue : residues) {
191 resNumberList.add(residue.getResidueNumber());
192 }
193
194
195 titrationManyBody = new TitrationManyBody(filename, activeAssembly.getForceField(),
196 resNumberList, titrationPH, manyBodyOptions);
197 activeAssembly = titrationManyBody.getProtonatedAssembly();
198 potentialEnergy = activeAssembly.getPotentialEnergy();
199 }
200
201 if (lambdaTerm) {
202 alchemicalOptions.setFirstSystemAlchemistry(activeAssembly);
203 LambdaInterface lambdaInterface = potentialEnergy;
204 double lambda = alchemicalOptions.getInitialLambda();
205 logger.info(format(" Setting ManyBody softcore lambda to: %5.3f", lambda));
206 lambdaInterface.setLambda(lambda);
207 }
208
209 RotamerOptimization rotamerOptimization = new RotamerOptimization(activeAssembly,
210 potentialEnergy, algorithmListener);
211 rotamerOptimization.setPHRestraint(manyBodyOptions.getPHRestraint());
212 rotamerOptimization.setpH(titrationPH);
213
214 manyBodyOptions.initRotamerOptimization(rotamerOptimization, activeAssembly);
215 List<Residue> residueList = rotamerOptimization.getResidues();
216
217 logger.info("\n Initial Potential Energy:");
218 potentialEnergy.energy(false, true);
219
220 logger.info("\n Initial Rotamer Torsion Angles:");
221 RotamerLibrary.measureRotamers(residueList, false);
222
223
224 rotamerOptimization.optimize(manyBodyOptions.getAlgorithm(residueList.size()));
225
226 boolean isTitrating = false;
227 Set<Atom> excludeAtoms = new HashSet<>();
228 int[] optimalRotamers = rotamerOptimization.getOptimumRotamers();
229 if (manyBodyOptions.getTitration()) {
230 isTitrating = titrationManyBody.excludeExcessAtoms(excludeAtoms, optimalRotamers, residueList);
231 }
232
233
234 int rank = Comm.world().rank();
235 if (rank == 0) {
236 logger.info(" Final Minimum Energy");
237 double energy = potentialEnergy.energy(false, true);
238 if (isTitrating) {
239 double phBias = rotamerOptimization.getEnergyExpansion().getTotalRotamerPhBias(residueList,
240 optimalRotamers, titrationPH, manyBodyOptions.getPHRestraint());
241 logger.info(format("\n Rotamer pH Bias %16.8f", phBias));
242 logger.info(format(" Potential with Bias%16.8f\n", phBias + energy));
243 }
244
245
246
247 properties.setProperty("standardizeAtomNames", "false");
248 File modelFile = saveDirFile(activeAssembly.getFile());
249 PDBFilter pdbFilter = new PDBFilter(modelFile, activeAssembly, activeAssembly.getForceField(),
250 properties);
251 if (manyBodyOptions.getTitration()) {
252 String remark = format("Titration pH: %6.3f", titrationPH);
253 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true, new String[]{remark})) {
254 logger.info(format(" Save failed for %s", activeAssembly));
255 }
256 } else {
257 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true)) {
258 logger.info(format(" Save failed for %s", activeAssembly));
259 }
260 }
261 }
262
263 if (manyBodyOptions.getTitration()) {
264 System.clearProperty("manybody-titration");
265 }
266
267 return this;
268 }
269
270
271
272
273 public ManyBodyOptions getManyBodyOptions() {
274 return manyBodyOptions;
275 }
276
277
278
279
280
281 public ForceFieldEnergy getPotential() {
282 return potentialEnergy;
283 }
284
285
286
287
288 @Override
289 public List<Potential> getPotentials() {
290 List<Potential> potentials;
291 if (potentialEnergy == null) {
292 potentials = Collections.emptyList();
293 } else {
294 potentials = Collections.singletonList(potentialEnergy);
295 }
296 return potentials;
297 }
298
299 }