1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.potential.parameters;
39
40 import ffx.utilities.FFXProperty;
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Element;
43
44 import java.util.Arrays;
45 import java.util.Comparator;
46 import java.util.HashMap;
47 import java.util.Map;
48 import java.util.logging.Level;
49 import java.util.logging.Logger;
50
51 import static ffx.potential.parameters.ForceField.ForceFieldType.UREYBRAD;
52 import static ffx.utilities.Constants.ANG_TO_NM;
53 import static ffx.utilities.Constants.KCAL_TO_KJ;
54 import static ffx.utilities.PropertyGroup.EnergyUnitConversion;
55 import static ffx.utilities.PropertyGroup.LocalGeometryFunctionalForm;
56 import static ffx.utilities.PropertyGroup.PotentialFunctionParameter;
57 import static java.lang.Double.parseDouble;
58 import static java.lang.Integer.parseInt;
59 import static java.lang.String.format;
60 import static java.lang.String.valueOf;
61
62
63
64
65
66
67
68 @FFXProperty(name = "ureybrad", clazz = String.class, propertyGroup = PotentialFunctionParameter, description = """
69 [3 integers and 2 reals]
70 Provides the values for a single Urey-Bradley cross term potential parameter.
71 The integer modifiers give the atom class numbers for the three kinds of atoms
72 involved in the angle for which a Urey-Bradley term is to be defined.
73 The real number modifiers give the force constant value for the term and the target value for the 1-3 distance in Angstroms.
74 The default units for the force constant are kcal/mole/Ang^2, but this can be controlled via the ureyunit keyword
75 """)
76 public final class UreyBradleyType extends BaseType implements Comparator<String> {
77
78
79
80
81 public static final double DEFAULT_UREY_UNIT = 1.0;
82
83
84
85 public static final double DEFAULT_UREY_CUBIC = 0.0;
86
87
88
89 public static final double DEFAULT_UREY_QUARTIC = 0.0;
90
91
92
93
94 @FFXProperty(name = "ureyunit", propertyGroup = EnergyUnitConversion, defaultValue = "1.0", description = """
95 Sets the scale factor needed to convert the energy value computed by the Urey-Bradley potential into units of kcal/mole.
96 The correct value is force field dependent and typically provided in the header of the master force field parameter file.
97 """)
98 public double ureyUnit = DEFAULT_UREY_UNIT;
99
100
101
102
103 @FFXProperty(name = "urey-cubic", propertyGroup = LocalGeometryFunctionalForm, defaultValue = "0.0", description = """
104 Sets the value of the cubic term in the Taylor series expansion form of the Urey-Bradley potential energy.
105 The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient.
106 The default value in the absence of the urey-cubic keyword is zero; i.e., the cubic Urey-Bradley term is omitted.
107 """)
108 public double cubic = DEFAULT_UREY_CUBIC;
109
110
111
112
113 @FFXProperty(name = "urey-quartic", propertyGroup = LocalGeometryFunctionalForm, defaultValue = "0.0", description = """
114 Sets the value of the quartic term in the Taylor series expansion form of the Urey-Bradley potential energy.
115 The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient.
116 The default value in the absence of the urey-quartic keyword is zero; i.e., the quartic Urey-Bradley term is omitted.
117 """)
118 public double quartic = DEFAULT_UREY_QUARTIC;
119
120
121
122
123 private static final Logger logger = Logger.getLogger(UreyBradleyType.class.getName());
124
125
126
127 public final int[] atomClasses;
128
129
130
131 public final double forceConstant;
132
133
134
135 public final double distance;
136
137
138
139
140
141
142
143
144 public UreyBradleyType(int[] atomClasses, double forceConstant, double distance) {
145 super(UREYBRAD, sortKey(atomClasses));
146 this.atomClasses = atomClasses;
147 this.forceConstant = forceConstant;
148 this.distance = distance;
149 }
150
151
152
153
154
155
156
157
158
159 public static UreyBradleyType average(UreyBradleyType ureyBradleyType1,
160 UreyBradleyType ureyBradleyType2, int[] atomClasses) {
161 if (ureyBradleyType1 == null || ureyBradleyType2 == null || atomClasses == null) {
162 return null;
163 }
164
165 double forceConstant = (ureyBradleyType1.forceConstant + ureyBradleyType2.forceConstant) / 2.0;
166 double distance = (ureyBradleyType1.distance + ureyBradleyType2.distance) / 2.0;
167
168 return new UreyBradleyType(atomClasses, forceConstant, distance);
169 }
170
171
172
173
174
175
176
177
178 public static UreyBradleyType parse(String input, String[] tokens) {
179 if (tokens.length < 5) {
180 logger.log(Level.WARNING, "Invalid UREYBRAD type:\n{0}", input);
181 } else {
182 try {
183 int[] atomClasses = new int[3];
184 atomClasses[0] = parseInt(tokens[1]);
185 atomClasses[1] = parseInt(tokens[2]);
186 atomClasses[2] = parseInt(tokens[3]);
187 double forceConstant = parseDouble(tokens[4]);
188 double distance = parseDouble(tokens[5]);
189 return new UreyBradleyType(atomClasses, forceConstant, distance);
190 } catch (NumberFormatException e) {
191 String message = "Exception parsing UREYBRAD type:\n" + input + "\n";
192 logger.log(Level.SEVERE, message, e);
193 }
194 }
195 return null;
196 }
197
198
199
200
201
202
203
204 public static String sortKey(int[] c) {
205 if (c == null || c.length != 3) {
206 return null;
207 }
208 if (c[0] > c[2]) {
209 int temp = c[0];
210 c[0] = c[2];
211 c[2] = temp;
212 }
213
214 return c[0] + " " + c[1] + " " + c[2];
215 }
216
217
218
219
220 @Override
221 public int compare(String key1, String key2) {
222 String[] keys1 = key1.split(" ");
223 String[] keys2 = key2.split(" ");
224 int[] c1 = new int[3];
225 int[] c2 = new int[3];
226 for (int i = 0; i < 3; i++) {
227 c1[i] = parseInt(keys1[i]);
228 c2[i] = parseInt(keys2[i]);
229 }
230 if (c1[1] < c2[1]) {
231 return -1;
232 } else if (c1[1] > c2[1]) {
233 return 1;
234 } else if (c1[0] < c2[0]) {
235 return -1;
236 } else if (c1[0] > c2[0]) {
237 return 1;
238 } else if (c1[2] < c2[2]) {
239 return -1;
240 } else if (c1[2] > c2[2]) {
241 return 1;
242 }
243 return 0;
244 }
245
246
247
248
249 @Override
250 public boolean equals(Object o) {
251 if (this == o) {
252 return true;
253 }
254 if (o == null || getClass() != o.getClass()) {
255 return false;
256 }
257 UreyBradleyType ureyBradleyType = (UreyBradleyType) o;
258 return Arrays.equals(atomClasses, ureyBradleyType.atomClasses);
259 }
260
261
262
263
264 @Override
265 public int hashCode() {
266 return Arrays.hashCode(atomClasses);
267 }
268
269
270
271
272
273
274 public void incrementClasses(int increment) {
275 for (int i = 0; i < atomClasses.length; i++) {
276 atomClasses[i] += increment;
277 }
278 setKey(sortKey(atomClasses));
279 }
280
281
282
283
284
285
286 public void patchClasses(HashMap<AtomType, AtomType> typeMap) {
287 int count = 0;
288 for (AtomType newType : typeMap.keySet()) {
289 for (int atomClass : atomClasses) {
290 if (atomClass == newType.atomClass) {
291 count++;
292 }
293 }
294 }
295 if (count > 0 && count < atomClasses.length) {
296 for (AtomType newType : typeMap.keySet()) {
297 for (int i = 0; i < atomClasses.length; i++) {
298 if (atomClasses[i] == newType.atomClass) {
299 AtomType knownType = typeMap.get(newType);
300 atomClasses[i] = knownType.atomClass;
301 }
302 }
303 }
304 setKey(sortKey(atomClasses));
305 }
306 }
307
308
309
310
311
312
313 @Override
314 public String toString() {
315 return format("ureybrad %5d %5d %5d %6.2f %7.4f", atomClasses[0], atomClasses[1],
316 atomClasses[2], forceConstant, distance);
317 }
318
319
320
321
322
323
324
325
326 public static Element getXMLForce(Document doc, ForceField forceField) {
327 Map<String, UreyBradleyType> types = forceField.getUreyBradleyTypes();
328 if (!types.values().isEmpty()) {
329 Element node = doc.createElement("AmoebaUreyBradleyForce");
330 node.setAttribute("cubic", valueOf(forceField.getDouble("urey-cubic", DEFAULT_UREY_CUBIC)));
331 node.setAttribute("quartic", valueOf(forceField.getDouble("urey-quartic", DEFAULT_UREY_QUARTIC)));
332 for (UreyBradleyType ureyBradleyType : types.values()) {
333 node.appendChild(ureyBradleyType.toXML(doc));
334 }
335 return node;
336 }
337 return null;
338 }
339
340
341
342
343 public Element toXML(Document doc) {
344 Element node = doc.createElement("UreyBradley");
345 node.setAttribute("class1", format("%d", atomClasses[0]));
346 node.setAttribute("class2", format("%d", atomClasses[1]));
347 node.setAttribute("class3", format("%d", atomClasses[2]));
348
349 node.setAttribute("k", format("%f", forceConstant * KCAL_TO_KJ / (ANG_TO_NM * ANG_TO_NM)));
350
351 node.setAttribute("d", format("%f", distance * ANG_TO_NM));
352 return node;
353 }
354 }