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.nonbonded;
39
40 import ffx.potential.parameters.ForceField;
41 import ffx.potential.parameters.VDWPairType;
42 import ffx.potential.parameters.VDWType;
43 import ffx.utilities.FFXProperty;
44
45 import java.util.Map;
46 import java.util.TreeMap;
47 import java.util.logging.Logger;
48
49 import static ffx.potential.parameters.ForceField.toEnumForm;
50 import static ffx.utilities.PropertyGroup.VanDerWaalsFunctionalForm;
51 import static java.lang.String.format;
52 import static org.apache.commons.math3.util.FastMath.pow;
53 import static org.apache.commons.math3.util.FastMath.sqrt;
54
55
56
57
58
59
60
61 public class VanDerWaalsForm {
62
63
64
65
66 private static final Logger logger = Logger.getLogger(VanDerWaalsForm.class.getName());
67
68
69
70
71 static final byte RADMIN = 0;
72
73
74
75 static final byte EPS = 1;
76
77
78
79
80 public static final double DEFAULT_VDW_TAPER = 0.9;
81
82
83
84
85 public static final double DEFAULT_VDW_CUTOFF = 12.0;
86
87
88
89
90 @FFXProperty(name = "halgren-gamma", propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "0.12",
91 description = """
92 Sets the value of the gamma parameter in Halgren’s buffered 14-7 vdw potential energy functional form.
93 In the absence of the gamma-halgren property, a default value of 0.12 is used."
94 """)
95
96 public final double gamma;
97
98
99
100
101 @FFXProperty(name = "halgren-delta", propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "0.07",
102 description = """
103 Sets the value of the delta parameter in Halgren’s buffered 14-7 vdw potential energy functional form.
104 In the absence of the delta-halgren property, a default value of 0.07 is used.
105 """)
106 public final double delta;
107
108
109
110
111 @FFXProperty(name = "vdwtype", clazz = String.class, propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "LENNARD-JONES",
112 description = """
113 [LENNARD-JONES / BUFFERED-14-7]
114 Sets the functional form for the van der Waals potential energy term.
115 The text modifier gives the name of the functional form to be used.
116 The default in the absence of the vdwtype keyword is to use the standard two parameter Lennard-Jones function.
117 """)
118 public VDWType.VDW_TYPE vdwType;
119
120
121
122
123 @FFXProperty(name = "epsilonrule", clazz = String.class, propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "GEOMETRIC",
124 description = """
125 [GEOMETRIC / HHG / W-H]
126 Selects the combining rule used to derive the epsilon value for van der Waals interactions.
127 The default in the absence of the epsilonrule keyword is to use the geometric mean of the
128 individual epsilon values of the two atoms involved in the van der Waals interaction.
129 """)
130 public VDWType.EPSILON_RULE epsilonRule;
131
132
133
134
135 @FFXProperty(name = "radiusrule", clazz = String.class, propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "ARITHMETIC",
136 description = """
137 [ARITHMETIC / GEOMETRIC / CUBIC-MEAN]
138 Sets the functional form of the radius combining rule for heteroatomic van der Waals potential energy interactions.
139 The default in the absence of the radiusrule keyword is to use the arithmetic mean combining rule to get radii for heteroatomic interactions.
140 """)
141 public VDWType.RADIUS_RULE radiusRule;
142
143
144
145
146 @FFXProperty(name = "radiussize", clazz = String.class, propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "RADIUS",
147 description = """
148 [RADIUS / DIAMETER]
149 Determines whether the atom size values given in van der Waals parameters read from
150 VDW keyword statements are interpreted as atomic radius or diameter values.
151 The default in the absence of the radiussize keyword is to assume that vdw size parameters are given as radius values.
152 """)
153 public VDWType.RADIUS_SIZE radiusSize;
154
155
156
157
158 @FFXProperty(name = "radiustype", clazz = String.class, propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "R-MIN",
159 description = """
160 [R-MIN / SIGMA]
161 Determines whether atom size values given in van der Waals parameters read from VDW keyword
162 statements are interpreted as potential minimum (Rmin) or LJ-style sigma values.
163 The default in the absence of the radiustype keyword is to assume that vdw size parameters are given as Rmin values.
164 """)
165 public VDWType.RADIUS_TYPE radiusType;
166
167
168
169
170 @FFXProperty(name = "vdw-12-scale", propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "0.0",
171 description = """
172 Provides a multiplicative scale factor that is applied to van der Waals potential
173 interactions between 1-2 connected atoms, i.e., atoms that are directly bonded.
174 The default value of 0.0 is used to omit 1-2 interactions,
175 if the vdw-12-scale property is not given in either the parameter file or the property file.
176 """)
177 protected double scale12;
178
179
180
181
182 @FFXProperty(name = "vdw-13-scale", propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "0.0",
183 description = """
184 Provides a multiplicative scale factor that is applied to van der Waals potential
185 interactions between 1-3 connected atoms, i.e., atoms separated by two covalent bonds.
186 The default value of 0.0 is used to omit 1-3 interactions, if the vdw-13-scale property
187 is not given in either the parameter file or the property file.
188 """)
189 protected double scale13;
190
191
192
193
194 @FFXProperty(name = "vdw-14-scale", propertyGroup = VanDerWaalsFunctionalForm, defaultValue = "1.0",
195 description = """
196 Provides a multiplicative scale factor that is applied to van der Waals potential
197 interactions between 1-4 connected atoms, i.e., atoms separated by three covalent bonds.
198 The default value of 1.0 is used, if the vdw-14-scale keyword is not given in either
199 the parameter file or the property file.
200 """)
201 protected double scale14;
202
203
204
205
206 int maxClass;
207
208
209
210 double[] rMin;
211
212
213
214 double[] eps;
215
216
217
218 private final double[][] radEps;
219
220
221
222
223
224 private final double[][] radEps14;
225
226
227
228 private final VDWPowers vdwPowers;
229
230
231
232 final int dispersivePower;
233
234
235
236 private final int dispersivePower1;
237
238
239
240 final double t1n;
241
242
243
244 final int repDispPower;
245
246
247
248 private final int repDispPower1;
249
250
251
252 final double gamma1;
253
254
255
256
257
258
259 public VanDerWaalsForm(ForceField forceField) {
260
261
262 vdwType = VDWType.DEFAULT_VDW_TYPE;
263 String value = forceField.getString("VDWTYPE", VDWType.DEFAULT_VDW_TYPE.name());
264 try {
265 vdwType = VDWType.VDW_TYPE.valueOf(toEnumForm(value));
266 } catch (Exception e) {
267 logger.info(format(" Unrecognized VDWTYPE %s; defaulting to %s.", value, vdwType));
268 }
269
270 switch (vdwType) {
271 case BUFFERED_14_7 -> vdwPowers = new Buffered_14_7();
272 case LENNARD_JONES -> vdwPowers = new LJ_6_12();
273 default -> vdwPowers = new VDWPowers();
274 }
275
276
277 epsilonRule = VDWType.DEFAULT_EPSILON_RULE;
278 value = forceField.getString("EPSILONRULE", VDWType.DEFAULT_EPSILON_RULE.name());
279 try {
280 epsilonRule = VDWType.EPSILON_RULE.valueOf(toEnumForm(value));
281 } catch (Exception e) {
282 logger.info(format(" Unrecognized EPSILONRULE %s; defaulting to %s.", value, epsilonRule));
283 }
284
285
286 radiusRule = VDWType.DEFAULT_RADIUS_RULE;
287 value = forceField.getString("RADIUSRULE", VDWType.DEFAULT_RADIUS_RULE.name());
288 try {
289 radiusRule = VDWType.RADIUS_RULE.valueOf(toEnumForm(value));
290 } catch (Exception e) {
291 logger.info(format(" Unrecognized RADIUSRULE %s; defaulting to %s.", value, radiusRule));
292 }
293
294
295 radiusSize = VDWType.DEFAULT_RADIUS_SIZE;
296 value = forceField.getString("RADIUSSIZE", VDWType.DEFAULT_RADIUS_SIZE.name());
297 try {
298 radiusSize = VDWType.RADIUS_SIZE.valueOf(toEnumForm(value));
299 } catch (Exception e) {
300 logger.info(format(" Unrecognized RADIUSSIZE %s; defaulting to %s.", value, radiusSize));
301 }
302
303
304 radiusType = VDWType.DEFAULT_RADIUS_TYPE;
305 value = forceField.getString("RADIUSTYPE", VDWType.DEFAULT_RADIUS_TYPE.name());
306 try {
307 radiusType = VDWType.RADIUS_TYPE.valueOf(toEnumForm(value));
308 } catch (Exception e) {
309 logger.info(format(" Unrecognized RADIUSTYPE %s; defaulting to %s", value, radiusType));
310 }
311
312
313 int repulsivePower;
314 switch (vdwType) {
315 case LENNARD_JONES -> {
316 repulsivePower = 12;
317 dispersivePower = 6;
318 delta = 0.0;
319 gamma = 0.0;
320 }
321 default -> {
322 repulsivePower = 14;
323 dispersivePower = 7;
324 delta = forceField.getDouble("DELTA-HALGREN", VDWType.DEFAULT_DELTA);
325 gamma = forceField.getDouble("GAMMA-HALGREN", VDWType.DEFAULT_GAMMA);
326 }
327 }
328
329 repDispPower = repulsivePower - dispersivePower;
330 dispersivePower1 = dispersivePower - 1;
331 repDispPower1 = repDispPower - 1;
332 double delta1 = 1.0 + delta;
333 t1n = pow(delta1, dispersivePower);
334 gamma1 = 1.0 + gamma;
335
336 scale12 = forceField.getDouble("VDW_12_SCALE", VDWType.DEFAULT_VDW_12_SCALE);
337 scale13 = forceField.getDouble("VDW_13_SCALE", VDWType.DEFAULT_VDW_13_SCALE);
338 scale14 = forceField.getDouble("VDW_14_SCALE", VDWType.DEFAULT_VDW_14_SCALE);
339 double scale15 = forceField.getDouble("VDW_15_SCALE", 1.0);
340 if (scale15 != 1.0) {
341 logger.severe(" Van Der Waals 1-5 masking rules are not supported.");
342 }
343
344
345 if (scale12 > 1.0) {
346 scale12 = 1.0 / scale12;
347 }
348 if (scale13 > 1.0) {
349 scale13 = 1.0 / scale13;
350 }
351 if (scale14 > 1.0) {
352 scale14 = 1.0 / scale14;
353 }
354
355 Map<String, VDWType> map = forceField.getVDWTypes();
356 TreeMap<String, VDWType> vdwTypes = new TreeMap<>(map);
357 maxClass = 0;
358 for (VDWType currentType : vdwTypes.values()) {
359 if (currentType.atomClass > maxClass) {
360 maxClass = currentType.atomClass;
361 }
362 }
363 radEps = new double[maxClass + 1][2 * (maxClass + 1)];
364 radEps14 = new double[maxClass + 1][2 * (maxClass + 1)];
365
366
367 double radScale = switch (radiusSize) {
368 case DIAMETER -> 0.5;
369 default -> 1.0;
370 };
371 switch (radiusType) {
372 case SIGMA -> radScale *= 1.122462048309372981;
373 default -> {
374 }
375 }
376
377 rMin = new double[maxClass + 1];
378 eps = new double[maxClass + 1];
379
380
381 for (VDWType vdwi : vdwTypes.values()) {
382 int i = vdwi.atomClass;
383 double ri = radScale * vdwi.radius;
384 double e1 = vdwi.wellDepth;
385 rMin[i] = ri;
386 eps[i] = e1;
387 for (VDWType vdwj : vdwTypes.tailMap(vdwi.getKey()).values()) {
388 int j = vdwj.atomClass;
389 double rj = radScale * vdwj.radius;
390 double e2 = vdwj.wellDepth;
391 double radmin = getCombinedRadius(ri, rj, radiusRule);
392 double eps = getCombinedEps(e1, e2, ri, rj, epsilonRule);
393 if (radmin > 0) {
394 radEps[i][j * 2 + RADMIN] = 1.0 / radmin;
395 radEps[j][i * 2 + RADMIN] = 1.0 / radmin;
396 radEps14[i][j * 2 + RADMIN] = 1.0 / radmin;
397 radEps14[j][i * 2 + RADMIN] = 1.0 / radmin;
398 } else {
399 radEps[i][j * 2 + RADMIN] = 0.0;
400 radEps[j][i * 2 + RADMIN] = 0.0;
401 radEps14[i][j * 2 + RADMIN] = 0.0;
402 radEps14[j][i * 2 + RADMIN] = 0.0;
403 }
404 radEps[i][j * 2 + EPS] = eps;
405 radEps[j][i * 2 + EPS] = eps;
406 radEps14[i][j * 2 + EPS] = eps;
407 radEps14[j][i * 2 + EPS] = eps;
408 }
409 }
410
411
412 Map<String, VDWType> vdw14Types = forceField.getVDW14Types();
413 for (VDWType vdwi : vdwTypes.values()) {
414
415 VDWType vdw14 = forceField.getVDW14Type(vdwi.getKey());
416 if (vdw14 != null) {
417 vdwi = vdw14;
418 }
419 int i = vdwi.atomClass;
420 double ri = radScale * vdwi.radius;
421 double e1 = vdwi.wellDepth;
422
423 for (VDWType vdwj : vdw14Types.values()) {
424 int j = vdwj.atomClass;
425 double rj = radScale * vdwj.radius;
426 double e2 = vdwj.wellDepth;
427 double radmin = getCombinedRadius(ri, rj, radiusRule);
428 double eps = getCombinedEps(e1, e2, ri, rj, epsilonRule);
429 if (radmin > 0) {
430 radEps14[i][j * 2 + RADMIN] = 1.0 / radmin;
431 radEps14[j][i * 2 + RADMIN] = 1.0 / radmin;
432 } else {
433 radEps14[i][j * 2 + RADMIN] = 0.0;
434 radEps14[j][i * 2 + RADMIN] = 0.0;
435 }
436 radEps14[i][j * 2 + EPS] = eps;
437 radEps14[j][i * 2 + EPS] = eps;
438 }
439 }
440
441
442 Map<String, VDWPairType> vdwPairTypes = forceField.getVDWPairTypes();
443 for (VDWPairType vdwPairType : vdwPairTypes.values()) {
444 int i = vdwPairType.atomClasses[0];
445 int j = vdwPairType.atomClasses[1];
446 double radmin = vdwPairType.radius;
447 double eps = vdwPairType.wellDepth;
448 if (radmin > 0) {
449 radEps[i][j * 2 + RADMIN] = 1.0 / radmin;
450 radEps[j][i * 2 + RADMIN] = 1.0 / radmin;
451 radEps14[i][j * 2 + RADMIN] = 1.0 / radmin;
452 radEps14[j][i * 2 + RADMIN] = 1.0 / radmin;
453 } else {
454 radEps[i][j * 2 + RADMIN] = 0.0;
455 radEps[j][i * 2 + RADMIN] = 0.0;
456 radEps14[i][j * 2 + RADMIN] = 0.0;
457 radEps14[j][i * 2 + RADMIN] = 0.0;
458 }
459 radEps[i][j * 2 + EPS] = eps;
460 radEps[j][i * 2 + EPS] = eps;
461 radEps14[i][j * 2 + EPS] = eps;
462 radEps14[j][i * 2 + EPS] = eps;
463 }
464 }
465
466
467
468
469
470
471
472
473
474
475
476 public static double getCombinedEps(double ei, double ej, double ri, double rj,
477 VDWType.EPSILON_RULE epsilonRule) {
478 double sei = sqrt(ei);
479 double sej = sqrt(ej);
480 switch (epsilonRule) {
481 case GEOMETRIC -> {
482 return sei * sej;
483 }
484 case W_H -> {
485
486 double rr = ri * rj;
487 double rr3 = rr * rr * rr;
488 double ri6 = pow(ri, 6);
489 double rj6 = pow(rj, 6);
490 return 2.0 * sei * sej * rr3 / (ri6 + rj6);
491 }
492 default -> {
493 if (ei * ej == 0.0) {
494 return 0.0;
495 }
496 return 4.0 * (ei * ej) / ((sei + sej) * (sei + sej));
497 }
498 }
499 }
500
501
502
503
504
505
506
507
508
509 public static double getCombinedRadius(double ri, double rj, VDWType.RADIUS_RULE radiusRule) {
510 switch (radiusRule) {
511 case ARITHMETIC -> {
512 return ri + rj;
513 }
514 case GEOMETRIC -> {
515 return 2.0 * sqrt(ri) * sqrt(rj);
516 }
517 default -> {
518 double ri2 = ri * ri;
519 double ri3 = ri * ri2;
520 double rj2 = rj * rj;
521 double rj3 = rj * rj2;
522 return 2.0 * (ri3 + rj3) / (ri2 + rj2);
523 }
524 }
525 }
526
527
528
529
530
531
532
533
534 public double getCombinedEps(int class1, int class2) {
535 return radEps[class1][class2 * 2 + EPS];
536 }
537
538
539
540
541
542
543
544
545 public double getCombinedEps14(int class1, int class2) {
546 return radEps14[class1][class2 * 2 + EPS];
547 }
548
549
550
551
552
553
554
555
556 public double getCombinedInverseRmin(int class1, int class2) {
557 return radEps[class1][class2 * 2 + RADMIN];
558 }
559
560
561
562
563
564
565
566
567 public double getCombinedInverseRmin14(int class1, int class2) {
568 return radEps14[class1][class2 * 2 + RADMIN];
569 }
570
571
572
573
574
575
576 public double[] getEps() {
577 return eps;
578 }
579
580
581
582
583
584
585 public double[] getRmin() {
586 return rMin;
587 }
588
589
590
591
592
593
594 public double getScale14() {
595 return scale14;
596 }
597
598
599
600
601
602
603
604 double rhoDisp1(double rho) {
605 return vdwPowers.rhoDisp1(rho);
606 }
607
608
609
610
611
612
613
614 double rhoDelta1(double rhoDelta) {
615 return vdwPowers.rhoDisp1(rhoDelta);
616 }
617
618
619
620
621 private class VDWPowers {
622
623 public double rhoDelta1(double rhoDelta) {
624 return pow(rhoDelta, repDispPower1);
625 }
626
627 public double rhoDisp1(double rho) {
628 return pow(rho, dispersivePower1);
629 }
630 }
631
632
633
634
635 private class LJ_6_12 extends VDWPowers {
636
637 @Override
638 public double rhoDelta1(double rhoDelta) {
639 double rhoDelta2 = rhoDelta * rhoDelta;
640 return rhoDelta2 * rhoDelta2 * rhoDelta;
641 }
642
643 @Override
644 public double rhoDisp1(double rho) {
645 double rho2 = rho * rho;
646 return rho2 * rho2 * rho;
647 }
648 }
649
650
651
652
653 private class Buffered_14_7 extends VDWPowers {
654
655 @Override
656 public double rhoDelta1(double rhoDelta) {
657 double rhoDelta2 = rhoDelta * rhoDelta;
658 return rhoDelta2 * rhoDelta2 * rhoDelta2;
659 }
660
661 @Override
662 public double rhoDisp1(double rho) {
663 double rho2 = rho * rho;
664 return rho2 * rho2 * rho2;
665 }
666 }
667 }