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.potential.parameters.ForceField.ForceFieldType;
41 import ffx.utilities.FFXProperty;
42 import org.w3c.dom.Document;
43 import org.w3c.dom.Element;
44
45 import java.util.Arrays;
46 import java.util.Comparator;
47 import java.util.logging.Level;
48 import java.util.logging.Logger;
49
50 import static ffx.utilities.Constants.ANG_TO_NM;
51 import static ffx.utilities.Constants.KCAL_TO_KJ;
52 import static ffx.utilities.PropertyGroup.PotentialFunctionParameter;
53 import static java.lang.Double.parseDouble;
54 import static java.lang.Integer.parseInt;
55 import static java.lang.String.format;
56
57
58
59
60
61
62
63 @FFXProperty(name = "vdwpr", clazz = String.class, propertyGroup = PotentialFunctionParameter, description = """
64 [2 integers and 2 reals]
65 Provides the values for the vdw parameters for a single special heteroatomic pair of atoms.
66 The integer modifiers give the pair of atom class numbers for which special vdw parameters are to be defined.
67 The two real number modifiers give the values of the minimum energy contact distance in Angstroms and the well depth at the minimum distance in kcal/mole.
68 """)
69 public final class VDWPairType extends BaseType implements Comparator<String> {
70
71 private static final Logger logger = Logger.getLogger(VDWPairType.class.getName());
72
73
74
75 public final double radius;
76
77
78
79 public final double wellDepth;
80
81
82
83 public final int[] atomClasses;
84
85
86
87
88
89
90
91
92
93 public VDWPairType(int[] atomClasses, double radius, double wellDepth) {
94 super(ForceFieldType.VDWPR, sortKey(atomClasses));
95 this.atomClasses = atomClasses;
96 this.radius = radius;
97 this.wellDepth = wellDepth;
98 }
99
100
101
102
103
104
105
106
107
108 public static VDWPairType average(VDWPairType vdwType1, VDWPairType vdwType2, int[] atomClasses) {
109 if (vdwType1 == null || vdwType2 == null) {
110 return null;
111 }
112
113 double radius = (vdwType1.radius + vdwType2.radius) / 2.0;
114 double wellDepth = (vdwType1.wellDepth + vdwType2.wellDepth) / 2.0;
115
116 return new VDWPairType(atomClasses, radius, wellDepth);
117 }
118
119
120
121
122
123
124
125
126 public static VDWPairType parse(String input, String[] tokens) {
127 if (tokens.length < 5) {
128 logger.log(Level.WARNING, "Invalid VDWPR type:\n{0}", input);
129 } else {
130 try {
131 int atomClass1 = parseInt(tokens[1]);
132 int atomClass2 = parseInt(tokens[2]);
133 double radius = parseDouble(tokens[3]);
134 double wellDepth = parseDouble(tokens[4]);
135 return new VDWPairType(new int[]{atomClass1, atomClass2}, radius, wellDepth);
136 } catch (NumberFormatException e) {
137 String message = "Exception parsing VDWPR type:\n" + input + "\n";
138 logger.log(Level.SEVERE, message, e);
139 }
140 }
141 return null;
142 }
143
144
145
146
147 @Override
148 public int compare(String key1, String key2) {
149 String[] keys1 = key1.split(" ");
150 String[] keys2 = key2.split(" ");
151 int[] c1 = new int[2];
152 int[] c2 = new int[2];
153 for (int i = 0; i < 2; i++) {
154 c1[i] = Integer.parseInt(keys1[i]);
155 c2[i] = Integer.parseInt(keys2[i]);
156 }
157
158 if (c1[0] < c2[0]) {
159 return -1;
160 } else if (c1[0] > c2[0]) {
161 return 1;
162 } else if (c1[1] < c2[1]) {
163 return -1;
164 } else if (c1[1] > c2[1]) {
165 return 1;
166 }
167
168 return 0;
169 }
170
171
172
173
174 @Override
175 public boolean equals(Object o) {
176 if (this == o) {
177 return true;
178 }
179 if (o == null || getClass() != o.getClass()) {
180 return false;
181 }
182 VDWPairType vdwPairType = (VDWPairType) o;
183 return Arrays.equals(atomClasses, vdwPairType.atomClasses);
184 }
185
186
187
188
189 @Override
190 public int hashCode() {
191 return Arrays.hashCode(atomClasses);
192 }
193
194
195
196
197
198
199 @Override
200 public String toString() {
201 return format("vdwpr %5d %5d %11.9f %11.9f", atomClasses[0], atomClasses[1], radius, wellDepth);
202 }
203
204
205
206
207 public Element toXML(Document doc) {
208 Element node = doc.createElement("Pair");
209 node.setAttribute("class1", format("%d", atomClasses[0]));
210 node.setAttribute("class2", format("%d", atomClasses[1]));
211
212 node.setAttribute("sigma", format("%f", radius * ANG_TO_NM));
213
214 node.setAttribute("epsilon", format("%f", wellDepth * KCAL_TO_KJ));
215 return node;
216 }
217
218
219
220
221
222
223
224 public static String sortKey(int[] c) {
225 if (c == null || c.length != 2) {
226 return null;
227 }
228
229 int temp;
230 if (c[1] <= c[0]) {
231 temp = c[1];
232 c[1] = c[0];
233 c[0] = temp;
234 }
235
236 return c[0] + " " + c[1];
237 }
238
239
240
241
242
243
244 public void incrementClasses(int increment) {
245 for (int i = 0; i < atomClasses.length; i++) {
246 atomClasses[i] += increment;
247 }
248 setKey(sortKey(atomClasses));
249 }
250
251 }