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