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-2021.
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.parameters;
39  
40  import static ffx.potential.parameters.ForceField.ForceFieldType.STRTORS;
41  import static ffx.utilities.KeywordGroup.EnergyUnitConversion;
42  import static ffx.utilities.KeywordGroup.PotentialFunctionParameter;
43  import static java.lang.Double.parseDouble;
44  import static java.lang.Integer.parseInt;
45  import static java.lang.String.format;
46  import static java.util.Arrays.copyOf;
47  
48  import ffx.utilities.FFXKeyword;
49  import java.util.Arrays;
50  import java.util.Comparator;
51  import java.util.HashMap;
52  import java.util.logging.Level;
53  import java.util.logging.Logger;
54  
55  /**
56   * The StretchTorsionType class defines one stretch-torsion energy type.
57   *
58   * @author Michael J. Schnieders
59   * @since 1.0
60   */
61  @FFXKeyword(name = "strtors", clazz = String.class, keywordGroup = PotentialFunctionParameter,
62      description = "[2 integers and 1 real] "
63          + "Provides the values for a single stretch-torsion cross term potential parameter. "
64          + "The two integer modifiers give the atom class numbers for the atoms involved in the central bond of the torsional angles to be parameterized. "
65          + "The real modifier gives the value of the stretch-torsion force constant for all torsional angles with the defined atom classes for the central bond. "
66          + "The default units for the stretch-torsion force constant can be controlled via the strtorunit keyword.")
67  public final class StretchTorsionType extends BaseType implements Comparator<String> {
68  
69    public static final double DEFAULT_STRTOR_UNIT = 1.0;
70  
71    /** Unit conversion. */
72    @FFXKeyword(name = "strtorunit", keywordGroup = EnergyUnitConversion, defaultValue = "1.0",
73        description =
74            "Sets the scale factor needed to convert the energy value computed by the bond stretching-torsional angle cross term potential into units of kcal/mole. "
75                + "The correct value is force field dependent and typically provided in the header of the master force field parameter file.")
76    public double strTorUnit = DEFAULT_STRTOR_UNIT;
77  
78    /** A Logger for the StretchTorsionType class. */
79    private static final Logger logger = Logger.getLogger(StretchTorsionType.class.getName());
80    /** Atom classes for this stretch-torsion type. */
81    public final int[] atomClasses;
82    /** Force constants. */
83    public final double[] forceConstants;
84  
85    /**
86     * StretchTorsionType Constructor.
87     *
88     * @param atomClasses Atom classes.
89     * @param forceConstants Force constant.
90     */
91    public StretchTorsionType(int[] atomClasses, double[] forceConstants) {
92      // Pass the key from sorted classes to the super constructor.
93      super(STRTORS, sortKey(atomClasses));
94      this.atomClasses = atomClasses;
95      this.forceConstants = forceConstants;
96    }
97  
98    /**
99     * average.
100    *
101    * @param stretchTorsionType1 a {@link ffx.potential.parameters.StretchTorsionType} object.
102    * @param stretchTorsionType2 a {@link ffx.potential.parameters.StretchTorsionType} object.
103    * @param atomClasses an array of {@link int} objects.
104    * @return a {@link ffx.potential.parameters.StretchTorsionType} object.
105    */
106   public static StretchTorsionType average(
107       StretchTorsionType stretchTorsionType1,
108       StretchTorsionType stretchTorsionType2,
109       int[] atomClasses) {
110     if (stretchTorsionType1 == null || stretchTorsionType2 == null || atomClasses == null) {
111       return null;
112     }
113     int len = stretchTorsionType1.forceConstants.length;
114     if (len != stretchTorsionType2.forceConstants.length) {
115       return null;
116     }
117     double[] forceConstants = new double[len];
118     for (int i = 0; i < len; i++) {
119       forceConstants[i] =
120           (stretchTorsionType1.forceConstants[i] + stretchTorsionType2.forceConstants[i]) / 2.0;
121     }
122     return new StretchTorsionType(atomClasses, forceConstants);
123   }
124 
125   /**
126    * Construct an StretchTorsionType from an input string.
127    *
128    * @param input The overall input String.
129    * @param tokens The input String tokenized.
130    * @return an StretchTorsionType instance.
131    */
132   public static StretchTorsionType parse(String input, String[] tokens) {
133     if (tokens.length < 13) {
134       logger.log(Level.WARNING, "Invalid STRTORS type:\n{0}", input);
135     } else {
136       try {
137         int[] atomClasses = new int[4];
138         atomClasses[0] = parseInt(tokens[1]);
139         atomClasses[1] = parseInt(tokens[2]);
140         atomClasses[2] = parseInt(tokens[3]);
141         atomClasses[3] = parseInt(tokens[4]);
142         double[] constants = new double[9];
143         constants[0] = parseDouble(tokens[5]);
144         constants[1] = parseDouble(tokens[6]);
145         constants[2] = parseDouble(tokens[7]);
146         constants[3] = parseDouble(tokens[8]);
147         constants[4] = parseDouble(tokens[9]);
148         constants[5] = parseDouble(tokens[10]);
149         constants[6] = parseDouble(tokens[11]);
150         constants[7] = parseDouble(tokens[12]);
151         constants[8] = parseDouble(tokens[13]);
152         return new StretchTorsionType(atomClasses, constants);
153       } catch (NumberFormatException e) {
154         String message = "Exception parsing STRTORS type:\n" + input + "\n";
155         logger.log(Level.SEVERE, message, e);
156       }
157     }
158     return null;
159   }
160 
161   /**
162    * This method sorts the atom classes for the torsion.
163    *
164    * @param c atomClasses
165    * @return lookup key
166    * @since 1.0
167    */
168   public static String sortKey(int[] c) {
169     return c[0] + " " + c[1] + " " + c[2] + " " + c[3];
170   }
171 
172   /**
173    * {@inheritDoc}
174    *
175    * @since 1.0
176    */
177   @Override
178   public int compare(String s1, String s2) {
179     String[] keys1 = s1.split(" ");
180     String[] keys2 = s2.split(" ");
181     int[] c1 = new int[4];
182     int[] c2 = new int[4];
183 
184     for (int i = 0; i < 4; i++) {
185       c1[i] = parseInt(keys1[i]);
186       c2[i] = parseInt(keys2[i]);
187     }
188 
189     if (c1[1] < c2[1]) {
190       return -1;
191     } else if (c1[1] > c2[1]) {
192       return 1;
193     } else if (c1[2] < c2[2]) {
194       return -1;
195     } else if (c1[2] > c2[2]) {
196       return 1;
197     } else if (c1[0] < c2[0]) {
198       return -1;
199     } else if (c1[0] > c2[0]) {
200       return 1;
201     } else if (c1[3] < c2[3]) {
202       return -1;
203     } else if (c1[3] > c2[3]) {
204       return 1;
205     }
206 
207     return 0;
208   }
209 
210   /** {@inheritDoc} */
211   @Override
212   public boolean equals(Object o) {
213     if (this == o) {
214       return true;
215     }
216     if (o == null || getClass() != o.getClass()) {
217       return false;
218     }
219     StretchTorsionType stretchTorsionType = (StretchTorsionType) o;
220     return Arrays.equals(atomClasses, stretchTorsionType.atomClasses);
221   }
222 
223   /** {@inheritDoc} */
224   @Override
225   public int hashCode() {
226     return Arrays.hashCode(atomClasses);
227   }
228 
229   /**
230    * incrementClasses
231    *
232    * @param increment a int.
233    */
234   public void incrementClasses(int increment) {
235     for (int i = 0; i < atomClasses.length; i++) {
236       atomClasses[i] += increment;
237     }
238     setKey(sortKey(atomClasses));
239   }
240 
241   /**
242    * Remap new atom classes to known internal ones.
243    *
244    * @param typeMap a lookup between new atom types and known atom types.
245    * @return a {@link ffx.potential.parameters.StretchTorsionType} object.
246    */
247   public StretchTorsionType patchClasses(HashMap<AtomType, AtomType> typeMap) {
248     int count = 0;
249     int len = atomClasses.length;
250 
251     // Check if this Type contain 1 or 2 mapped atom classes.
252     for (AtomType newType : typeMap.keySet()) {
253       for (int atomClass : atomClasses) {
254         if (atomClass == newType.atomClass) {
255           count++;
256         }
257       }
258     }
259 
260     // If found, create a new StretchTorsionType that bridges to known classes.
261     if (count == 1 || count == 2) {
262       int[] newClasses = copyOf(atomClasses, len);
263       for (AtomType newType : typeMap.keySet()) {
264         for (int i = 0; i < len; i++) {
265           if (atomClasses[i] == newType.atomClass) {
266             AtomType knownType = typeMap.get(newType);
267             newClasses[i] = knownType.atomClass;
268           }
269         }
270       }
271       return new StretchTorsionType(newClasses, forceConstants);
272     }
273     return null;
274   }
275 
276   /**
277    * {@inheritDoc}
278    *
279    * <p>Nicely formatted Stretch-Torsion string.
280    */
281   @Override
282   public String toString() {
283     return format(
284         "strtors  %5d  %5d  %5d  %5d  %6.3f  %6.3f  %6.3f  %6.3f  %6.3f  %6.3f  %6.3f  %6.3f  %6.3f",
285         atomClasses[0],
286         atomClasses[1],
287         atomClasses[2],
288         atomClasses[3],
289         forceConstants[0],
290         forceConstants[1],
291         forceConstants[2],
292         forceConstants[3],
293         forceConstants[4],
294         forceConstants[5],
295         forceConstants[6],
296         forceConstants[7],
297         forceConstants[8]);
298   }
299 }