Java tutorial
/** * Title: Force Field X. * * Description: Force Field X - Software for Molecular Biophysics. * * Copyright: Copyright (c) Michael J. Schnieders 2001-2017. * * This file is part of Force Field X. * * Force Field X is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * Force Field X is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA * * Linking this library statically or dynamically with other modules is making a * combined work based on this library. Thus, the terms and conditions of the * GNU General Public License cover the whole combination. * * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent modules, and * to copy and distribute the resulting executable under terms of your choice, * provided that you also meet, for each linked independent module, the terms * and conditions of the license of that module. An independent module is a * module which is not derived from or based on this library. If you modify this * library, you may extend this exception to your version of the library, but * you are not obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package ffx.potential.parameters; import java.io.File; import java.net.URL; import java.util.Arrays; import java.util.Collection; import java.util.EnumMap; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import static java.lang.String.format; import org.apache.commons.configuration.CompositeConfiguration; /** * The ForceField class organizes parameters for a molecular mechanics force * field. * * @author Michael J. Schnieders * @since 1.0 * */ public class ForceField { private static final Logger logger = Logger.getLogger(ForceField.class.getName()); /** * A map between a force field name and its internal parameter file. */ private static final Map<ForceFieldName, URL> forceFields = new EnumMap<>(ForceFieldName.class); private static final boolean noRenumbering = System.getProperty("noPatchRenumbering") != null; static { ClassLoader cl = ForceField.class.getClassLoader(); String prefix = "ffx/potential/parameters/ff/"; for (ForceFieldName ff : ForceFieldName.values()) { forceFields.put(ff, cl.getResource(prefix + ff)); } } /** * <p> * Get for the URL for the named force field.</p> * * @param forceField a * {@link ffx.potential.parameters.ForceField.ForceFieldName} object. * @return a {@link java.net.URL} object. */ public static URL getForceFieldURL(ForceFieldName forceField) { if (forceField == null) { return null; } return forceFields.get(forceField); } /** * URL to the force field parameter file. */ public URL forceFieldURL; /** * Reference to the keyword file in use. */ public File keywordFile; /** * The CompositeConfiguration that contains key=value property pairs from a * number of sources. */ private final CompositeConfiguration properties; private final Map<String, AngleType> angleTypes; private final Map<String, AtomType> atomTypes; private final Map<String, BioType> bioTypes; private final Map<String, BondType> bondTypes; private final Map<String, ChargeType> chargeTypes; private final Map<String, ISolvRadType> iSolvRadTypes; private final Map<String, MultipoleType> multipoleTypes; private final Map<String, OutOfPlaneBendType> outOfPlaneBendTypes; private final Map<String, PolarizeType> polarizeTypes; private final Map<String, StretchBendType> stretchBendTypes; private final Map<String, PiTorsionType> piTorsionTypes; private final Map<String, TorsionType> torsionTypes; private final Map<String, ImproperTorsionType> imptorsTypes; private final Map<String, TorsionTorsionType> torsionTorsionTypes; private final Map<String, UreyBradleyType> ureyBradleyTypes; private final Map<String, VDWType> vanderWaalsTypes; private final Map<String, RelativeSolvationType> relativeSolvationTypes; private final Map<ForceFieldType, Map> forceFieldTypes; /** * ForceField Constructor. * * @param properties a * {@link org.apache.commons.configuration.CompositeConfiguration} object. * @param parameterFile a {@link java.io.File} object. */ public ForceField(CompositeConfiguration properties, File parameterFile) { this(properties); this.keywordFile = parameterFile; } /** * ForceField Constructor. * * @param properties a * {@link org.apache.commons.configuration.CompositeConfiguration} object. */ public ForceField(CompositeConfiguration properties) { this.properties = properties; /** * Each force field "type" implements the "Comparator<String>" interface * so that passing an "empty" instance of the "type" to its TreeMap * constructor will keep the types sorted. */ angleTypes = new TreeMap<>(new AngleType(new int[3], 0, new double[1], null)); atomTypes = new TreeMap<>(new AtomType(0, 0, null, null, 0, 0, 0)); bioTypes = new TreeMap<>(new BioType(0, null, null, 0, null)); bondTypes = new TreeMap<>(new BondType(new int[2], 0, 0, null)); chargeTypes = new TreeMap<>(new ChargeType(0, 0)); iSolvRadTypes = new TreeMap<>(new ISolvRadType(0, 0.0)); multipoleTypes = new TreeMap<>(new MultipoleType(0, new double[3], new double[3][3], null, null)); outOfPlaneBendTypes = new TreeMap<>(new OutOfPlaneBendType(new int[4], 0)); piTorsionTypes = new TreeMap<>(new PiTorsionType(new int[2], 0)); polarizeTypes = new TreeMap<>(new PolarizeType(0, 0, 0, new int[1])); stretchBendTypes = new TreeMap<>(new StretchBendType(new int[3], new double[1])); torsionTorsionTypes = new TreeMap<>(); torsionTypes = new TreeMap<>(new TorsionType(new int[4], new double[1], new double[1], new int[1])); imptorsTypes = new TreeMap<>(new ImproperTorsionType(new int[4], 0.0, 0.0, 2)); ureyBradleyTypes = new TreeMap<>(new UreyBradleyType(new int[3], 0, 0)); vanderWaalsTypes = new TreeMap<>(new VDWType(0, 0, 0, 0)); relativeSolvationTypes = new TreeMap<>(new RelativeSolvationType("", 0.0)); forceFieldTypes = new EnumMap<>(ForceFieldType.class); forceFieldTypes.put(ForceFieldType.ANGLE, angleTypes); forceFieldTypes.put(ForceFieldType.ATOM, atomTypes); forceFieldTypes.put(ForceFieldType.BOND, bondTypes); forceFieldTypes.put(ForceFieldType.BIOTYPE, bioTypes); forceFieldTypes.put(ForceFieldType.CHARGE, chargeTypes); forceFieldTypes.put(ForceFieldType.ISOLVRAD, iSolvRadTypes); forceFieldTypes.put(ForceFieldType.OPBEND, outOfPlaneBendTypes); forceFieldTypes.put(ForceFieldType.MULTIPOLE, multipoleTypes); forceFieldTypes.put(ForceFieldType.PITORS, piTorsionTypes); forceFieldTypes.put(ForceFieldType.POLARIZE, polarizeTypes); forceFieldTypes.put(ForceFieldType.STRBND, stretchBendTypes); forceFieldTypes.put(ForceFieldType.TORSION, torsionTypes); forceFieldTypes.put(ForceFieldType.IMPTORS, imptorsTypes); forceFieldTypes.put(ForceFieldType.TORTORS, torsionTorsionTypes); forceFieldTypes.put(ForceFieldType.UREYBRAD, ureyBradleyTypes); forceFieldTypes.put(ForceFieldType.VDW, vanderWaalsTypes); forceFieldTypes.put(ForceFieldType.RELATIVESOLV, relativeSolvationTypes); } /** * Returns the minimum atom class value. * * @return */ public int minClass() { int minClass = maxClass(); for (AtomType type : atomTypes.values()) { if (type.atomClass < minClass) { minClass = type.atomClass; } } return minClass; } /** * Returns the minimum atom type value. * * @return */ public int minType() { int minType = maxType(); for (String key : atomTypes.keySet()) { int type = Integer.parseInt(key); if (type < minType) { minType = type; } } return minType; } /** * Returns the minimum Biotype value. * * @return */ public int minBioType() { int minBioType = maxBioType(); for (String key : bioTypes.keySet()) { int type = Integer.parseInt(key); if (type < minBioType) { minBioType = type; } } return minBioType; } /** * Returns the maximum atom class value. * * @return */ public int maxClass() { int maxClass = 0; for (AtomType type : atomTypes.values()) { if (type.atomClass > maxClass) { maxClass = type.atomClass; } } return maxClass; } /** * Returns the maximum atom type value. * * @return */ public int maxType() { int maxType = 0; for (String key : atomTypes.keySet()) { int type = Integer.parseInt(key); if (type > maxType) { maxType = type; } } return maxType; } /** * Returns the maximum Biotype. * * @return */ public int maxBioType() { int maxBioType = 0; for (String key : bioTypes.keySet()) { int type = Integer.parseInt(key); if (type > maxBioType) { maxBioType = type; } } return maxBioType; } /** * Renumber ForceField class, type and biotype values. * * @param classOffset * @param typeOffset * @param bioTypeOffset */ public void renumberForceField(int classOffset, int typeOffset, int bioTypeOffset) { if (noRenumbering) { return; } for (AngleType angleType : angleTypes.values()) { angleType.incrementClasses(classOffset); } for (AtomType atomType : atomTypes.values()) { atomType.incrementClassAndType(classOffset, typeOffset); } for (BioType bioType : bioTypes.values()) { bioType.incrementIndexAndType(bioTypeOffset, typeOffset); } for (BondType bondType : bondTypes.values()) { bondType.incrementClasses(classOffset); } for (MultipoleType multipoleType : multipoleTypes.values()) { multipoleType.incrementType(typeOffset); } for (OutOfPlaneBendType outOfPlaneBendType : outOfPlaneBendTypes.values()) { outOfPlaneBendType.incrementClasses(classOffset); } for (PiTorsionType piTorsionType : piTorsionTypes.values()) { piTorsionType.incrementClasses(classOffset); } for (PolarizeType polarizeType : polarizeTypes.values()) { polarizeType.incrementType(typeOffset); } for (StretchBendType stretchBendType : stretchBendTypes.values()) { stretchBendType.incrementClasses(classOffset); } for (TorsionTorsionType torsionTorsionType : torsionTorsionTypes.values()) { torsionTorsionType.incrementClasses(classOffset); } for (TorsionType torsionType : torsionTypes.values()) { torsionType.incrementClasses(classOffset); } for (ImproperTorsionType improperTorsionType : imptorsTypes.values()) { improperTorsionType.incrementClasses(classOffset); } for (UreyBradleyType ureyBradleyType : ureyBradleyTypes.values()) { ureyBradleyType.incrementClasses(classOffset); } for (VDWType vanderWaalsType : vanderWaalsTypes.values()) { vanderWaalsType.incrementClass(classOffset); } for (ISolvRadType iSolvRadType : iSolvRadTypes.values()) { iSolvRadType.incrementType(typeOffset); } } /** * Append a 2nd ForceField "patch" to the current ForceField. Note that only * the force field types are appended; properties are ignored. * * @param patch The force field patch to append. */ public void append(ForceField patch) { // Determine the highest current atom class, atom type and biotype index. int classOffset = maxClass(); int typeOffset = maxType(); int bioTypeOffset = maxBioType(); int minClass = patch.minClass(); int minType = patch.minType(); int minBioType = patch.minBioType(); classOffset -= (minClass - 1); typeOffset -= (minType - 1); bioTypeOffset -= (minBioType - 1); patch.renumberForceField(classOffset, typeOffset, bioTypeOffset); for (AngleType angleType : patch.angleTypes.values()) { angleTypes.put(angleType.getKey(), angleType); } for (AtomType atomType : patch.atomTypes.values()) { atomTypes.put(atomType.getKey(), atomType); } for (BioType bioType : patch.bioTypes.values()) { bioTypes.put(bioType.getKey(), bioType); } for (BondType bondType : patch.bondTypes.values()) { bondTypes.put(bondType.getKey(), bondType); } for (MultipoleType multipoleType : patch.multipoleTypes.values()) { multipoleTypes.put(multipoleType.getKey(), multipoleType); } for (OutOfPlaneBendType outOfPlaneBendType : patch.outOfPlaneBendTypes.values()) { outOfPlaneBendTypes.put(outOfPlaneBendType.getKey(), outOfPlaneBendType); } for (PiTorsionType piTorsionType : patch.piTorsionTypes.values()) { piTorsionTypes.put(piTorsionType.getKey(), piTorsionType); } for (PolarizeType polarizeType : patch.polarizeTypes.values()) { polarizeTypes.put(polarizeType.getKey(), polarizeType); } for (StretchBendType stretchBendType : patch.stretchBendTypes.values()) { stretchBendTypes.put(stretchBendType.getKey(), stretchBendType); } for (TorsionTorsionType torsionTorsionType : patch.torsionTorsionTypes.values()) { torsionTorsionTypes.put(torsionTorsionType.getKey(), torsionTorsionType); } for (TorsionType torsionType : patch.torsionTypes.values()) { torsionTypes.put(torsionType.getKey(), torsionType); } for (ImproperTorsionType improperTorsionType : patch.imptorsTypes.values()) { imptorsTypes.put(improperTorsionType.getKey(), improperTorsionType); } for (UreyBradleyType ureyBradleyType : patch.ureyBradleyTypes.values()) { ureyBradleyTypes.put(ureyBradleyType.getKey(), ureyBradleyType); } for (VDWType vdwType : patch.vanderWaalsTypes.values()) { vanderWaalsTypes.put(vdwType.getKey(), vdwType); } for (ISolvRadType iSolvRadType : patch.iSolvRadTypes.values()) { iSolvRadTypes.put(iSolvRadType.getKey(), iSolvRadType); // logger.info(" Adding iSolvRadType to map: " + iSolvRadType.getKey() + "/" + iSolvRadType); } for (RelativeSolvationType rsType : patch.relativeSolvationTypes.values()) { relativeSolvationTypes.put(rsType.getKey(), rsType); } // Is this a modified residue patch? String modres = patch.getString(ForceFieldString.MODRES, "false"); if (!modres.equalsIgnoreCase("false")) { logger.info(" Adding modified residue patch."); modifiedResidue(modres); } } private void modifiedResidue(String modres) { String tokens[] = modres.trim().split(" +"); String modResname = tokens[0].toUpperCase(); String stdName = tokens[1].toUpperCase(); HashMap<String, AtomType> patchAtomTypes = getAtomTypes(modResname); HashMap<String, AtomType> stdAtomTypes = getAtomTypes(stdName); HashMap<String, AtomType> patchTypes = new HashMap<>(); int len = tokens.length; for (int i = 2; i < len; i++) { String atomName = tokens[i].toUpperCase(); if (!patchTypes.containsKey(atomName) && patchAtomTypes.containsKey(atomName)) { AtomType type = patchAtomTypes.get(atomName); patchTypes.put(atomName, type); } } HashMap<AtomType, AtomType> typeMap = new HashMap<>(); for (String atomName : stdAtomTypes.keySet()) { boolean found = false; for (int i = 2; i < len; i++) { if (atomName.equalsIgnoreCase(tokens[i])) { found = true; } } if (!found) { AtomType stdType = stdAtomTypes.get(atomName); // Edit new BioType records to point to an existing force field type. AtomType patchType = updateBioType(modResname, atomName, stdType.type); if (patchType != null) { typeMap.put(patchType, stdType); logger.info(" " + patchType.toString() + " -> " + stdType.toString()); } } } patchClassesAndTypes(typeMap, patchTypes); } /** * Enums are uppercase with underscores, but property files use lower case * with dashes. * * @param s an input Enum string * @return the normalized keyword */ public static String toPropertyForm(String s) { if (s == null) { return null; } return s.toLowerCase().replace("_", "-"); } /** * Enums are uppercase with underscores, but property files use lower case * with dashes. * * @param key an input keyword * @return the keyword in Enum form. */ public static String toEnumForm(String key) { if (key == null) { return null; } return key.toUpperCase().replace("-", "_"); } public CompositeConfiguration getProperties() { return properties; } /** * <p> * getDouble</p> * * @param forceFieldDouble a * {@link ffx.potential.parameters.ForceField.ForceFieldDouble} object. * @return a double. * @throws java.lang.Exception if any. */ public double getDouble(ForceFieldDouble forceFieldDouble) throws Exception { if (forceFieldDouble == null) { throw new Exception("NULL keyword"); } String key = toPropertyForm(forceFieldDouble.toString()); if (!properties.containsKey(key)) { throw new Exception("Undefined keyword: " + key); } return properties.getDouble(key); } /** * <p> * getDouble</p> * * @param forceFieldDouble a * {@link ffx.potential.parameters.ForceField.ForceFieldDouble} object. * @param defaultValue a double. * @return a double. */ public double getDouble(ForceFieldDouble forceFieldDouble, double defaultValue) { try { return getDouble(forceFieldDouble); } catch (Exception e) { return defaultValue; } } /** * <p> * getInteger</p> * * @param forceFieldInteger a * {@link ffx.potential.parameters.ForceField.ForceFieldInteger} object. * @return a int. * @throws java.lang.Exception if any. */ public int getInteger(ForceFieldInteger forceFieldInteger) throws Exception { if (forceFieldInteger == null) { throw new Exception("NULL keyword"); } String key = toPropertyForm(forceFieldInteger.toString()); if (!properties.containsKey(key)) { throw new Exception("Undefined keyword: " + key); } return properties.getInt(key); } /** * <p> * getInteger</p> * * @param forceFieldInteger a * {@link ffx.potential.parameters.ForceField.ForceFieldInteger} object. * @param defaultValue a int. * @return a int. */ public int getInteger(ForceFieldInteger forceFieldInteger, int defaultValue) { try { return getInteger(forceFieldInteger); } catch (Exception e) { return defaultValue; } } /** * <p> * getString</p> * * @param forceFieldString a * {@link ffx.potential.parameters.ForceField.ForceFieldString} object. * @return a {@link java.lang.String} object. * @throws java.lang.Exception if any. */ public String getString(ForceFieldString forceFieldString) throws Exception { if (forceFieldString == null) { throw new Exception("NULL keyword"); } String key = toPropertyForm(forceFieldString.toString()); if (!properties.containsKey(key)) { throw new Exception("Undefined keyword: " + key); } return properties.getString(key); } /** * <p> * getString</p> * * @param forceFieldString a * {@link ffx.potential.parameters.ForceField.ForceFieldString} object. * @param defaultString a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String getString(ForceFieldString forceFieldString, String defaultString) { try { return getString(forceFieldString); } catch (Exception e) { return defaultString; } } /** * <p> * getBoolean</p> * * @param forceFieldBoolean a * {@link ffx.potential.parameters.ForceField.ForceFieldBoolean} object. * @return a boolean. * @throws java.lang.Exception if any. */ public boolean getBoolean(ForceFieldBoolean forceFieldBoolean) throws Exception { if (forceFieldBoolean == null) { throw new Exception("NULL keyword"); } String key = toPropertyForm(forceFieldBoolean.toString()); if (!properties.containsKey(key)) { throw new Exception("Undefined keyword: " + key); } return properties.getBoolean(key); } /** * <p> * getBoolean</p> * * @param forceFieldBoolean a * {@link ffx.potential.parameters.ForceField.ForceFieldBoolean} object. * @param defaultBoolean a {@link java.lang.Boolean} object. * @return a boolean. */ public boolean getBoolean(ForceFieldBoolean forceFieldBoolean, Boolean defaultBoolean) { try { return getBoolean(forceFieldBoolean); } catch (Exception e) { return defaultBoolean; } } /** * Add a force field keyword that is represented by a double. * * @param forceFieldDouble ForceFieldDouble * @param value double */ public void addForceFieldDouble(ForceFieldDouble forceFieldDouble, double value) { if (forceFieldDouble == null) { return; } String key = toPropertyForm(forceFieldDouble.toString()); try { double old = getDouble(forceFieldDouble); if (old == value) { return; } properties.clearProperty(key); logger.info(String.format(" Removed %s %8.3f", key, old)); } catch (Exception e) { // Property does not exist yet. } finally { properties.addProperty(key, value); logger.info(String.format(" %s %8.3f", key, value)); } } /** * Add a force field keyword that is represented by an int. * * @param forceFieldInteger ForceFieldInteger * @param value int */ public void addForceFieldInteger(ForceFieldInteger forceFieldInteger, int value) { if (forceFieldInteger == null) { return; } String key = toPropertyForm(forceFieldInteger.toString()); try { int old = getInteger(forceFieldInteger); if (old == value) { return; } logger.info(String.format(" Clearing %s %d", key, old)); properties.clearProperty(key); } catch (Exception e) { // Property does not exist yet. } finally { logger.info(String.format(" %s %d", key, value)); properties.addProperty(key, value); } } public static boolean isForceFieldKeyword(String keyword) { keyword = keyword.toUpperCase(); try { ForceFieldBoolean forceFieldBoolean = ForceFieldBoolean.valueOf(keyword); return true; } catch (Exception e) { // Ignore. } try { ForceFieldDouble forceFieldDouble = ForceFieldDouble.valueOf(keyword); return true; } catch (Exception e) { // Ignore. } try { ForceFieldInteger forceFieldInteger = ForceFieldInteger.valueOf(keyword); return true; } catch (Exception e) { // Ignore. } try { ForceFieldString forceFieldString = ForceFieldString.valueOf(keyword); return true; } catch (Exception e) { // Ignore. } try { ForceFieldType forceFieldType = ForceFieldType.valueOf(keyword); return true; } catch (Exception e) { // Ignore. } return false; } /** * Store a force field keyword that is represented by a String. * * @param forceFieldString ForceFieldString * @param value String */ public void addForceFieldString(ForceFieldString forceFieldString, String value) { if (forceFieldString == null) { return; } String key = toPropertyForm(forceFieldString.toString()); try { String old = getString(forceFieldString); if (old.equalsIgnoreCase(value)) { return; } properties.clearProperty(key); logger.info(String.format(" Removed %s %s.", key, old)); } catch (Exception e) { // Property does not exist yet. } finally { properties.addProperty(key, value); logger.info(String.format(" %s %s", key, value)); } } /** * Store a force field keyword that is represented by a Boolean. * * @param forceFieldBoolean ForceFielBoolean * @param value Boolean */ public void addForceFieldBoolean(ForceFieldBoolean forceFieldBoolean, Boolean value) { if (forceFieldBoolean == null) { return; } String key = toPropertyForm(forceFieldBoolean.toString()); try { boolean old = getBoolean(forceFieldBoolean); if (old == value) { return; } properties.clearProperty(key); logger.info(String.format(" Cleared %s %s", key, Boolean.toString(old))); } catch (Exception e) { // Property does not exist yet. } finally { properties.addProperty(key, value); logger.info(String.format(" %s %s", key, Boolean.toString(value))); } } /** * Add an instance of a force field type. Force Field types are more * complicated than simple Strings or doubles, in that they have multiple * fields and may occur multiple times. * * @param type BaseType */ @SuppressWarnings("unchecked") public void addForceFieldType(BaseType type) { if (type == null) { logger.info(" Null force field type ignored."); return; } Map treeMap = forceFieldTypes.get(type.forceFieldType); if (treeMap == null) { logger.log(Level.INFO, " Unrecognized force field type ignored {0}", type.forceFieldType); type.print(); return; } if (treeMap.containsKey(type.key)) { if (treeMap.get(type.key).toString().equalsIgnoreCase(type.toString())) { // Ignore this type if its identical to an existing type. return; } logger.log(Level.WARNING, " A force field entry of type {0} already exists with the key: {1}\n The (discarded) old entry: {2}\n The new entry : {3}", new Object[] { type.forceFieldType, type.key, treeMap.get(type.key).toString(), type.toString() }); } Class baseTypeClass = type.getClass(); treeMap.put(type.key, baseTypeClass.cast(type)); } /** * <p> * getAngleType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.AngleType} object. */ public AngleType getAngleType(String key) { return angleTypes.get(key); } /** * <p> * getAtomType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.AtomType} object. */ public AtomType getAtomType(String key) { return atomTypes.get(key); } /** * <p> * getAtomType</p> * * @param moleculeName a {@link java.lang.String} object. * @param atomName a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.AtomType} object. */ public AtomType getAtomType(String moleculeName, String atomName) { for (BioType bioType : bioTypes.values()) { if (bioType.moleculeName.equalsIgnoreCase(moleculeName) && bioType.atomName.equalsIgnoreCase(atomName)) { String key = Integer.toString(bioType.atomType); return atomTypes.get(key); } } return null; } public BioType getBioType(String moleculeName, String atomName) { for (BioType bioType : bioTypes.values()) { if (bioType.moleculeName.equalsIgnoreCase(moleculeName) && bioType.atomName.equalsIgnoreCase(atomName)) { return bioType; } } return null; } /** * All atoms whose atomName begins with name in the passed molecule will be * updated to the new type. The case where an atom such as CD is should map * to both CD1 and CD2. * * @param molecule * @param atom * @param newType * @return */ public AtomType updateBioType(String molecule, String atom, int newType) { int type = 0; for (BioType bioType : bioTypes.values()) { if (bioType.moleculeName.equalsIgnoreCase(molecule)) { if (atom.length() <= bioType.atomName.length()) { if (bioType.atomName.toUpperCase().startsWith(atom.toUpperCase())) { type = bioType.atomType; bioType.atomType = newType; } } } } return getAtomType(Integer.toString(type)); } public Map<String, BioType> getBioTypeMap() { return bioTypes; } /** * <p> * Getter for the field <code>atomTypes</code>.</p> * * @param moleculeName a {@link java.lang.String} object. * @return a {@link java.util.HashMap} object. */ public HashMap<String, AtomType> getAtomTypes(String moleculeName) { HashMap<String, AtomType> types = new HashMap<>(); for (BioType bioType : bioTypes.values()) { if (bioType.moleculeName.equalsIgnoreCase(moleculeName)) { String key = Integer.toString(bioType.atomType); AtomType type = atomTypes.get(key); types.put(bioType.atomName.toUpperCase(), type); } } return types; } public HashMap<String, RelativeSolvationType> getRelativeSolvationTypes() { HashMap<String, RelativeSolvationType> types = new HashMap<>(); for (String key : relativeSolvationTypes.keySet()) { types.put(key, relativeSolvationTypes.get(key)); } return types; } /** * <p> * getBonds</p> * * @param moleculeName a {@link java.lang.String} object. * @param atomName a {@link java.lang.String} object. * @return an array of {@link java.lang.String} objects. */ public String[] getBonds(String moleculeName, String atomName) { for (BioType bioType : bioTypes.values()) { if (bioType.moleculeName.equalsIgnoreCase(moleculeName) && bioType.atomName.equalsIgnoreCase(atomName)) { return bioType.bonds; } } return null; } /** * <p> * getBondType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.BondType} object. */ public BondType getBondType(String key) { return bondTypes.get(key); } /** * <p> * getBioType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.BioType} object. */ public BioType getBioType(String key) { return bioTypes.get(key); } /** * <p> * getMultipoleType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.MultipoleType} object. */ public MultipoleType getMultipoleType(String key) { return multipoleTypes.get(key); } /** * <p> * getOutOfPlaneBendType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.OutOfPlaneBendType} object. */ public OutOfPlaneBendType getOutOfPlaneBendType(String key) { return outOfPlaneBendTypes.get(key); } /** * <p> * getPolarizeType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.PolarizeType} object. */ public PolarizeType getPolarizeType(String key) { return polarizeTypes.get(key); } /** * <p> * getStretchBendType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.StretchBendType} object. */ public StretchBendType getStretchBendType(String key) { return stretchBendTypes.get(key); } /** * <p> * getPiTorsionType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.PiTorsionType} object. */ public PiTorsionType getPiTorsionType(String key) { return piTorsionTypes.get(key); } /** * <p> * getTorsionType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.TorsionType} object. */ public TorsionType getTorsionType(String key) { return torsionTypes.get(key); } /** * <p> * getImproperType</p> * * @return a {@link ffx.potential.parameters.TorsionType} object. */ public Collection<ImproperTorsionType> getImproperTypes() { return imptorsTypes.values(); } /** * <p> * getImproperType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.TorsionType} object. */ public ImproperTorsionType getImproperType(String key) { return imptorsTypes.get(key); } /** * <p> * getTorsionTorsionType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.TorsionTorsionType} object. */ public TorsionTorsionType getTorsionTorsionType(String key) { return torsionTorsionTypes.get(key); } /** * <p> * getUreyBradleyType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.UreyBradleyType} object. */ public UreyBradleyType getUreyBradleyType(String key) { return ureyBradleyTypes.get(key); } /** * <p> * getVDWType</p> * * @param key a {@link java.lang.String} object. * @return a {@link ffx.potential.parameters.VDWType} object. */ public VDWType getVDWType(String key) { return vanderWaalsTypes.get(key); } /** * <p> * getVDWTypes</p> * * @return a {@link java.util.Map} object. */ public Map<String, VDWType> getVDWTypes() { return vanderWaalsTypes; } public ISolvRadType getISolvRadType(String key) { return iSolvRadTypes.get(key); } public Map<String, ISolvRadType> getISolvRadTypes() { return iSolvRadTypes; } /** * <p> * getForceFieldTypeCount</p> * * @param type a {@link ffx.potential.parameters.ForceField.ForceFieldType} * object. * @return a int. */ @SuppressWarnings("unchecked") public int getForceFieldTypeCount(ForceFieldType type) { TreeMap<String, BaseType> treeMap = (TreeMap<String, BaseType>) forceFieldTypes.get(type); if (treeMap == null) { logger.log(Level.WARNING, "Unrecognized Force Field Type: {0}", type); return 0; } return treeMap.size(); } /** * Check for self-consistent polarization groups. */ public void checkPolarizationTypes() { boolean change = false; for (String key : polarizeTypes.keySet()) { PolarizeType polarizeType = polarizeTypes.get(key); int orig = Integer.parseInt(key); int types[] = polarizeType.polarizationGroup; if (types == null) { continue; } for (int i = 0; i < types.length; i++) { int type = types[i]; String key2 = Integer.toString(type); PolarizeType polarizeType2 = polarizeTypes.get(key2); if (polarizeType2 == null) { logger.severe(format("Polarize type %s references nonexistant polarize type %s.", key, key2)); continue; } int types2[] = polarizeType2.polarizationGroup; if (types2 == null) { polarizeType2.add(orig); change = true; continue; } boolean found = false; for (int j = 0; j < types2.length; j++) { int type2 = types2[j]; for (int k = 0; k < types.length; k++) { if (type2 == types[k]) { found = true; } } if (!found) { polarizeType.add(type2); change = true; } } } } if (change) { checkPolarizationTypes(); } } /** * <p> * log</p> */ public void log() { for (ForceFieldType s : forceFieldTypes.keySet()) { log(s.toString()); } } /** * Prints any force field keyword to Standard.out. * * @param key String */ public void log(String key) { ForceFieldType type = ForceFieldType.valueOf(key); logger.info(toString(type)); } /** * <p> * print</p> */ public void print() { for (ForceFieldType s : forceFieldTypes.keySet()) { print(s.toString()); } } /** * <p> * print</p> * * @param key a {@link java.lang.String} object. */ public void print(String key) { ForceFieldType type = ForceFieldType.valueOf(key); System.out.println(toString(type)); } public void printMultipoleTypes() { StringBuilder sb = new StringBuilder(); sb.append(String.format(" Loaded multipole types: \n")); for (String key : multipoleTypes.keySet()) { sb.append(String.format(" m %s : \n", key, multipoleTypes.get(key).key)); } logger.info(sb.toString()); } public void printAtomTypes() { StringBuilder sb = new StringBuilder(); sb.append(String.format(" Loaded atom types: \n")); for (String key : atomTypes.keySet()) { sb.append(String.format(" a %s : \n", key, atomTypes.get(key).key)); } logger.info(sb.toString()); } /** * Return a String for any Force Field keyword. * * @param type ForceFieldType * @return String */ public String toString(ForceFieldType type) { StringBuilder sb = new StringBuilder("\n"); Map t = forceFieldTypes.get(type); if (t.size() > 0) { Set set = t.keySet(); Iterator i = set.iterator(); while (i.hasNext()) { sb.append(t.get(i.next())).append("\n"); } return sb.toString(); } return ""; } @Override public String toString() { String forceFieldName; try { forceFieldName = getString(ForceFieldString.FORCEFIELD); } catch (Exception ex) { forceFieldName = "Unknown"; } return forceFieldName; } /** * <p> * toString</p> * * @param key a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String toString(String key) { if (key == null) { return null; } key = toPropertyForm(key); if (properties.containsKey(key)) { List l = properties.getList(key); return key + " " + Arrays.toString(l.toArray()); } else { return key + " is not defined."; } } /** * Patches that add new atom classes/types that bond to existing atom * classes/types require "hybrid" force field types that include a mixture * of new and existing types. * * @param typeMap A look-up from new types to existing types. */ public void patchClassesAndTypes(HashMap<AtomType, AtomType> typeMap, HashMap<String, AtomType> patchTypes) { for (BondType bondType : bondTypes.values().toArray(new BondType[0])) { BondType newType = bondType.patchClasses(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } for (AngleType angleType : angleTypes.values().toArray(new AngleType[0])) { AngleType newType = angleType.patchClasses(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } for (OutOfPlaneBendType outOfPlaneBendType : outOfPlaneBendTypes.values() .toArray(new OutOfPlaneBendType[0])) { OutOfPlaneBendType newType = outOfPlaneBendType.patchClasses(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } for (PiTorsionType piTorsionType : piTorsionTypes.values().toArray(new PiTorsionType[0])) { PiTorsionType newType = piTorsionType.patchClasses(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } for (StretchBendType stretchBendType : stretchBendTypes.values().toArray(new StretchBendType[0])) { StretchBendType newType = stretchBendType.patchClasses(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } /* for (TorsionTorsionType torsionTorsionType : * torsionTorsionTypes.values().toArray(new TorsionTorsionType[0])) { * String currentKey = torsionTorsionType.key; * torsionTorsionType.patchClasses(typeMap); if * (!torsionTorsionType.key.equals(currentKey)) { * torsionTorsionTypes.remove(currentKey); * addForceFieldType(torsionTorsionType); } } */ for (TorsionType torsionType : torsionTypes.values().toArray(new TorsionType[0])) { TorsionType newType = torsionType.patchClasses(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } /* for (ImproperTorsionType improperType : imptorsTypes.values().toArray(new ImproperTorsionType[0])) { String currentKey = improperType.key; improperType.patchClasses(typeMap); if (!improperType.key.equals(currentKey)) { torsionTypes.remove(currentKey); addForceFieldType(improperType); } } for (UreyBradleyType ureyBradleyType : ureyBradleyTypes.values().toArray(new UreyBradleyType[0])) { String currentKey = ureyBradleyType.key; ureyBradleyType.patchClasses(typeMap); if (!ureyBradleyType.key.equals(currentKey)) { ureyBradleyTypes.remove(currentKey); addForceFieldType(ureyBradleyType); } } */ for (MultipoleType multipoleType : multipoleTypes.values().toArray(new MultipoleType[0])) { MultipoleType newType = multipoleType.patchTypes(typeMap); if (newType != null) { logger.info(" " + newType.toString()); addForceFieldType(newType); } } try { for (AtomType atomType : patchTypes.values()) { PolarizeType polarizeType = getPolarizeType(atomType.key); if (polarizeType != null && polarizeType.patchTypes(typeMap)) { logger.info(" " + polarizeType.toString()); } } } catch (Exception e) { // Inefficient hack. Should actually check if polarizeTypes are necessary. } } /** * Available force fields. */ public enum ForceFieldName { AMBER99SB, AMBER99SB_TIP3F, AMBER99SB_TIP3AMOEBA, AMOEBA_WATER, AMOEBA_WATER_2003, AMOEBA_WATER_2014, AMOEBA_2004, AMOEBA_PROTEIN_2004, AMOEBA_PROTEIN_2004_U1, AMOEBA_2009, AMOEBA_BIO_2009, AMOEBA_BIO_2009_ORIG, AMOEBA_PROTEIN_2013, IAMOEBA_WATER, OPLS_AAL } public enum ForceFieldString { CAVMODEL, ARRAY_REDUCTION, EPSILONRULE, FFT_METHOD, FORCEFIELD, NCSGROUP, MODRES, POLARIZATION, RADIUSRULE, RADIUSSIZE, RADIUSTYPE, REAL_SCHEDULE, RECIP_SCHEDULE, RELATIVE_SOLVATION, SCF_PREDICTOR, SCF_ALGORITHM, SPACEGROUP, VDWINDEX, VDWTYPE, VDW_SCHEDULE, GK_RADIIOVERRIDE, GK_RADIIBYNUMBER } public enum ForceFieldDouble { A_AXIS, B_AXIS, C_AXIS, ALPHA, BETA, GAMMA, POLAR_DAMP, POLAR_SOR, POLAR_EPS, POLAR_EPS_PRECISE, EWALD_CUTOFF, EWALD_ALPHA, EWALD_PRECISION, PME_MESH_DENSITY, VDW_CUTOFF, MPOLE_11_SCALE, MPOLE_12_SCALE, MPOLE_13_SCALE, MPOLE_14_SCALE, MPOLE_15_SCALE, POLAR_12_SCALE, POLAR_13_SCALE, DIRECT_11_SCALE, RIGID_SCALE, VDW_LAMBDA_EXPONENT, VDW_LAMBDA_ALPHA, PERMANENT_LAMBDA_EXPONENT, PERMANENT_LAMBDA_ALPHA, POLARIZATION_LAMBDA_START, POLARIZATION_LAMBDA_END, POLARIZATION_LAMBDA_EXPONENT, POLARIZATION_LAMEDH_START, POLARIZATION_LAMEDH_END, DUAL_TOPOLOGY_LAMBDA_EXPONENT, CG_PRECONDITIONER_CUTOFF, CG_PRECONDITIONER_EWALD, CG_PRECONDITIONER_SOR, RESTRAINT_K, PROBE_RADIUS, BORNAI, SURFACE_TENSION, TORSIONUNIT, IMPTORUNIT, VDW_12_SCALE, VDW_13_SCALE, VDW_14_SCALE, VDW_15_SCALE, GK_EPSILON, GK_BONDIOVERRIDE, GK_OVERLAPSCALE } public enum ForceFieldInteger { FF_THREADS, PME_ORDER, PME_REAL_THREADS, PME_GRID_X, PME_GRID_Y, PME_GRID_Z, LIGAND_START, LIGAND_STOP, SCF_CYCLES, SCF_PREDICTOR_ORDER } public enum ForceFieldBoolean { BONDTERM, ANGLETERM, RESTRAINTERM, COMRESTRAINTERM, STRBNDTERM, UREYTERM, OPBENDTERM, TORSIONTERM, PITORSTERM, TORTORTERM, VDWLRTERM, VDWTERM, IMPROPERTERM, MPOLETERM, POLARIZETERM, GKTERM, SCFCACHE, APERIODIC, RIGID_HYDROGENS, LAMBDATERM, NCSTERM, USE_CHARGES, USE_DIPOLES, USE_QUADRUPOLES, ROTATE_MULTIPOLES, LIGAND_VAPOR_ELEC, NO_LIGAND_CONDENSED_SCF, USE_SCF_PRECONDITIONER, INTERMOLECULAR_SOFTCORE, INTRAMOLECULAR_SOFTCORE, LAMBDA_VALENCE_RESTRAINTS, LAMBDA_TORSIONS, RECIPTERM, BORN_USE_ALL, CHECK_ALL_NODE_CHARGES, GK_USEFITRADII, GK_VERBOSERADII, PRINT_ON_FAILURE } public enum ForceFieldType { KEYWORD, ANGLE, ATOM, BIOTYPE, BOND, CHARGE, ISOLVRAD, IMPTORS, MULTIPOLE, OPBEND, PITORS, POLARIZE, STRBND, TORSION, TORTORS, UREYBRAD, VDW, RELATIVESOLV } /** * 1) Read in protein with HETATM side-chain. 2) Read in side-chain analog * patch and add to ForceField. 3) Define HETATM precedence via 1) existing * side-chain or 2) patch. 4) Create needed parameters via averaging. A) * Create a map between patch atoms and forcefield atoms. B) Loop over all * patch terms and create averaged ones if there is mixed precedence. */ }