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.UREYBRAD;
41  import static ffx.utilities.KeywordGroup.EnergyUnitConversion;
42  import static ffx.utilities.KeywordGroup.LocalGeometryFunctionalForm;
43  import static ffx.utilities.KeywordGroup.PotentialFunctionParameter;
44  import static java.lang.Double.parseDouble;
45  import static java.lang.Integer.parseInt;
46  import static java.lang.String.format;
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 UreyBradleyType class defines one harmonic UreyBradley cross term.
57   *
58   * @author Michael J. Schnieders
59   * @since 1.0
60   */
61  @FFXKeyword(name = "ureybrad", clazz = String.class, keywordGroup = PotentialFunctionParameter,
62      description = "[3 integers and 2 reals] "
63          + "Provides the values for a single Urey-Bradley cross term potential parameter. "
64          + "The integer modifiers give the atom class numbers for the three kinds of atoms involved in the angle for which a Urey-Bradley term is to be defined. "
65          + "The real number modifiers give the force constant value for the term and the target value for the 1-3 distance in Angstroms. "
66          + "The default units for the force constant are kcal/mole/Ang^2, but this can be controlled via the ureyunit keyword")
67  public final class UreyBradleyType extends BaseType implements Comparator<String> {
68  
69    /** Default conversion Urey-Bradley stretch energy to kcal/mole. */
70    public static final double DEFAULT_UREY_UNIT = 1.0;
71    /** Default cubic coefficient in Urey-Bradley stretch potential. */
72    public static final double DEFAULT_UREY_CUBIC = 0.0;
73    /** Default quartic coefficient in Urey-Bradley stretch potential. */
74    public static final double DEFAULT_UREY_QUARTIC = 0.0;
75  
76    /** Convert Urey-Bradley stretch energy to kcal/mole. */
77    @FFXKeyword(name = "ureyunit", keywordGroup = EnergyUnitConversion, defaultValue = "1.0",
78        description =
79            "Sets the scale factor needed to convert the energy value computed by the Urey-Bradley potential into units of kcal/mole. "
80                + "The correct value is force field dependent and typically provided in the header of the master force field parameter file.")
81    public double ureyUnit = DEFAULT_UREY_UNIT;
82  
83    /** Cubic coefficient in bond stretch potential. */
84    @FFXKeyword(name = "urey-cubic", keywordGroup = LocalGeometryFunctionalForm, defaultValue = "0.0",
85        description =
86            "Sets the value of the cubic term in the Taylor series expansion form of the Urey-Bradley potential energy. "
87                + "The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient. "
88                + "The default value in the absence of the urey-cubic keyword is zero; i.e., the cubic Urey-Bradley term is omitted.")
89    public double cubic = DEFAULT_UREY_CUBIC;
90  
91    /** Quartic coefficient in bond stretch potential. */
92    @FFXKeyword(name = "urey-quartic", keywordGroup = LocalGeometryFunctionalForm, defaultValue = "0.0",
93        description =
94            "Sets the value of the quartic term in the Taylor series expansion form of the Urey-Bradley potential energy. "
95                + "The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient. "
96                + "The default value in the absence of the urey-quartic keyword is zero; i.e., the quartic Urey-Bradley term is omitted.")
97    public double quartic = DEFAULT_UREY_QUARTIC;
98  
99    /** A Logger for the UreyBradleyType class. */
100   private static final Logger logger = Logger.getLogger(UreyBradleyType.class.getName());
101   /** Atom classes that form this Urey-Bradley cross term. */
102   public final int[] atomClasses;
103   /** Force constant (Kcal/mole/angstroms^2). */
104   public final double forceConstant;
105   /** Equilibrium 1-3 separation (Angstroms). */
106   public final double distance;
107 
108   /**
109    * UreyBradleyType constructor.
110    *
111    * @param atomClasses Atom classes.
112    * @param forceConstant Force constant (Kcal/mole/angstroms^2).
113    * @param distance Equilibrium 1-3 separation (Angstroms).
114    */
115   public UreyBradleyType(int[] atomClasses, double forceConstant, double distance) {
116     super(UREYBRAD, sortKey(atomClasses));
117     this.atomClasses = atomClasses;
118     this.forceConstant = forceConstant;
119     this.distance = distance;
120   }
121 
122   /**
123    * average.
124    *
125    * @param ureyBradleyType1 a {@link ffx.potential.parameters.UreyBradleyType} object.
126    * @param ureyBradleyType2 a {@link ffx.potential.parameters.UreyBradleyType} object.
127    * @param atomClasses an array of {@link int} objects.
128    * @return a {@link ffx.potential.parameters.UreyBradleyType} object.
129    */
130   public static UreyBradleyType average(
131       UreyBradleyType ureyBradleyType1, UreyBradleyType ureyBradleyType2, int[] atomClasses) {
132     if (ureyBradleyType1 == null || ureyBradleyType2 == null || atomClasses == null) {
133       return null;
134     }
135 
136     double forceConstant = (ureyBradleyType1.forceConstant + ureyBradleyType2.forceConstant) / 2.0;
137     double distance = (ureyBradleyType1.distance + ureyBradleyType2.distance) / 2.0;
138 
139     return new UreyBradleyType(atomClasses, forceConstant, distance);
140   }
141 
142   /**
143    * Construct a UreyBradleyType from an input string.
144    *
145    * @param input The overall input String.
146    * @param tokens The input String tokenized.
147    * @return a UreyBradleyType instance.
148    */
149   public static UreyBradleyType parse(String input, String[] tokens) {
150     if (tokens.length < 5) {
151       logger.log(Level.WARNING, "Invalid UREYBRAD type:\n{0}", input);
152     } else {
153       try {
154         int[] atomClasses = new int[3];
155         atomClasses[0] = parseInt(tokens[1]);
156         atomClasses[1] = parseInt(tokens[2]);
157         atomClasses[2] = parseInt(tokens[3]);
158         double forceConstant = parseDouble(tokens[4]);
159         double distance = parseDouble(tokens[5]);
160         return new UreyBradleyType(atomClasses, forceConstant, distance);
161       } catch (NumberFormatException e) {
162         String message = "Exception parsing UREYBRAD type:\n" + input + "\n";
163         logger.log(Level.SEVERE, message, e);
164       }
165     }
166     return null;
167   }
168 
169   /**
170    * This method sorts the atom classes as: min, c[1], max
171    *
172    * @param c atomClasses
173    * @return lookup key
174    */
175   public static String sortKey(int[] c) {
176     if (c == null || c.length != 3) {
177       return null;
178     }
179     if (c[0] > c[2]) {
180       int temp = c[0];
181       c[0] = c[2];
182       c[2] = temp;
183     }
184 
185     return c[0] + " " + c[1] + " " + c[2];
186   }
187 
188   /** {@inheritDoc} */
189   @Override
190   public int compare(String key1, String key2) {
191     String[] keys1 = key1.split(" ");
192     String[] keys2 = key2.split(" ");
193     int[] c1 = new int[3];
194     int[] c2 = new int[3];
195     for (int i = 0; i < 3; i++) {
196       c1[i] = parseInt(keys1[i]);
197       c2[i] = parseInt(keys2[i]);
198     }
199     if (c1[1] < c2[1]) {
200       return -1;
201     } else if (c1[1] > c2[1]) {
202       return 1;
203     } else if (c1[0] < c2[0]) {
204       return -1;
205     } else if (c1[0] > c2[0]) {
206       return 1;
207     } else if (c1[2] < c2[2]) {
208       return -1;
209     } else if (c1[2] > c2[2]) {
210       return 1;
211     }
212     return 0;
213   }
214 
215   /** {@inheritDoc} */
216   @Override
217   public boolean equals(Object o) {
218     if (this == o) {
219       return true;
220     }
221     if (o == null || getClass() != o.getClass()) {
222       return false;
223     }
224     UreyBradleyType ureyBradleyType = (UreyBradleyType) o;
225     return Arrays.equals(atomClasses, ureyBradleyType.atomClasses);
226   }
227 
228   /** {@inheritDoc} */
229   @Override
230   public int hashCode() {
231     return Arrays.hashCode(atomClasses);
232   }
233 
234   /**
235    * incrementClasses
236    *
237    * @param increment a int.
238    */
239   public void incrementClasses(int increment) {
240     for (int i = 0; i < atomClasses.length; i++) {
241       atomClasses[i] += increment;
242     }
243     setKey(sortKey(atomClasses));
244   }
245 
246   /**
247    * Remap new atom classes to known internal ones.
248    *
249    * @param typeMap a lookup between new atom types and known atom types.
250    */
251   public void patchClasses(HashMap<AtomType, AtomType> typeMap) {
252     int count = 0;
253     for (AtomType newType : typeMap.keySet()) {
254       for (int atomClass : atomClasses) {
255         if (atomClass == newType.atomClass) {
256           count++;
257         }
258       }
259     }
260     if (count > 0 && count < atomClasses.length) {
261       for (AtomType newType : typeMap.keySet()) {
262         for (int i = 0; i < atomClasses.length; i++) {
263           if (atomClasses[i] == newType.atomClass) {
264             AtomType knownType = typeMap.get(newType);
265             atomClasses[i] = knownType.atomClass;
266           }
267         }
268       }
269       setKey(sortKey(atomClasses));
270     }
271   }
272 
273   /**
274    * {@inheritDoc}
275    *
276    * <p>Nicely formatted Urey-Bradley string.
277    */
278   @Override
279   public String toString() {
280     return format(
281         "ureybrad  %5d  %5d  %5d  %6.2f  %7.4f",
282         atomClasses[0], atomClasses[1], atomClasses[2], forceConstant, distance);
283   }
284 }