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