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.RefinementMinimize.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 RefinementEnergy refinementEnergy;
96
97 ForceFieldEnergy potentialEnergy;
98 private MolecularAssembly[] molecularAssemblies;
99 TitrationManyBody titrationManyBody;
100
101
102
103
104 public ManyBody() {
105 super();
106 }
107
108
109
110
111
112 public ManyBody(String[] args) {
113 super(args);
114 }
115
116
117
118
119
120 public ManyBody(FFXBinding binding) {
121 super(binding);
122 }
123
124 @Override
125 public ManyBody run() {
126
127 if (!init()) {
128 return this;
129 }
130
131 xrayOptions.init();
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 modelFilename;
148 if (filenames != null && !filenames.isEmpty()) {
149 molecularAssemblies = algorithmFunctions.openAll(filenames.get(0));
150 activeAssembly = molecularAssemblies[0];
151 modelFilename = filenames.get(0);
152 } else if (activeAssembly == null) {
153 logger.info(helpString());
154 return this;
155 } else {
156 molecularAssemblies = new MolecularAssembly[]{activeAssembly};
157 modelFilename = activeAssembly.getFile().getAbsolutePath();
158 }
159
160 CompositeConfiguration properties = activeAssembly.getProperties();
161 activeAssembly.getPotentialEnergy().setPrintOnFailure(false, false);
162 potentialEnergy = activeAssembly.getPotentialEnergy();
163
164
165 if (xrayOptions.refinementMode != RefinementMode.COORDINATES) {
166 logger.info(" Refinement mode set to COORDINATES.");
167 xrayOptions.refinementMode = RefinementMode.COORDINATES;
168 }
169
170
171 List<Residue> residues = manyBodyOptions.collectResidues(activeAssembly);
172 if (residues == null || residues.isEmpty()) {
173 logger.info(" There are no residues in the active system to optimize.");
174 return this;
175 }
176
177
178 if (titrationPH > 0) {
179 logger.info(format("\n Adding titration hydrogen to: %s\n", filenames.get(0)));
180 List<Integer> resNumberList = new ArrayList<>();
181 for (Residue residue : residues) {
182 resNumberList.add(residue.getResidueNumber());
183 }
184
185
186 titrationManyBody = new TitrationManyBody(filenames.get(0), activeAssembly.getForceField(),
187 resNumberList, titrationPH, manyBodyOptions);
188 MolecularAssembly[] protonatedAssemblies = titrationManyBody.getProtonatedAssemblies();
189 setActiveAssembly(protonatedAssemblies[0]);
190 potentialEnergy = protonatedAssemblies[0].getPotentialEnergy();
191 molecularAssemblies = protonatedAssemblies;
192 }
193
194
195 xrayOptions.setProperties(parseResult, properties);
196
197
198 DiffractionData diffractionData = xrayOptions.getDiffractionData(filenames, molecularAssemblies, properties);
199 refinementEnergy = xrayOptions.toXrayEnergy(diffractionData);
200 refinementEnergy.setScaling(null);
201
202 boolean isTitrating = false;
203 Set<Atom> excludeAtoms = new HashSet<>();
204 for (MolecularAssembly currentMolecularAssembly : molecularAssemblies) {
205 setActiveAssembly(currentMolecularAssembly);
206 currentMolecularAssembly.setFile(new File(filenames.get(0)));
207 if (currentMolecularAssembly.getAtomList().get(0).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().get(0).getOccupancy());
213 logger.info(" Occupancy of 2nd Molecular Assembly Atoms: " + molecularAssemblies[1].getAtomList().get(0).getOccupancy());
214
215 } else if (currentMolecularAssembly.getAtomList().get(0).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().get(0).getOccupancy());
221 logger.info(" Occupancy of 2nd Molecular Assembly Atoms: " + molecularAssemblies[1].getAtomList().get(0).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
240 if (titrationPH > 0) {
241 isTitrating = titrationManyBody.excludeExcessAtoms(excludeAtoms, optimalRotamers, residueList);
242 }
243 logger.info(" Final Minimum Energy");
244
245 x = refinementEnergy.getCoordinates(x);
246 e = refinementEnergy.energy(x, true);
247
248 if (isTitrating) {
249 double phBias = rotamerOptimization.getEnergyExpansion().getTotalRotamerPhBias(residueList, optimalRotamers, titrationPH, manyBodyOptions.getPHRestraint());
250 logger.info(format("\n Rotamer pH Bias %16.8f", phBias));
251 logger.info(format(" Xray Target with Bias%16.8f\n", phBias + e));
252 } else {
253 logger.info(format("\n Xray Target %16.8f\n", e));
254 }
255 diffractionData.scaleBulkFit();
256 diffractionData.printStats();
257 }
258
259 if (molecularAssemblies.length > 1) {
260 List<Residue> residueListA = molecularAssemblies[0].getResidueList();
261 List<Residue> residueListB = molecularAssemblies[1].getResidueList();
262 int firstRes = residueListA.get(0).getResidueNumber();
263 for (Residue residue : residueListA) {
264 int resNum = residue.getResidueNumber();
265 List<Atom> atomList = residue.getAtomList();
266 for (int i = 0; i < residue.getAtomList().size(); i++) {
267 Atom atom = atomList.get(i);
268 String resNameA = atom.getResidueName();
269
270 double coorAX = atom.getX();
271 double coorAY = atom.getY();
272 double coorAZ = atom.getZ();
273 Residue residueB = residueListB.get(resNum - firstRes);
274 List<Atom> atomListB = residueB.getAtomList();
275 Atom atomB = atomListB.get(i);
276 String resNameB = atomB.getResidueName();
277
278 double coorBX = atomB.getX();
279 double coorBY = atomB.getY();
280 double coorBZ = atomB.getZ();
281 if (coorAX == coorBX && coorAY == coorBY && coorAZ == coorBZ && resNameA.equals(resNameB)) {
282 atom.setAltLoc(' ');
283 atomB.setAltLoc(' ');
284 atom.setOccupancy(1.0);
285 }
286 }
287 }
288 if (titrationPH > 0) {
289 diffractionData.writeModel(removeExtension(filenames.get(0)) + ".pdb", excludeAtoms, titrationPH);
290 } else {
291 diffractionData.writeModel(removeExtension(filenames.get(0)) + ".pdb");
292 }
293 diffractionData.writeData(removeExtension(filenames.get(0)) + ".mtz");
294 } else if (Comm.world().rank() == 0) {
295 String ext = FilenameUtils.getExtension(modelFilename);
296 modelFilename = FilenameUtils.removeExtension(modelFilename);
297 if (ext.toUpperCase().contains("XYZ")) {
298 algorithmFunctions.saveAsXYZ(activeAssembly, new File(modelFilename + ".xyz"));
299 } else {
300 properties.setProperty("standardizeAtomNames", "false");
301 File modelFile = saveDirFile(activeAssembly.getFile());
302 PDBFilter pdbFilter = new PDBFilter(modelFile, activeAssembly,
303 activeAssembly.getForceField(), properties);
304 if (titrationPH > 0) {
305 String remark = format("Titration pH: %6.3f", titrationPH);
306 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true, new String[]{remark})) {
307 logger.info(format(" Save failed for %s", activeAssembly));
308 }
309 } else {
310 if (!pdbFilter.writeFile(modelFile, false, excludeAtoms, true, true)) {
311 logger.info(format(" Save failed for %s", activeAssembly));
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 refinementEnergy == null ? Collections.emptyList() :
331 Collections.singletonList((Potential) refinementEnergy);
332 }
333 }