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.potential.cli; 39 40 import static org.apache.commons.io.FilenameUtils.getFullPath; 41 42 import ffx.numerics.Potential; 43 import ffx.potential.MolecularAssembly; 44 import ffx.potential.utils.PotentialsFunctions; 45 import ffx.potential.utils.PotentialsUtils; 46 import ffx.utilities.FFXScript; 47 import groovy.lang.Binding; 48 49 import java.io.File; 50 import java.util.ArrayList; 51 import java.util.List; 52 import java.util.Properties; 53 54 import org.apache.log4j.PropertyConfigurator; 55 56 import javax.annotation.Nullable; 57 58 /** 59 * Base class for scripts in the Potentials package, providing some key functions. 60 * 61 * @author Michael J. Schnieders 62 * @since 1.0 63 */ 64 public abstract class PotentialScript extends FFXScript { 65 66 /** 67 * An instance of PotentialFunctions passed into the current context. 68 */ 69 public PotentialsFunctions potentialFunctions; 70 71 /** 72 * An active MolecularAssembly passed into the current context or loaded by the Script from a file 73 * argument. 74 */ 75 public MolecularAssembly activeAssembly; 76 77 /** 78 * A temporary directory that contains script artifacts. Temporary files are often created by unit 79 * tests and then deleted. 80 */ 81 public File baseDir = null; 82 83 /** 84 * Default constructor. 85 */ 86 public PotentialScript() { 87 this(new Binding()); 88 } 89 90 /** 91 * Create a Script using the supplied Binding. 92 * 93 * @param binding Binding with variables to use. 94 */ 95 public PotentialScript(Binding binding) { 96 super(binding); 97 } 98 99 /** 100 * Reclaims resources associated with all Potential objects associated with this script. 101 * 102 * @return If all Potentials had resources reclaimed. 103 */ 104 public boolean destroyPotentials() { 105 boolean allSucceeded = true; 106 for (Potential potential : getPotentials()) { 107 if (potential != null) { 108 allSucceeded = allSucceeded && potential.destroy(); 109 } 110 } 111 return allSucceeded; 112 } 113 114 /** 115 * Set the Active Assembly. This is a work-around for a strange Groovy static compilation bug where 116 * direct assignment of activeAssembly in Groovy scripts that extend PotentialScript fails (a NPE 117 * results). 118 * 119 * @param molecularAssembly The MolecularAssembly that should be active. 120 */ 121 public void setActiveAssembly(MolecularAssembly molecularAssembly) { 122 activeAssembly = molecularAssembly; 123 } 124 125 /** 126 * Returns a List of all Potential objects associated with this script. Should be written to 127 * tolerate nulls, as many tests run help() and exit without instantiating their Potentials. 128 * 129 * @return All Potentials. Sometimes empty, never null. 130 */ 131 public List<Potential> getPotentials() { 132 List<Potential> potentialList = new ArrayList<>(); 133 if (activeAssembly != null && activeAssembly.getPotentialEnergy() != null) { 134 potentialList.add(activeAssembly.getPotentialEnergy()); 135 } 136 return potentialList; 137 } 138 139 /** 140 * {@inheritDoc} 141 * 142 * <p>Execute the BaseScript init method, then load potential functions. 143 */ 144 @Override 145 public boolean init() { 146 if (!super.init()) { 147 return false; 148 } 149 150 Binding binding = getBinding(); 151 152 if (binding.hasVariable("functions")) { 153 // FFX is running. 154 potentialFunctions = (PotentialsFunctions) binding.getVariable("functions"); 155 } else { 156 // Potential package is running. 157 potentialFunctions = new PotentialsUtils(); 158 binding.setVariable("functions", potentialFunctions); 159 // Turn off log4j. 160 Properties properties = new Properties(); 161 properties.setProperty("log4j.threshold", "OFF"); 162 properties.setProperty("log4j2.level", "OFF"); 163 properties.setProperty("org.apache.logging.log4j.level", "OFF"); 164 PropertyConfigurator.configure(properties); 165 } 166 167 activeAssembly = null; 168 if (binding.hasVariable("active")) { 169 activeAssembly = (MolecularAssembly) binding.getVariable("active"); 170 } 171 172 if (binding.hasVariable("baseDir")) { 173 baseDir = (File) binding.getVariable("baseDir"); 174 } 175 176 return true; 177 } 178 179 /** 180 * Check that we can write into the current base directory. If not, update the baseDir based on the 181 * supplied filename, including updating the script Binding instance. 182 * 183 * @param dirFromFilename Set the base directory variable <code>baseDir</code> using 184 * this filename if it's not set to a writeable directory. 185 * @return Return the base directory as a String (including an appended 186 * <code>File.separator</code>). 187 */ 188 public String getBaseDirString(String dirFromFilename) { 189 if (baseDir == null || !baseDir.exists() || !baseDir.isDirectory() || !baseDir.canWrite()) { 190 File file = new File(dirFromFilename); 191 baseDir = new File(getFullPath(file.getAbsolutePath())); 192 Binding binding = getBinding(); 193 binding.setVariable("baseDir", baseDir); 194 } 195 return baseDir.toString() + File.separator; 196 } 197 198 /** 199 * If a filename is supplied, open it and return the MolecularAssembly. Otherwise, the current 200 * activeAssembly is returned (which may be null). 201 * 202 * @param filename Filename to open. 203 * @return The active assembly. 204 */ 205 public MolecularAssembly getActiveAssembly(@Nullable String filename) { 206 if (filename != null) { 207 // Open the supplied file. 208 MolecularAssembly[] assemblies = {potentialFunctions.open(filename)}; 209 activeAssembly = assemblies[0]; 210 } 211 return activeAssembly; 212 } 213 214 /** 215 * If a filename is supplied, open it and return the MolecularAssemblies. 216 * Otherwise, the current activeAssembly is returned (which may be null). 217 * 218 * @param filename Filename to open. 219 * @return The active assemblies. 220 */ 221 public MolecularAssembly[] getActiveAssemblies(@Nullable String filename) { 222 MolecularAssembly[] assemblies; 223 if (filename != null) { 224 // Open the supplied file. 225 assemblies = potentialFunctions.openAll(filename); 226 activeAssembly = assemblies[0]; 227 return assemblies; 228 } else { 229 assemblies = new MolecularAssembly[]{activeAssembly}; 230 } 231 return assemblies; 232 } 233 234 }