View Javadoc
1   //******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  //******************************************************************************
38  package ffx.algorithms.commands;
39  
40  import ffx.algorithms.cli.AlgorithmsCommand;
41  import ffx.algorithms.cli.MinimizeOptions;
42  import ffx.crystal.Crystal;
43  import ffx.numerics.Potential;
44  import ffx.potential.ForceFieldEnergy;
45  import ffx.potential.cli.AtomSelectionOptions;
46  import ffx.potential.openmm.OpenMMEnergy;
47  import ffx.potential.parsers.PDBFilter;
48  import ffx.potential.parsers.SystemFilter;
49  import ffx.potential.parsers.XYZFilter;
50  import ffx.utilities.FFXBinding;
51  import ffx.utilities.FileUtils;
52  import org.apache.commons.io.FilenameUtils;
53  import picocli.CommandLine.Command;
54  import picocli.CommandLine.Mixin;
55  import picocli.CommandLine.Parameters;
56  
57  import java.io.File;
58  import java.util.Collections;
59  import java.util.List;
60  
61  import static java.lang.String.format;
62  
63  /**
64   * The Minimize script uses OpenMM accelerated L-BFGS algorithm to minimize the
65   * energy of a molecular system.
66   * <br>
67   * Usage:
68   * <br>
69   * ffxc MinimizeOpenMM [options] &lt;filename&gt;
70   */
71  @Command(description = " Run OpenMM Accelerated L-BFGS minimization on a system.", name = "MinimizeOpenMM")
72  public class MinimizeOpenMM extends AlgorithmsCommand {
73  
74    @Mixin
75    private AtomSelectionOptions atomSelectionOptions;
76  
77    @Mixin
78    private MinimizeOptions minimizeOptions;
79  
80    /**
81     * A PDB or XYZ filename.
82     */
83    @Parameters(arity = "1", paramLabel = "file",
84        description = "XYZ or PDB input file.")
85    private String filename;
86  
87    private ForceFieldEnergy forceFieldEnergy;
88  
89    /**
90     * MinimizeOpenMM Constructor.
91     */
92    public MinimizeOpenMM() {
93      super();
94    }
95  
96    /**
97     * MinimizeOpenMM Constructor.
98     *
99     * @param binding The Binding to use.
100    */
101   public MinimizeOpenMM(FFXBinding binding) {
102     super(binding);
103   }
104 
105   /**
106    * MinimizeOpenMM constructor that sets the command line arguments.
107    *
108    * @param args Command line arguments.
109    */
110   public MinimizeOpenMM(String[] args) {
111     super(args);
112   }
113 
114   /**
115    * {@inheritDoc}
116    */
117   @Override
118   public MinimizeOpenMM run() {
119 
120     // Init the context and bind variables.
121     if (!init()) {
122       return this;
123     }
124 
125     if (System.getProperty("platform") == null || System.getProperty("platform").isEmpty()) {
126       System.setProperty("platform", "OMM");
127     }
128 
129     // Load the MolecularAssembly.
130     activeAssembly = getActiveAssembly(filename);
131     if (activeAssembly == null) {
132       logger.info(helpString());
133       return this;
134     }
135 
136     // Set the filename.
137     filename = activeAssembly.getFile().getAbsolutePath();
138 
139     atomSelectionOptions.setActiveAtoms(activeAssembly);
140 
141     forceFieldEnergy = activeAssembly.getPotentialEnergy();
142     switch (forceFieldEnergy.getPlatform()) {
143       case OMM:
144       case OMM_CUDA:
145       case OMM_OPENCL:
146       case OMM_CPU:
147       case OMM_REF:
148         logger.fine(" Platform is appropriate for OpenMM Minimization.");
149         break;
150       case FFX:
151       default:
152         logger.severe(format(
153             " Platform %s is inappropriate for OpenMM minimization. Please explicitly specify an OpenMM platform.",
154             forceFieldEnergy.getPlatform()));
155         break;
156     }
157 
158     if (forceFieldEnergy instanceof OpenMMEnergy) {
159       ffx.algorithms.optimize.MinimizeOpenMM minimizeOpenMM = new ffx.algorithms.optimize.MinimizeOpenMM(
160           activeAssembly);
161       minimizeOpenMM.minimize(minimizeOptions.getEps(), minimizeOptions.getIterations());
162 
163       if (baseDir == null || !baseDir.exists() || !baseDir.isDirectory() || !baseDir.canWrite()) {
164         baseDir = new File(FilenameUtils.getFullPath(filename));
165       }
166 
167       String dirName = baseDir.toString() + File.separator;
168       String name = FilenameUtils.getName(filename);
169       String ext = FilenameUtils.getExtension(name);
170       name = FilenameUtils.removeExtension(name);
171 
172       File saveFile;
173       SystemFilter writeFilter;
174       PDBFilter pdbFilter = null;
175       XYZFilter xyzFilter = null;
176       if (ext.toUpperCase().contains("XYZ")) {
177         saveFile = new File(dirName + name + ".xyz");
178         xyzFilter = new XYZFilter(saveFile, activeAssembly, activeAssembly.getForceField(),
179             activeAssembly.getProperties());
180         writeFilter = xyzFilter;
181         algorithmFunctions.saveAsXYZ(activeAssembly, saveFile);
182       } else if (ext.toUpperCase().contains("ARC")) {
183         saveFile = new File(dirName + name + ".arc");
184         xyzFilter = new XYZFilter(saveFile, activeAssembly, activeAssembly.getForceField(),
185             activeAssembly.getProperties());
186         writeFilter = xyzFilter;
187         algorithmFunctions.saveAsXYZ(activeAssembly, saveFile);
188       } else {
189         saveFile = new File(dirName + name + ".pdb");
190         pdbFilter = new PDBFilter(saveFile, activeAssembly, activeAssembly.getForceField(),
191             activeAssembly.getProperties());
192         writeFilter = pdbFilter;
193         int numModels = algorithmFunctions.getFilter().countNumModels();
194         if (numModels > 1) {
195           pdbFilter.setModelNumbering(0);
196         }
197         pdbFilter.writeFile(saveFile, true, false, false);
198       }
199 
200       SystemFilter systemFilter = algorithmFunctions.getFilter();
201       saveFile = activeAssembly.getFile();
202 
203       if (systemFilter instanceof XYZFilter || systemFilter instanceof PDBFilter) {
204         while (systemFilter.readNext()) {
205           Crystal crystal = activeAssembly.getCrystal();
206           ForceFieldEnergy forceFieldEnergy = activeAssembly.getPotentialEnergy();
207           forceFieldEnergy.setCrystal(crystal);
208           if (systemFilter instanceof PDBFilter) {
209             FileUtils.append(saveFile, "ENDMDL\n");
210             minimizeOpenMM.minimize(minimizeOptions.getEps(), minimizeOptions.getIterations());
211             pdbFilter.writeFile(saveFile, true, false, false);
212           } else if (systemFilter instanceof XYZFilter) {
213             minimizeOpenMM.minimize(minimizeOptions.getEps(), minimizeOptions.getIterations());
214             writeFilter.writeFile(saveFile, true);
215           }
216         }
217         if (systemFilter instanceof PDBFilter) {
218           FileUtils.append(saveFile, "END\n");
219         }
220       }
221     } else {
222       logger.severe(" Could not start OpenMM minimization.");
223     }
224 
225     return this;
226   }
227 
228   /**
229    * {@inheritDoc}
230    */
231   @Override
232   public List<Potential> getPotentials() {
233     List<Potential> potentials;
234     if (forceFieldEnergy == null) {
235       potentials = Collections.emptyList();
236     } else {
237       potentials = Collections.singletonList(forceFieldEnergy);
238     }
239     return potentials;
240   }
241 
242 }