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 MolecularAssembly protonatedAssembly = titrationManyBody.getProtonatedAssembly();
198 setActiveAssembly(protonatedAssembly);
199 potentialEnergy = protonatedAssembly.getPotentialEnergy();
200 }
201
202 if (lambdaTerm) {
203 alchemicalOptions.setFirstSystemAlchemistry(activeAssembly);
204 LambdaInterface lambdaInterface = (LambdaInterface) potentialEnergy;
205 double lambda = alchemicalOptions.getInitialLambda();
206 logger.info(format(" Setting ManyBody softcore lambda to: %5.3f", lambda));
207 lambdaInterface.setLambda(lambda);
208 }
209
210 RotamerOptimization rotamerOptimization = new RotamerOptimization(activeAssembly,
211 potentialEnergy, algorithmListener);
212 rotamerOptimization.setPHRestraint(manyBodyOptions.getPHRestraint());
213 rotamerOptimization.setpH(titrationPH);
214
215 manyBodyOptions.initRotamerOptimization(rotamerOptimization, activeAssembly);
216 List<Residue> residueList = rotamerOptimization.getResidues();
217
218 logger.info("\n Initial Potential Energy:");
219 potentialEnergy.energy(false, true);
220
221 logger.info("\n Initial Rotamer Torsion Angles:");
222 RotamerLibrary.measureRotamers(residueList, false);
223
224
225 rotamerOptimization.optimize(manyBodyOptions.getAlgorithm(residueList.size()));
226
227 boolean isTitrating = false;
228 Set<Atom> excludeAtoms = new HashSet<>();
229 int[] optimalRotamers = rotamerOptimization.getOptimumRotamers();
230 if (manyBodyOptions.getTitration()) {
231 isTitrating = titrationManyBody.excludeExcessAtoms(excludeAtoms, optimalRotamers, residueList);
232 }
233
234
235 int rank = Comm.world().rank();
236 if (rank == 0) {
237 logger.info(" Final Minimum Energy");
238 double energy = potentialEnergy.energy(false, true);
239 if (isTitrating) {
240 double phBias = rotamerOptimization.getEnergyExpansion().getTotalRotamerPhBias(residueList,
241 optimalRotamers, titrationPH, manyBodyOptions.getPHRestraint());
242 logger.info(format("\n Rotamer pH Bias %16.8f", phBias));
243 logger.info(format(" Potential with Bias%16.8f\n", phBias + energy));
244 }
245
246
247
248 properties.setProperty("standardizeAtomNames", "false");
249 File modelFile = saveDirFile(activeAssembly.getFile());
250 PDBFilter pdbFilter = new PDBFilter(modelFile, activeAssembly, activeAssembly.getForceField(),
251 properties);
252 if (manyBodyOptions.getTitration()) {
253 String remark = format("Titration pH: %6.3f", titrationPH);
254 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true, new String[]{remark})) {
255 logger.info(format(" Save failed for %s", activeAssembly));
256 }
257 } else {
258 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true)) {
259 logger.info(format(" Save failed for %s", activeAssembly));
260 }
261 }
262 }
263
264 if (manyBodyOptions.getTitration()) {
265 System.clearProperty("manybody-titration");
266 }
267
268 return this;
269 }
270
271
272
273
274 public ManyBodyOptions getManyBodyOptions() {
275 return manyBodyOptions;
276 }
277
278
279
280
281
282 public ForceFieldEnergy getPotential() {
283 return potentialEnergy;
284 }
285
286
287
288
289 @Override
290 public List<Potential> getPotentials() {
291 List<Potential> potentials;
292 if (potentialEnergy == null) {
293 potentials = Collections.emptyList();
294 } else {
295 potentials = Collections.singletonList(potentialEnergy);
296 }
297 return potentials;
298 }
299
300 }