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-2024.
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.cli;
39  
40  import static java.lang.String.format;
41  
42  import ffx.algorithms.AlgorithmFunctions;
43  import ffx.algorithms.AlgorithmListener;
44  import ffx.algorithms.AlgorithmUtils;
45  import ffx.numerics.Potential;
46  import ffx.potential.MolecularAssembly;
47  import ffx.utilities.FFXScript;
48  import groovy.lang.Binding;
49  
50  import javax.annotation.Nullable;
51  import java.io.File;
52  import java.util.ArrayList;
53  import java.util.List;
54  
55  /**
56   * Base class for scripts in the Algorithms package, providing some key functions.
57   *
58   * @author Michael J. Schnieders
59   * @since 1.0
60   */
61  public class AlgorithmsScript extends FFXScript {
62  
63    /**
64     * An instance of AlgorithmFunctions passed into the current context.
65     */
66    public AlgorithmFunctions algorithmFunctions;
67  
68    /**
69     * An active MolecularAssembly passed into the current context or loaded by the Script from a file
70     * argument.
71     */
72    public MolecularAssembly activeAssembly;
73  
74    /**
75     * An instance of the AlgorithmListener interface.
76     */
77    public AlgorithmListener algorithmListener;
78  
79    /**
80     * The directory in which to place output files. Mostly for tests.
81     */
82    protected File baseDir;
83  
84    public AlgorithmsScript() {
85      this(new Binding());
86    }
87  
88    public AlgorithmsScript(Binding binding) {
89      super(binding);
90    }
91  
92    /**
93     * Reclaims resources associated with all Potential objects associated with this script.
94     *
95     * @return If all Potentials had resources reclaimed.
96     */
97    public boolean destroyPotentials() {
98      boolean allSucceeded = true;
99      for (Potential potent : getPotentials()) {
100       logger.fine(format(" Potential %s is being destroyed. ", potent));
101       allSucceeded = allSucceeded && potent.destroy();
102     }
103     return allSucceeded;
104   }
105 
106   /**
107    * Returns a List of all Potential objects associated with this script.
108    *
109    * @return All Potentials. Sometimes empty, never null.
110    */
111   public List<Potential> getPotentials() {
112     List<Potential> plist = new ArrayList<>();
113     if (activeAssembly != null && activeAssembly.getPotentialEnergy() != null) {
114       plist.add(activeAssembly.getPotentialEnergy());
115     }
116     return plist;
117   }
118 
119   /**
120    * {@inheritDoc}
121    *
122    * <p>Execute the BaseScript init method, then load algorithm functions.
123    */
124   @Override
125   public boolean init() {
126     if (!super.init()) {
127       return false;
128     }
129 
130     Binding binding = getBinding();
131 
132     if (binding.hasVariable("functions")) {
133       algorithmFunctions = (AlgorithmFunctions) binding.getVariable("functions");
134     } else {
135       algorithmFunctions = new AlgorithmUtils();
136       binding.setVariable("functions", algorithmFunctions);
137     }
138 
139     activeAssembly = null;
140     if (binding.hasVariable("active")) {
141       activeAssembly = (MolecularAssembly) binding.getVariable("active");
142     }
143 
144     algorithmListener = null;
145     if (binding.hasVariable("listener")) {
146       algorithmListener = (AlgorithmListener) binding.getVariable("listener");
147     }
148 
149     if (binding.hasVariable("baseDir")) {
150       baseDir = (File) binding.getVariable("baseDir");
151     }
152 
153     return true;
154   }
155 
156   /**
157    * Sets the directory this script should save files to. Mostly used for tests.
158    *
159    * @param baseDir Directory to save output to.
160    */
161   public void setBaseDir(File baseDir) {
162     this.baseDir = baseDir;
163   }
164 
165   /**
166    * Return a File in the base directory with the same name as the input file.
167    * <p>
168    * This will just be the original file if baseDir was never set, which is the case for production
169    * runs.
170    *
171    * @param file File to find a save location for.
172    * @return Returns a File in the base directory with the same name as the input file.
173    */
174   protected File saveDirFile(File file) {
175     if (baseDir == null || !baseDir.exists() || !baseDir.isDirectory() || !baseDir.canWrite()) {
176       return file;
177     } else {
178       String baseName = file.getName();
179       String newName = baseDir.getAbsolutePath() + File.separator + baseName;
180       return new File(newName);
181     }
182   }
183 
184   /**
185    * If a filename is supplied, open it and return the MolecularAssembly. Otherwise, the current
186    * activeAssembly is returned (which may be null).
187    *
188    * @param filename Filename to open.
189    * @return The active assembly.
190    */
191   public MolecularAssembly getActiveAssembly(@Nullable String filename) {
192     if (filename != null) {
193       // Open the supplied file.
194       MolecularAssembly[] assemblies = {algorithmFunctions.open(filename)};
195       activeAssembly = assemblies[0];
196     }
197     return activeAssembly;
198   }
199 
200   /**
201    * If a filename is supplied, open it and return the MolecularAssemblies. Otherwise, the current
202    * activeAssembly is returned (which may be null).
203    *
204    * @param filename Filename to open.
205    * @return The active assemblies.
206    */
207   public MolecularAssembly[] getActiveAssemblies(@Nullable String filename) {
208     MolecularAssembly[] assemblies;
209     if (filename != null) {
210       // Open the supplied file.
211       assemblies = algorithmFunctions.openAll(filename);
212       activeAssembly = assemblies[0];
213       return assemblies;
214     } else {
215       assemblies = new MolecularAssembly[]{activeAssembly};
216     }
217     return assemblies;
218   }
219 
220   /**
221    * Set the Active Assembly. This is a work-around for a strange Groovy static compilation bug where
222    * direct assignment of activeAssembly in Groovy scripts that extend AlgorithmsScript fails (a NPE
223    * results).
224    *
225    * @param molecularAssembly The MolecularAssembly that should be active.
226    */
227   public void setActiveAssembly(MolecularAssembly molecularAssembly) {
228     activeAssembly = molecularAssembly;
229   }
230 
231 }