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.OPBEND;
41 import static ffx.utilities.PropertyGroup.EnergyUnitConversion;
42 import static ffx.utilities.PropertyGroup.LocalGeometryFunctionalForm;
43 import static ffx.utilities.PropertyGroup.PotentialFunctionParameter;
44 import static java.lang.Double.parseDouble;
45 import static java.lang.Integer.parseInt;
46 import static java.util.Arrays.copyOf;
47 import static org.apache.commons.math3.util.FastMath.PI;
48 import static org.apache.commons.math3.util.FastMath.pow;
49
50 import ffx.utilities.FFXProperty;
51
52 import java.util.Arrays;
53 import java.util.Comparator;
54 import java.util.HashMap;
55 import java.util.logging.Level;
56 import java.util.logging.Logger;
57
58
59
60
61
62
63
64 @FFXProperty(name = "opbend", clazz = String.class, propertyGroup = PotentialFunctionParameter, description = """
65 [4 integers and 1 real]
66 Provides the values for a single out-of-plane bending potential parameter.
67 The first integer modifier is the atom class of the out-of-plane atom and the second integer is the atom class of the central trigonal atom.
68 The third and fourth integers give the atom classes of the two remaining atoms attached to the trigonal atom.
69 Values of zero for the third and fourth integers are treated as wildcards, and can represent any atom type.
70 The real number modifier gives the force constant value for the out-of-plane angle.
71 The default units for the force constant are kcal/mole/radian^2, but this can be controlled via the opbendunit keyword.
72 """)
73 public final class OutOfPlaneBendType extends BaseType implements Comparator<String> {
74
75
76
77
78 public static final double DEFAULT_OPBEND_CUBIC = 0.0;
79
80
81
82 public static final double DEFAULT_OPBEND_QUARTIC = 0.0;
83
84
85
86 public static final double DEFAULT_OPBEND_PENTIC = 0.0;
87
88
89
90 public static final double DEFAULT_OPBEND_SEXTIC = 0.0;
91
92
93
94
95 @FFXProperty(name = "opbend-cubic", propertyGroup = LocalGeometryFunctionalForm, defaultValue = "0.0", description = """
96 Sets the value of the cubic term in the Taylor series expansion form of the out-of-plane bending potential energy.
97 The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient.
98 This term multiplied by the out-of-plane bending energy unit conversion factor, the force constant,
99 and the cube of the deviation of the out-of-plane angle from zero gives the cubic contribution to the out-of-plane bending energy.
100 The default value in the absence of the opbend-cubic keyword is zero; i.e., the cubic out-of-plane bending term is omitted.
101 """)
102 public double cubic = DEFAULT_OPBEND_CUBIC;
103
104
105
106
107 @FFXProperty(name = "opbend-quartic", propertyGroup = LocalGeometryFunctionalForm, defaultValue = "0.0", description = """
108 Sets the value of the quartic term in the Taylor series expansion form of the out-of-plane bending potential energy.
109 The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient.
110 This term multiplied by the out-of-plane bending energy unit conversion factor, the force constant,
111 and the forth power of the deviation of the out-of-plane angle from zero gives the quartic contribution to the out-of-plane bending energy.
112 The default value in the absence of the opbend-quartic keyword is zero; i.e., the quartic out-of-plane bending term is omitted.
113 """)
114 public double quartic = DEFAULT_OPBEND_QUARTIC;
115
116
117
118
119 @FFXProperty(name = "opbend-pentic", propertyGroup = LocalGeometryFunctionalForm, defaultValue = "0.0", description = """
120 Sets the value of the fifth power term in the Taylor series expansion form of the out-of-plane bending potential energy.
121 The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient.
122 This term multiplied by the out-of-plane bending energy unit conversion factor, the force constant,
123 and the fifth power of the deviation of the out-of-plane angle from zero gives the pentic contribution to the out-of-plane bending energy.
124 The default value in the absence of the opbend-pentic keyword is zero; i.e., the pentic out-of-plane bending term is omitted.
125 """)
126 public double pentic = DEFAULT_OPBEND_PENTIC;
127
128
129
130
131 @FFXProperty(name = "opbend-sextic", propertyGroup = LocalGeometryFunctionalForm, defaultValue = "0.0", description = """
132 Sets the value of the sixth power term in the Taylor series expansion form of the out-of-plane bending potential energy.
133 The real number modifier gives the value of the coefficient as a multiple of the quadratic coefficient.
134 This term multiplied by the out-of-plane bending energy unit conversion factor, the force constant,
135 and the sixth power of the deviation of the out-of-plane angle from zero gives the sextic contribution to the out-of-plane bending energy.
136 The default value in the absence of the opbend-sextic keyword is zero; i.e., the sextic out-of-plane bending term is omitted.
137 """)
138 public double sextic = DEFAULT_OPBEND_SEXTIC;
139
140
141
142
143
144
145
146
147
148
149 @FFXProperty(name = "opbendunit", propertyGroup = EnergyUnitConversion, defaultValue = "(Pi/180)^2", description = """
150 Sets the scale factor needed to convert the energy value computed by the out-of-plane bending potential into units of kcal/mole. "
151 The correct value is force field dependent and typically provided in the header of the master force field parameter file.
152 """)
153 public double opBendUnit = DEFAULT_OPBEND_UNIT;
154
155 public static final double DEFAULT_OPBEND_UNIT = pow(PI / 180.0, 2);
156
157
158
159 private static final Logger logger = Logger.getLogger(OutOfPlaneBendType.class.getName());
160
161
162
163 public final int[] atomClasses;
164
165
166
167 public final double forceConstant;
168
169
170
171
172
173
174
175 public OutOfPlaneBendType(int[] atomClasses, double forceConstant) {
176 super(OPBEND, sortKey(atomClasses));
177 this.atomClasses = atomClasses;
178 this.forceConstant = forceConstant;
179 }
180
181
182
183
184
185
186
187
188
189
190 public static OutOfPlaneBendType average(OutOfPlaneBendType outOfPlaneBendType1,
191 OutOfPlaneBendType outOfPlaneBendType2, int[] atomClasses) {
192 if (outOfPlaneBendType1 == null || outOfPlaneBendType2 == null || atomClasses == null) {
193 return null;
194 }
195
196 double forceConstant =
197 (outOfPlaneBendType1.forceConstant + outOfPlaneBendType2.forceConstant) / 2.0;
198
199 return new OutOfPlaneBendType(atomClasses, forceConstant);
200 }
201
202
203
204
205
206
207
208
209 public static OutOfPlaneBendType parse(String input, String[] tokens) {
210 if (tokens.length < 6) {
211 logger.log(Level.WARNING, "Invalid OPBEND type:\n{0}", input);
212 } else {
213 try {
214 int[] atomClasses = new int[4];
215 atomClasses[0] = parseInt(tokens[1]);
216 atomClasses[1] = parseInt(tokens[2]);
217 atomClasses[2] = parseInt(tokens[3]);
218 atomClasses[3] = parseInt(tokens[4]);
219 double forceConstant = parseDouble(tokens[5]);
220 return new OutOfPlaneBendType(atomClasses, forceConstant);
221 } catch (NumberFormatException e) {
222 String message = "Exception parsing OPBEND type:\n" + input + "\n";
223 logger.log(Level.SEVERE, message, e);
224 }
225 }
226 return null;
227 }
228
229
230
231
232
233
234
235 public static String sortKey(int[] c) {
236 if (c == null || c.length != 4) {
237 return null;
238 }
239 return c[0] + " " + c[1] + " " + c[2] + " " + c[3];
240 }
241
242
243
244
245 @Override
246 public int compare(String s1, String s2) {
247 String[] keys1 = s1.split(" ");
248 String[] keys2 = s2.split(" ");
249
250 for (int i = 0; i < 4; i++) {
251 int c1 = parseInt(keys1[i]);
252 int c2 = parseInt(keys2[i]);
253 if (c1 < c2) {
254 return -1;
255 } else if (c1 > c2) {
256 return 1;
257 }
258 }
259 return 0;
260 }
261
262
263
264
265 @Override
266 public boolean equals(Object o) {
267 if (this == o) {
268 return true;
269 }
270 if (o == null || getClass() != o.getClass()) {
271 return false;
272 }
273 OutOfPlaneBendType outOfPlaneBendType = (OutOfPlaneBendType) o;
274 return Arrays.equals(atomClasses, outOfPlaneBendType.atomClasses);
275 }
276
277
278
279
280 @Override
281 public int hashCode() {
282 return Arrays.hashCode(atomClasses);
283 }
284
285
286
287
288
289
290 public void incrementClasses(int increment) {
291 for (int i = 0; i < atomClasses.length; i++) {
292 if (atomClasses[i] > 0) {
293 atomClasses[i] += increment;
294 }
295 }
296 setKey(sortKey(atomClasses));
297 }
298
299
300
301
302
303
304
305 public OutOfPlaneBendType patchClasses(HashMap<AtomType, AtomType> typeMap) {
306 int count = 0;
307 int len = atomClasses.length;
308
309
310 for (AtomType newType : typeMap.keySet()) {
311
312 for (int atomClass : atomClasses) {
313 if (atomClass == newType.atomClass) {
314 count++;
315 }
316 }
317 }
318
319
320 if (count == 1) {
321 int[] newClasses = copyOf(atomClasses, len);
322 for (AtomType newType : typeMap.keySet()) {
323 for (int i = 0; i < len; i++) {
324 if (atomClasses[i] == newType.atomClass) {
325 AtomType knownType = typeMap.get(newType);
326 newClasses[i] = knownType.atomClass;
327 }
328 }
329 }
330 return new OutOfPlaneBendType(newClasses, forceConstant);
331 }
332 return null;
333 }
334
335
336
337
338
339
340 @Override
341 public String toString() {
342 return String.format("opbend %5d %5d %5d %5d %6.2f", atomClasses[0], atomClasses[1],
343 atomClasses[2], atomClasses[3], forceConstant);
344 }
345 }