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 System.setProperty("sor-scf-fallback", "false");
131 System.setProperty("direct-scf-fallback", "true");
132
133
134
135
136
137 double titrationPH = manyBodyOptions.getTitrationPH();
138
139 if (manyBodyOptions.getTitration()) {
140 System.setProperty("manybody-titration", "true");
141 }
142
143
144 boolean lambdaTerm = alchemicalOptions.hasSoftcore();
145 if (lambdaTerm) {
146
147 System.setProperty("lambdaterm", "true");
148
149 System.setProperty("elec-lambdaterm", "false");
150
151 System.setProperty("intramolecular-softcore", "true");
152 }
153
154
155 activeAssembly = getActiveAssembly(filename);
156
157 if (activeAssembly == null) {
158 logger.info(helpString());
159 return this;
160 }
161
162 String listResidues = "";
163 if (manyBodyOptions.getOnlyTitration() ||
164 manyBodyOptions.getInterestedResidue() != -1 && manyBodyOptions.getInclusionCutoff() != -1) {
165 listResidues = manyBodyOptions.selectInclusionResidues(activeAssembly.getResidueList(),
166 manyBodyOptions.getInterestedResidue(), manyBodyOptions.getOnlyTitration(), manyBodyOptions.getInclusionCutoff());
167 manyBodyOptions.setListResidues(listResidues);
168 }
169
170 CompositeConfiguration properties = activeAssembly.getProperties();
171
172
173 if (properties.getBoolean("standardizeAtomNames", false)) {
174 renameAtomsToPDBStandard(activeAssembly);
175 }
176
177 activeAssembly.getPotentialEnergy().setPrintOnFailure(false, false);
178 potentialEnergy = activeAssembly.getPotentialEnergy();
179
180
181 List<Residue> residues = manyBodyOptions.collectResidues(activeAssembly);
182 if (residues == null || residues.isEmpty()) {
183 logger.info(" There are no residues in the active system to optimize.");
184 return this;
185 }
186
187
188 if (manyBodyOptions.getTitration()) {
189 logger.info("\n Adding titration hydrogen to : " + filename + "\n");
190
191
192 List<Integer> resNumberList = new ArrayList<>();
193 for (Residue residue : residues) {
194 resNumberList.add(residue.getResidueNumber());
195 }
196
197
198 titrationManyBody = new TitrationManyBody(filename, activeAssembly.getForceField(),
199 resNumberList, titrationPH, manyBodyOptions);
200 activeAssembly = titrationManyBody.getProtonatedAssembly();
201 potentialEnergy = activeAssembly.getPotentialEnergy();
202 }
203
204 if (lambdaTerm) {
205 alchemicalOptions.setFirstSystemAlchemistry(activeAssembly);
206 LambdaInterface lambdaInterface = potentialEnergy;
207 double lambda = alchemicalOptions.getInitialLambda();
208 logger.info(format(" Setting ManyBody softcore lambda to: %5.3f", lambda));
209 lambdaInterface.setLambda(lambda);
210 }
211
212 RotamerOptimization rotamerOptimization = new RotamerOptimization(activeAssembly,
213 potentialEnergy, algorithmListener);
214 rotamerOptimization.setPHRestraint(manyBodyOptions.getPHRestraint());
215 rotamerOptimization.setpH(titrationPH);
216
217 manyBodyOptions.initRotamerOptimization(rotamerOptimization, activeAssembly);
218 List<Residue> residueList = rotamerOptimization.getResidues();
219
220 logger.info("\n Initial Potential Energy:");
221 potentialEnergy.energy(false, true);
222
223 logger.info("\n Initial Rotamer Torsion Angles:");
224 RotamerLibrary.measureRotamers(residueList, false);
225
226
227 rotamerOptimization.optimize(manyBodyOptions.getAlgorithm(residueList.size()));
228
229 boolean isTitrating = false;
230 Set<Atom> excludeAtoms = new HashSet<>();
231 int[] optimalRotamers = rotamerOptimization.getOptimumRotamers();
232 if (manyBodyOptions.getTitration()) {
233 isTitrating = titrationManyBody.excludeExcessAtoms(excludeAtoms, optimalRotamers, residueList);
234 }
235
236
237 int rank = Comm.world().rank();
238 if (rank == 0) {
239 logger.info(" Final Minimum Energy");
240 double energy = potentialEnergy.energy(false, true);
241 if (isTitrating) {
242 double phBias = rotamerOptimization.getEnergyExpansion().getTotalRotamerPhBias(residueList,
243 optimalRotamers, titrationPH, manyBodyOptions.getPHRestraint());
244 logger.info(format("\n Rotamer pH Bias %16.8f", phBias));
245 logger.info(format(" Potential with Bias%16.8f\n", phBias + energy));
246 }
247
248
249
250 properties.setProperty("standardizeAtomNames", "false");
251 File modelFile = saveDirFile(activeAssembly.getFile());
252 PDBFilter pdbFilter = new PDBFilter(modelFile, activeAssembly, activeAssembly.getForceField(),
253 properties);
254 if (manyBodyOptions.getTitration()) {
255 String remark = format("Titration pH: %6.3f", titrationPH);
256 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true, new String[]{remark})) {
257 logger.info(format(" Save failed for %s", activeAssembly));
258 }
259 } else {
260 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true)) {
261 logger.info(format(" Save failed for %s", activeAssembly));
262 }
263 }
264 }
265
266 if (manyBodyOptions.getTitration()) {
267 System.clearProperty("manybody-titration");
268 }
269
270 return this;
271 }
272
273
274
275
276 public ManyBodyOptions getManyBodyOptions() {
277 return manyBodyOptions;
278 }
279
280
281
282
283
284 public ForceFieldEnergy getPotential() {
285 return potentialEnergy;
286 }
287
288
289
290
291 @Override
292 public List<Potential> getPotentials() {
293 List<Potential> potentials;
294 if (potentialEnergy == null) {
295 potentials = Collections.emptyList();
296 } else {
297 potentials = Collections.singletonList(potentialEnergy);
298 }
299 return potentials;
300 }
301
302 }