1 package ffx.potential.commands;
2
3 import static java.lang.String.format;
4
5 import com.google.common.collect.MinMaxPriorityQueue;
6 import ffx.crystal.Crystal;
7 import ffx.numerics.Potential;
8 import ffx.potential.AssemblyState;
9 import ffx.potential.ForceFieldEnergy;
10 import ffx.potential.MolecularAssembly;
11 import ffx.potential.cli.AtomSelectionOptions;
12 import ffx.potential.cli.PotentialCommand;
13 import ffx.potential.parsers.PDBFilter;
14 import ffx.potential.parsers.SystemFilter;
15 import ffx.potential.parsers.XYZFilter;
16 import ffx.potential.utils.StructureMetrics;
17 import ffx.utilities.FFXContext;
18 import java.io.File;
19 import java.util.Collections;
20 import java.util.List;
21 import org.apache.commons.io.FilenameUtils;
22 import picocli.CommandLine.Command;
23 import picocli.CommandLine.Mixin;
24 import picocli.CommandLine.Option;
25 import picocli.CommandLine.Parameters;
26
27
28
29
30
31
32
33
34 @Command(description = " Compute the force field potential energy.", name = "ffxc Energy")
35 public class Energy extends PotentialCommand {
36
37 @Mixin
38 private AtomSelectionOptions atomSelectionOptions;
39
40
41
42 @Option(names = {"-m",
43 "--moments"}, paramLabel = "false", defaultValue = "false", description = "Print out electrostatic moments.")
44 private boolean moments = false;
45
46
47
48 @Option(names = {"--rg",
49 "--gyrate"}, paramLabel = "false", defaultValue = "false", description = "Print out the radius of gyration.")
50 private boolean gyrate = false;
51
52
53
54 @Option(names = {"--in",
55 "--inertia"}, paramLabel = "false", defaultValue = "false", description = "Print out the moments of inertia.")
56 private boolean inertia = false;
57
58
59
60 @Option(names = {"-g",
61 "--gradient"}, paramLabel = "false", defaultValue = "false", description = "Compute the atomic gradient as well as energy.")
62 private boolean gradient = false;
63
64
65
66 @Option(names = {"--fl",
67 "--findLowest"}, paramLabel = "0", defaultValue = "0", description = "Return the n lowest energies from an ARC/PDB file.")
68 private int fl = 0;
69
70
71
72
73 @Option(names = {"-v",
74 "--verbose"}, paramLabel = "false", defaultValue = "false", description = "Print out all energy components for each snapshot.")
75 private boolean verbose = false;
76
77
78
79 @Option(names = {"--dc",
80 "--densityCutoff"}, paramLabel = "0.0", defaultValue = "0.0", description = "Create ARC file of structures above a specified density.")
81 private double dCutoff = 0.0;
82
83
84
85
86 @Option(names = {"--ec",
87 "--energyCutoff"}, paramLabel = "0.0", defaultValue = "0.0", description = "Create ARC file of structures within a specified energy of the lowest energy structure.")
88 private double eCutoff = 0.0;
89
90
91
92 @Parameters(arity = "1", paramLabel = "file", description = "The atomic coordinate file in PDB or XYZ format.")
93 private String filename = null;
94 public double energy = 0.0;
95 public ForceFieldEnergy forceFieldEnergy = null;
96 private AssemblyState assemblyState = null;
97
98
99
100
101 public Energy() {
102 this(new FFXContext());
103 }
104
105
106
107
108
109
110 public Energy(FFXContext ffxContext) {
111 super(ffxContext);
112 }
113
114
115
116
117 public Energy run() {
118
119 if (!init()) {
120 return this;
121 }
122
123
124 setActiveAssembly(getActiveAssembly(filename));
125 if (activeAssembly == null) {
126 logger.info(helpString());
127 return this;
128 }
129
130
131 filename = activeAssembly.getFile().getAbsolutePath();
132
133 logger.info("\n Running Energy on " + filename);
134
135
136 atomSelectionOptions.setActiveAtoms(activeAssembly);
137
138 forceFieldEnergy = activeAssembly.getPotentialEnergy();
139 int nVars = forceFieldEnergy.getNumberOfVariables();
140 double[] x = new double[nVars];
141 forceFieldEnergy.getCoordinates(x);
142
143 if (gradient) {
144 double[] g = new double[nVars];
145 int nAts = (nVars / 3);
146 energy = forceFieldEnergy.energyAndGradient(x, g, true);
147 logger.info(" Atom X, Y and Z Gradient Components (kcal/mol/A)");
148 for (int i = 0; i < nAts; i++) {
149 int i3 = 3 * i;
150 logger.info(String.format(" %7d %16.8f %16.8f %16.8f", i + 1, g[i3], g[i3 + 1], g[i3 + 2]));
151 }
152 } else {
153 energy = forceFieldEnergy.energy(x, true);
154 }
155
156 if (moments) {
157 forceFieldEnergy.getPmeNode().computeMoments(activeAssembly.getActiveAtomArray(), false);
158 }
159
160 if (gyrate) {
161 double rg = StructureMetrics.radiusOfGyration(activeAssembly.getActiveAtomArray());
162 logger.info(String.format(" Radius of gyration: %10.5f A", rg));
163 }
164
165 if (inertia) {
166 double[][] inertiaValue = StructureMetrics.momentsOfInertia(
167 activeAssembly.getActiveAtomArray(), false, true, true);
168 }
169
170 SystemFilter systemFilter = potentialFunctions.getFilter();
171 if (systemFilter instanceof XYZFilter || systemFilter instanceof PDBFilter) {
172
173 int numSnaps = fl;
174 double lowestEnergy = energy;
175 assemblyState = new AssemblyState(activeAssembly);
176 int index = 1;
177
178
179 MinMaxPriorityQueue<StateContainer> lowestEnergyQueue = null;
180 if (fl > 0) {
181 lowestEnergyQueue = MinMaxPriorityQueue.maximumSize(numSnaps).create();
182 lowestEnergyQueue.add(new StateContainer(assemblyState, lowestEnergy));
183 }
184
185 int numModels = systemFilter.countNumModels();
186
187 double[] densities = new double[numModels];
188
189 double[] energies = new double[numModels];
190 energies[0] = energy;
191
192 while (systemFilter.readNext()) {
193 index = index++;
194 Crystal crystal = activeAssembly.getCrystal();
195 densities[index - 1] = crystal.getDensity(activeAssembly.getMass());
196 forceFieldEnergy.setCrystal(crystal);
197 forceFieldEnergy.getCoordinates(x);
198 if (verbose) {
199 logger.info(String.format(" Snapshot %4d", index));
200 if (!crystal.aperiodic()) {
201 logger.info(String.format("\n Density: %6.3f (g/cc)",
202 crystal.getDensity(activeAssembly.getMass())));
203 }
204
205 energy = forceFieldEnergy.energy(x, true);
206 } else {
207 energy = forceFieldEnergy.energy(x, false);
208 logger.info(String.format(" Snapshot %4d: %16.8f (kcal/mol)", index, energy));
209 }
210
211 energies[index - 1] = energy;
212
213
214 if (energy < lowestEnergy) {
215 lowestEnergy = energy;
216 }
217
218 if (fl > 0) {
219 lowestEnergyQueue.add(new StateContainer(new AssemblyState(activeAssembly), energy));
220 }
221
222 if (moments) {
223 forceFieldEnergy.getPmeNode().computeMoments(activeAssembly.getActiveAtomArray(), false);
224 }
225
226 if (gyrate) {
227 double rg = StructureMetrics.radiusOfGyration(activeAssembly.getActiveAtomArray());
228 logger.info(String.format(" Radius of gyration: %10.5f A", rg));
229 }
230
231 if (inertia) {
232 double[][] inertiaValue = StructureMetrics.momentsOfInertia(
233 activeAssembly.getActiveAtomArray(), false, true, true);
234 }
235
236 }
237
238
239 String dirString = getBaseDirString(filename);
240
241
242 try {
243 if ((eCutoff > 0.0 || dCutoff > 0.0) && numModels > 1) {
244 systemFilter.readNext(true);
245 setActiveAssembly(systemFilter.getActiveMolecularSystem());
246
247 String name = FilenameUtils.getName(filename);
248 String ext = FilenameUtils.getExtension(name);
249 name = FilenameUtils.removeExtension(name);
250
251 File saveFile;
252 SystemFilter writeFilter;
253 if (ext.toUpperCase().contains("XYZ")) {
254 saveFile = new File(dirString + name + ".xyz");
255 writeFilter = new XYZFilter(saveFile, activeAssembly, activeAssembly.getForceField(),
256 activeAssembly.getProperties());
257 potentialFunctions.saveAsXYZ(activeAssembly, saveFile);
258 } else if (ext.toUpperCase().contains("ARC")) {
259 saveFile = new File(dirString + name + ".arc");
260 saveFile = potentialFunctions.versionFile(saveFile);
261 writeFilter = new XYZFilter(saveFile, activeAssembly, activeAssembly.getForceField(),
262 activeAssembly.getProperties());
263 logger.info(" Saving to " + saveFile.getAbsolutePath());
264 saveFile.createNewFile();
265 } else {
266 saveFile = new File(dirString + name + ".pdb");
267 saveFile = potentialFunctions.versionFile(saveFile);
268 writeFilter = new PDBFilter(saveFile, activeAssembly, activeAssembly.getForceField(),
269 activeAssembly.getProperties());
270 ((PDBFilter) writeFilter).setModelNumbering(0);
271 saveFile.createNewFile();
272 }
273
274
275 if (systemFilter instanceof XYZFilter || systemFilter instanceof PDBFilter) {
276 int structNum = 0;
277 if (eCutoff > 0.0) {
278 logger.info(
279 format("Lowest Energy of: %16.4f\n Saving structures with energy below: %16.4f",
280 lowestEnergy, lowestEnergy + eCutoff));
281 }
282
283 do {
284 if (dCutoff > 0.0 && eCutoff > 0.0) {
285 if (energies[structNum] < lowestEnergy + eCutoff && densities[structNum] > dCutoff) {
286 if (systemFilter instanceof PDBFilter) {
287 PDBFilter pdbFilter = (PDBFilter) systemFilter;
288 pdbFilter.writeFile(saveFile, true, false, false);
289
290 } else if (systemFilter instanceof XYZFilter) {
291 writeFilter.writeFile(saveFile, true);
292 }
293 }
294 } else if (dCutoff > 0.0) {
295 if (densities[structNum] > dCutoff) {
296 if (systemFilter instanceof PDBFilter) {
297 PDBFilter pdbFilter = (PDBFilter) systemFilter;
298 pdbFilter.writeFile(saveFile, true, false, false);
299
300 } else if (systemFilter instanceof XYZFilter) {
301 writeFilter.writeFile(saveFile, true);
302 }
303 }
304 } else if (eCutoff > 0.0) {
305 if (energies[structNum] < lowestEnergy + eCutoff) {
306 if (systemFilter instanceof PDBFilter) {
307 PDBFilter pdbFilter = (PDBFilter) systemFilter;
308 pdbFilter.writeFile(saveFile, true, false, false);
309
310 } else if (systemFilter instanceof XYZFilter) {
311 writeFilter.writeFile(saveFile, true);
312 }
313 }
314 }
315 structNum++;
316 } while (systemFilter.readNext());
317 if (systemFilter instanceof PDBFilter) {
318
319 }
320 }
321 }
322 } catch (Exception e) {
323 logger.info(" Exception evaluating cutoffs:\n " + e);
324 }
325
326 if (fl > 0) {
327 if (numSnaps > index) {
328 logger.warning(String.format(
329 " Requested %d snapshots, but file %s has only %d snapshots. All %d energies will be reported",
330 numSnaps, filename, index, index));
331 numSnaps = index;
332 }
333
334 String name = FilenameUtils.getName(filename);
335
336 for (int i = 0; i < numSnaps - 1; i++) {
337 StateContainer savedState = lowestEnergyQueue.removeLast();
338 AssemblyState finalAssembly = savedState.state();
339 finalAssembly.revertState();
340 double finalEnergy = savedState.getEnergy();
341 logger.info(
342 String.format(" The potential energy found is %16.8f (kcal/mol)", finalEnergy));
343 File saveFile = potentialFunctions.versionFile(new File(dirString + name));
344 MolecularAssembly molecularAssembly = assemblyState.getMolecularAssembly();
345 potentialFunctions.saveAsPDB(molecularAssembly, saveFile);
346 }
347
348 StateContainer savedState = lowestEnergyQueue.removeLast();
349 AssemblyState lowestAssembly = savedState.state();
350 lowestEnergy = savedState.getEnergy();
351
352 assemblyState.revertState();
353 logger.info(
354 String.format(" The lowest potential energy found is %16.8f (kcal/mol)", lowestEnergy));
355
356
357 File saveFile = potentialFunctions.versionFile(new File(dirString + name));
358 MolecularAssembly molecularAssembly = assemblyState.getMolecularAssembly();
359 potentialFunctions.saveAsPDB(molecularAssembly, saveFile);
360 }
361
362 }
363
364 return this;
365 }
366
367 @Override
368 public List<Potential> getPotentials() {
369 List<Potential> potentials;
370 if (forceFieldEnergy == null) {
371 potentials = Collections.emptyList();
372 } else {
373 potentials = Collections.singletonList((Potential) forceFieldEnergy);
374 }
375
376 return potentials;
377 }
378
379
380
381
382
383
384 public static void main(String... args) {
385 System.setProperty("java.awt.headless", "true");
386 System.setProperty("j3d.rend", "noop");
387 FFXContext binding = new FFXContext(args);
388 Energy energyScript = new Energy(binding);
389 energyScript.run();
390 System.exit(0);
391 }
392
393 public AtomSelectionOptions getAtomSelectionOptions() {
394 return atomSelectionOptions;
395 }
396
397 public void setAtomSelectionOptions(AtomSelectionOptions atomSelectionOptions) {
398 this.atomSelectionOptions = atomSelectionOptions;
399 }
400
401 private record StateContainer(AssemblyState state, double e) implements Comparable<StateContainer> {
402
403 public double getEnergy() {
404 return e;
405 }
406
407 @Override
408 public int compareTo(StateContainer o) {
409 return Double.compare(e, o.getEnergy());
410 }
411
412 }
413 }