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