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.SOLUTE;
41 import static ffx.utilities.PropertyGroup.PotentialFunctionParameter;
42 import static java.lang.Double.parseDouble;
43 import static java.lang.Integer.parseInt;
44 import static java.lang.String.format;
45
46 import ffx.potential.bonded.Atom;
47 import ffx.utilities.FFXProperty;
48 import org.apache.commons.lang3.math.NumberUtils;
49
50 import java.util.Comparator;
51 import java.util.HashMap;
52 import java.util.Map;
53 import java.util.Objects;
54 import java.util.logging.Level;
55 import java.util.logging.Logger;
56
57
58
59
60
61
62
63 @FFXProperty(name = "solute", clazz = String.class, propertyGroup = PotentialFunctionParameter,
64 description = """
65 [integers and 4 reals]
66 Provides values for a single implicit solvation parameter.
67 The integer modifier gives the atom type number for which solvation atom size parameters are to be defined.
68 The first three real number modifiers give the values of the atomic diameter in Angstroms,
69 for use in Poisson-Boltzmann (APBS), ddCOSMO and Generalized Kirkwood (GK) calculations, respectively.
70 The final real number is the Sneck scaling factor for implicit solvent interstitial space corrections.
71 """)
72 public final class SoluteType extends BaseType implements Comparator<String> {
73
74
75 private static final Logger logger = Logger.getLogger(SoluteType.class.getName());
76
77 public enum SOLUTE_RADII_TYPE {VDW, CONSENSUS, SOLUTE}
78
79
80 static final Map<Integer, SoluteType> CONSENSUS_RADII = new HashMap<>();
81
82
83 public double pbDiameter;
84
85 public double cosDiameter;
86
87 public double gkDiameter;
88
89 public double sneck;
90 public double DEFAULT_SNECK = 0.6784;
91
92
93 public String description;
94
95 private int atomType;
96
97
98
99
100
101
102
103 public SoluteType(int atomType, double diameter) {
104 super(SOLUTE, Integer.toString(atomType));
105 this.atomType = atomType;
106 this.pbDiameter = diameter;
107 this.cosDiameter = diameter;
108 this.gkDiameter = diameter;
109 this.description = null;
110 this.sneck = DEFAULT_SNECK;
111 }
112
113
114
115
116
117
118
119
120
121 public SoluteType(int atomType, double pbDiameter, double cosDiameter, double gkDiameter) {
122 super(SOLUTE, Integer.toString(atomType));
123 this.atomType = atomType;
124 this.pbDiameter = pbDiameter;
125 this.cosDiameter = cosDiameter;
126 this.gkDiameter = gkDiameter;
127 this.description = null;
128 this.sneck = DEFAULT_SNECK;
129 }
130
131
132
133
134
135
136
137
138
139
140 public SoluteType(int atomType, double pbDiameter, double cosDiameter, double gkDiameter, double sneck) {
141 super(SOLUTE, Integer.toString(atomType));
142 this.atomType = atomType;
143 this.pbDiameter = pbDiameter;
144 this.cosDiameter = cosDiameter;
145 this.gkDiameter = gkDiameter;
146 this.description = null;
147 this.sneck = sneck;
148 }
149
150
151
152
153
154
155
156
157
158
159 public SoluteType(int atomType, String description, double pbDiameter, double cosDiameter, double gkDiameter) {
160 this(atomType, pbDiameter, cosDiameter, gkDiameter);
161 this.description = description;
162 this.sneck = DEFAULT_SNECK;
163 }
164
165
166
167
168
169
170
171
172 public static SoluteType parse(String input, String[] tokens) {
173 if (tokens.length < 4) {
174 logger.log(Level.WARNING, "Invalid SOLUTE type:\n{0}", input);
175 } else {
176 try {
177 if (tokens.length == 5) {
178 int atomType = parseInt(tokens[1].trim());
179 double pbDiameter = parseDouble(tokens[2].trim());
180 double cosDiameter = parseDouble(tokens[3].trim());
181 double gkDiameter = parseDouble(tokens[4].trim());
182 return new SoluteType(atomType, pbDiameter, cosDiameter, gkDiameter);
183 } else {
184
185
186 if (NumberUtils.isParsable(tokens[2].trim())) {
187
188 int atomType = parseInt(tokens[1].trim());
189 double pbDiameter = parseDouble(tokens[2].trim());
190 double cosDiameter = parseDouble(tokens[3].trim());
191 double gkDiameter = parseDouble(tokens[4].trim());
192 double sneck = parseDouble(tokens[5].trim());
193 return new SoluteType(atomType, pbDiameter, cosDiameter, gkDiameter, sneck);
194 } else {
195
196
197 int atomType = parseInt(tokens[1].trim());
198 String description = tokens[2].trim();
199 double pbDiameter = parseDouble(tokens[3].trim());
200 double cosDiameter = parseDouble(tokens[4].trim());
201 double gkDiameter = parseDouble(tokens[5].trim());
202 return new SoluteType(atomType, description, pbDiameter, cosDiameter, gkDiameter);
203 }
204 }
205 } catch (NumberFormatException e) {
206 String message = "Exception parsing SOLUTE type:\n" + input + "\n";
207 logger.log(Level.SEVERE, message, e);
208 }
209 }
210 return null;
211 }
212
213
214 @Override
215 public int compare(String key1, String key2) {
216 int type1 = parseInt(key1);
217 int type2 = parseInt(key2);
218 return Integer.compare(type1, type2);
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 SoluteType soluteType = (SoluteType) o;
231 return soluteType.atomType == this.atomType;
232 }
233
234
235 @Override
236 public int hashCode() {
237 return Objects.hash(atomType);
238 }
239
240
241
242
243
244
245 @Override
246 public String toString() {
247 if (description == null) {
248 return format("solute %4d %7.4f %7.4f %7.4f", atomType, pbDiameter, cosDiameter,
249 gkDiameter);
250 } else {
251 return format("solute %4d %30s %7.4f %7.4f %7.4f", atomType, description, pbDiameter,
252 cosDiameter, gkDiameter);
253 }
254 }
255
256
257
258
259
260
261 void incrementType(int increment) {
262 atomType += increment;
263 setKey(Integer.toString(atomType));
264 }
265
266 static {
267 CONSENSUS_RADII.put(0, new SoluteType(0, 0.00 * 2.0));
268 CONSENSUS_RADII.put(1, new SoluteType(1, 1.20 * 2.0));
269 CONSENSUS_RADII.put(2, new SoluteType(2, 1.40 * 2.0));
270 CONSENSUS_RADII.put(5, new SoluteType(5, 1.80 * 2.0));
271 CONSENSUS_RADII.put(6, new SoluteType(6, 1.70 * 2.0));
272 CONSENSUS_RADII.put(7, new SoluteType(7, 1.55 * 2.0));
273 CONSENSUS_RADII.put(8, new SoluteType(8, 1.52 * 2.0));
274 CONSENSUS_RADII.put(9, new SoluteType(9, 1.47 * 2.0));
275 CONSENSUS_RADII.put(10, new SoluteType(10, 1.54 * 2.0));
276 CONSENSUS_RADII.put(14, new SoluteType(14, 2.10 * 2.0));
277 CONSENSUS_RADII.put(15, new SoluteType(15, 1.80 * 2.0));
278 CONSENSUS_RADII.put(16, new SoluteType(16, 1.80 * 2.0));
279 CONSENSUS_RADII.put(17, new SoluteType(17, 1.75 * 2.0));
280 CONSENSUS_RADII.put(18, new SoluteType(18, 1.88 * 2.0));
281 CONSENSUS_RADII.put(34, new SoluteType(34, 1.90 * 2.0));
282 CONSENSUS_RADII.put(35, new SoluteType(35, 1.85 * 2.0));
283 CONSENSUS_RADII.put(36, new SoluteType(36, 2.02 * 2.0));
284 CONSENSUS_RADII.put(53, new SoluteType(53, 1.98 * 2.0));
285 CONSENSUS_RADII.put(54, new SoluteType(54, 2.16 * 2.0));
286 for (int i = 0; i <= 118; i++) {
287 if (!CONSENSUS_RADII.containsKey(i)) {
288 CONSENSUS_RADII.put(i, new SoluteType(i, 2.0 * 2.0));
289 }
290 }
291 }
292
293 public static SoluteType getCensusSoluteType(int atomicNumber) {
294 return CONSENSUS_RADII.get(atomicNumber);
295 }
296
297 public static SoluteType getVDWSoluteType(VDWType vdwType) {
298 return new SoluteType(vdwType.atomClass, vdwType.radius);
299 }
300
301 public static SoluteType getFitSoluteType(ForceField forceField, int type) {
302 SoluteType soluteType = forceField.getSoluteType(Integer.toString(type));
303 if (soluteType != null) {
304 if (soluteType.gkDiameter <= 0.0) {
305 logger.severe(format(" Invalid solute type: %s", soluteType));
306 }
307 }
308 return soluteType;
309 }
310
311 public static SoluteType getSoluteType(Atom atom, ForceField forceField,
312 SOLUTE_RADII_TYPE soluteRadiiType) {
313
314 SoluteType soluteType = getCensusSoluteType(atom.getAtomicNumber());
315
316 if (soluteRadiiType == SOLUTE_RADII_TYPE.VDW) {
317 SoluteType type = getVDWSoluteType(atom.getVDWType());
318 if (type != null) {
319 soluteType = type;
320 }
321 } else if (soluteRadiiType == SOLUTE_RADII_TYPE.SOLUTE) {
322 SoluteType type = getFitSoluteType(forceField, atom.getAtomType().type);
323 if (type != null) {
324 soluteType = type;
325 }
326 }
327 return soluteType;
328 }
329
330 public static void setSoluteRadii(ForceField forceField, Atom[] atoms,
331 SOLUTE_RADII_TYPE soluteRadiiType) {
332 for (Atom atom : atoms) {
333 atom.setSoluteType(getSoluteType(atom, forceField, soluteRadiiType));
334 }
335 }
336
337 }