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.xray.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.MolecularAssembly;
47 import ffx.potential.bonded.Atom;
48 import ffx.potential.bonded.Residue;
49 import ffx.potential.bonded.RotamerLibrary;
50 import ffx.potential.parsers.PDBFilter;
51 import ffx.utilities.FFXBinding;
52 import ffx.xray.DiffractionData;
53 import ffx.xray.RefinementEnergy;
54 import ffx.xray.cli.XrayOptions;
55 import ffx.xray.refine.RefinementMode;
56 import org.apache.commons.configuration2.CompositeConfiguration;
57 import picocli.CommandLine.Command;
58 import picocli.CommandLine.Mixin;
59 import picocli.CommandLine.Parameters;
60
61 import java.io.File;
62 import java.util.ArrayList;
63 import java.util.HashSet;
64 import java.util.List;
65 import java.util.Set;
66
67 import static java.lang.String.format;
68
69
70
71
72
73
74
75
76 @Command(description = " Discrete optimization using a many-body expansion and elimination expressions.", name = "xray.ManyBody")
77 public class ManyBody extends AlgorithmsCommand {
78
79 @Mixin
80 private XrayOptions xrayOptions;
81
82 @Mixin
83 private ManyBodyOptions manyBodyOptions;
84
85
86
87
88 @Parameters(arity = "1..*", paramLabel = "files", description = "PDB and Real Space input files.")
89 private List<String> filenames;
90 private MolecularAssembly[] molecularAssemblies;
91 private DiffractionData diffractionData;
92 private double initialTargetEnergy;
93 private double finalTargetEnergy;
94
95
96
97
98 public ManyBody() {
99 super();
100 }
101
102
103
104
105
106
107 public ManyBody(String[] args) {
108 super(args);
109 }
110
111
112
113
114
115
116 public ManyBody(FFXBinding binding) {
117 super(binding);
118 }
119
120 @Override
121 public ManyBody run() {
122
123 if (!init()) {
124 return this;
125 }
126
127 xrayOptions.init();
128
129
130 System.setProperty("sor-scf-fallback", "false");
131 System.setProperty("direct-scf-fallback", "true");
132
133
134
135
136
137
138 double titrationPH = manyBodyOptions.getTitrationPH();
139 if (titrationPH > 0) {
140 System.setProperty("manybody-titration", "true");
141 }
142
143
144 String nea = System.getProperty("native-environment-approximation", "true");
145 System.setProperty("native-environment-approximation", nea);
146
147 String filename;
148 if (filenames != null && !filenames.isEmpty()) {
149
150 molecularAssemblies = algorithmFunctions.openAll(filenames.getFirst());
151 activeAssembly = molecularAssemblies[0];
152 } else if (activeAssembly == null) {
153 logger.info(helpString());
154 return this;
155 } else {
156 molecularAssemblies = new MolecularAssembly[]{activeAssembly};
157 }
158
159
160 filename = activeAssembly.getFile().getAbsolutePath();
161
162 CompositeConfiguration properties = activeAssembly.getProperties();
163 activeAssembly.getPotentialEnergy().setPrintOnFailure(false, false);
164
165
166 if (xrayOptions.refinementMode != RefinementMode.COORDINATES) {
167 logger.info(" Refinement mode set to COORDINATES.");
168 xrayOptions.refinementMode = RefinementMode.COORDINATES;
169 }
170
171
172 List<Residue> residues = manyBodyOptions.collectResidues(activeAssembly);
173 if (residues == null || residues.isEmpty()) {
174 logger.info(" There are no residues in the active system to optimize.");
175 return this;
176 }
177
178
179 TitrationManyBody titrationManyBody = null;
180 if (titrationPH > 0) {
181 logger.info(format("\n Adding titration hydrogen to: %s\n", filenames.getFirst()));
182 List<Integer> resNumberList = new ArrayList<>();
183 for (Residue residue : residues) {
184 resNumberList.add(residue.getResidueNumber());
185 }
186
187
188 titrationManyBody = new TitrationManyBody(filenames.getFirst(), activeAssembly.getForceField(),
189 resNumberList, titrationPH, manyBodyOptions);
190 molecularAssemblies = titrationManyBody.getProtonatedAssemblies();
191 activeAssembly = molecularAssemblies[0];
192 }
193
194
195 xrayOptions.setProperties(parseResult, properties);
196
197
198 diffractionData = xrayOptions.getDiffractionData(filenames, molecularAssemblies, properties);
199 RefinementEnergy refinementEnergy = xrayOptions.toXrayEnergy(diffractionData);
200 refinementEnergy.setScaling(null);
201
202 boolean isTitrating = false;
203 Set<Atom> excludeAtoms = new HashSet<>();
204
205 for (int i = 0; i < molecularAssemblies.length; i++) {
206
207
208 if (i > 0) {
209 break;
210 }
211 activeAssembly = molecularAssemblies[i];
212 activeAssembly.setFile(new File(filenames.getFirst()));
213
214
215
216 Atom[] atoms = activeAssembly.getAtomArray();
217 double[] bfactors = new double[atoms.length];
218 double averageBFactor = 0;
219 for (int j = 0; j < atoms.length; j++) {
220 double bfactor = atoms[j].getTempFactor();
221 bfactors[j] = bfactor;
222 averageBFactor += bfactor;
223 }
224
225 averageBFactor /= atoms.length;
226 for (Atom atom : atoms) {
227 atom.setTempFactor(averageBFactor);
228 }
229
230 diffractionData.scaleBulkFit();
231 diffractionData.printStats();
232
233 RotamerOptimization rotamerOptimization = new RotamerOptimization(activeAssembly, refinementEnergy, algorithmListener);
234 manyBodyOptions.initRotamerOptimization(rotamerOptimization, activeAssembly);
235
236 double[] x = new double[refinementEnergy.getNumberOfVariables()];
237 x = refinementEnergy.getCoordinates(x);
238 initialTargetEnergy = refinementEnergy.energy(x, true);
239 logger.info(format("\n Initial target energy: %16.8f ", initialTargetEnergy));
240
241 List<Residue> residueList = rotamerOptimization.getResidues();
242
243
244 if (i > 0) {
245 Character altLoc = activeAssembly.getAlternateLocation();
246 List<Residue> altLocResidues = new ArrayList<>();
247 for (Residue r : residues) {
248 if (r.conatainsAltLoc(altLoc)) {
249 altLocResidues.add(r);
250 }
251 }
252 residueList = altLocResidues;
253 rotamerOptimization.setResidues(altLocResidues);
254 }
255
256 RotamerLibrary.measureRotamers(residueList, false);
257 rotamerOptimization.optimize(manyBodyOptions.getAlgorithm(residueList.size()));
258
259 int[] optimalRotamers = rotamerOptimization.getOptimumRotamers();
260
261 if (titrationPH > 0) {
262 isTitrating = titrationManyBody.excludeExcessAtoms(excludeAtoms, optimalRotamers, residueList);
263 }
264 logger.info(" Final Minimum Energy");
265
266 x = refinementEnergy.getCoordinates(x);
267 finalTargetEnergy = refinementEnergy.energy(x, true);
268
269 if (isTitrating) {
270 double phBias = rotamerOptimization.getEnergyExpansion().getTotalRotamerPhBias(residueList, optimalRotamers, titrationPH, manyBodyOptions.getPHRestraint());
271 logger.info(format("\n Rotamer pH Bias %16.8f", phBias));
272 logger.info(format(" Xray Target with Bias%16.8f\n", phBias + finalTargetEnergy));
273 } else {
274 logger.info(format("\n Final Target Energy %16.8f\n", finalTargetEnergy));
275 }
276
277
278 for (int j = 0; j < atoms.length; j++) {
279 atoms[j].setTempFactor(bfactors[j]);
280 }
281 diffractionData.scaleBulkFit();
282 diffractionData.printStats();
283 }
284
285 if (Comm.world().rank() == 0) {
286 properties.setProperty("standardizeAtomNames", "false");
287 File modelFile = saveDirFile(activeAssembly.getFile());
288 PDBFilter pdbFilter = new PDBFilter(modelFile, List.of(molecularAssemblies), activeAssembly.getForceField(), properties);
289 if (titrationPH > 0) {
290 String remark = format("Titration pH: %6.3f", titrationPH);
291 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true, new String[]{remark})) {
292 logger.info(format(" Save failed for %s", activeAssembly));
293 }
294 } else {
295 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true)) {
296 logger.info(format(" Save failed for %s", activeAssembly));
297 }
298 }
299 }
300
301 return this;
302 }
303
304 public double getInitialTargetEnergy() {
305 return initialTargetEnergy;
306 }
307
308 public double getFinalTargetEnergy() {
309 return finalTargetEnergy;
310 }
311
312
313
314
315
316
317
318 public ManyBodyOptions getManyBodyOptions() {
319 return manyBodyOptions;
320 }
321
322 @Override
323 public List<Potential> getPotentials() {
324 return getPotentialsFromAssemblies(molecularAssemblies);
325 }
326
327 @Override
328 public boolean destroyPotentials() {
329 return diffractionData == null ? true : diffractionData.destroy();
330 }
331 }