View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
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   * This class contains fields and methods for maintaining details of the van der Waals functional
57   * form.
58   *
59   * @author Michael J. Schnieders
60   */
61  public class VanDerWaalsForm {
62  
63    /**
64     * The logger.
65     */
66    private static final Logger logger = Logger.getLogger(VanDerWaalsForm.class.getName());
67  
68    /**
69     * Constant <code>RADMIN=0</code>
70     */
71    static final byte RADMIN = 0;
72    /**
73     * Constant <code>EPS=1</code>
74     */
75    static final byte EPS = 1;
76  
77    /**
78     * The default van der Waals taper location is at 90% of the cut-off distance.
79     */
80    public static final double DEFAULT_VDW_TAPER = 0.9;
81  
82    /**
83     * The default van der Waals cut-off radius is 12.0 Angstroms.
84     */
85    public static final double DEFAULT_VDW_CUTOFF = 12.0;
86  
87    /**
88     * First constant suggested by Halgren for the Buffered-14-7 potential.
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     * Second constant suggested by Halgren for the Buffered-14-7 potential.
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    * van der Waals functional form.
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    * Epsilon combining rule.
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    * Radius combining rule.
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    * Radius size in the parameter file (radius or diameter).
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    * Radius type in the parameter file (R-Min or Sigma).
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    * Define scale factors between 1-2 atoms.
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    * Define scale factors between 1-3 atoms.
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    * Define scale factors between 1-4 atoms.
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    * Maximum number of classes in the force field.
205    */
206   int maxClass;
207   /**
208    * Store the Rmin for each class.
209    */
210   double[] rMin;
211   /**
212    * Store the Eps for each class
213    */
214   double[] eps;
215   /**
216    * Store combined radius and epsilon values.
217    */
218   private final double[][] radEps;
219   /**
220    * Store combined radius and epsilon values for 1-4 interactions.
221    *
222    * <p>Currently this is specific to the CHARMM force fields.
223    */
224   private final double[][] radEps14;
225   /**
226    * Softcore vdW partial derivatives that are different between LJ and B14-7.
227    */
228   private final VDWPowers vdwPowers;
229   /**
230    * vdW Dispersive Power (e.g. 6).
231    */
232   final int dispersivePower;
233   /**
234    * vdW Dispersive Power minus 1 (e.g. 6-1 = 5).
235    */
236   private final int dispersivePower1;
237   /**
238    * Define some handy constants.
239    */
240   final double t1n;
241   /**
242    * Repulsive power minus dispersive power (e.g., 12-6 = 6).
243    */
244   final int repDispPower;
245   /**
246    * Repulsive power minus dispersive power minus 1 (e.g., 12-6-1 = 5).
247    */
248   private final int repDispPower1;
249   /**
250    * First constant suggested by Halgren for the Buffered-14-7 potential plus 1
251    */
252   final double gamma1;
253 
254   /**
255    * Constructor for VanDerWaalsForm.
256    *
257    * @param forceField a {@link ffx.potential.parameters.ForceField} object.
258    */
259   public VanDerWaalsForm(ForceField forceField) {
260 
261     // Define functional form.
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     // Define epsilon combining rule.
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     // Define radius combining rule.
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     // Define radius size.
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     // Define radius type.
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     // Configure van der Waals well shape parameters.
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     // The convention in TINKER is a vdw-14-scale factor of 2.0 means to scale by 0.5.
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     // Scale factor to convert to vdW size to Rmin.
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     // Atom Class numbering starts at 1.
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     // Handle vdw14 types -- loop over VDW types.
412     Map<String, VDWType> vdw14Types = forceField.getVDW14Types();
413     for (VDWType vdwi : vdwTypes.values()) {
414       // Replace a normal VDW type with a VDW14 type if available.
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       // Loop over VDW14 types.
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     // Replace combined VDW and VDW14 parameters with VDW Pair values.
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    * Get the combined EPS value.
468    *
469    * @param ei          The eps value of the first atom.
470    * @param ej          The eps value of the second atom.
471    * @param ri          The radius of the first atom.
472    * @param rj          The radius of the second atom.
473    * @param epsilonRule The epsilon rule to use.
474    * @return The combined eps value.
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         // ep = 2.0d0 * (seps(i)*seps(k)) * (rad(i)*rad(k))**3 / (rad(i)**6+rad(k)**6)
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    * Get the combined radius value.
503    *
504    * @param ri         The radius of the first atom.
505    * @param rj         The radius of the second atom.
506    * @param radiusRule The radius combining rule to use.
507    * @return The combined radius value.
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    * Return the combined well depth (kcal/mol)
529    *
530    * @param class1 Class for atom 1.
531    * @param class2 Class for atom 2.
532    * @return Combined Eps.
533    */
534   public double getCombinedEps(int class1, int class2) {
535     return radEps[class1][class2 * 2 + EPS];
536   }
537 
538   /**
539    * Return the combined well depth (kcal/mol) for special 1-4 interactions
540    *
541    * @param class1 Class for atom 1.
542    * @param class2 Class for atom 2.
543    * @return Combined Eps.
544    */
545   public double getCombinedEps14(int class1, int class2) {
546     return radEps14[class1][class2 * 2 + EPS];
547   }
548 
549   /**
550    * Return the combined inverse Rmin value (1/Rmin).
551    *
552    * @param class1 Class for atom 1.
553    * @param class2 Class for atom 2.
554    * @return Combined inverse Rmin.
555    */
556   public double getCombinedInverseRmin(int class1, int class2) {
557     return radEps[class1][class2 * 2 + RADMIN];
558   }
559 
560   /**
561    * Return the combined inverse Rmin value (1/Rmin) for special 1-4 interactions.
562    *
563    * @param class1 Class for atom 1.
564    * @param class2 Class for atom 2.
565    * @return Combined inverse Rmin.
566    */
567   public double getCombinedInverseRmin14(int class1, int class2) {
568     return radEps14[class1][class2 * 2 + RADMIN];
569   }
570 
571   /**
572    * Return the eps value for each class.
573    *
574    * @return Returns the eps array.
575    */
576   public double[] getEps() {
577     return eps;
578   }
579 
580   /**
581    * Return the Rmin value for each class.
582    *
583    * @return Returns the Rmin array.
584    */
585   public double[] getRmin() {
586     return rMin;
587   }
588 
589   /**
590    * Getter for the field <code>scale14</code>.
591    *
592    * @return a double.
593    */
594   public double getScale14() {
595     return scale14;
596   }
597 
598   /**
599    * rhoDisp1.
600    *
601    * @param rho a double.
602    * @return a double.
603    */
604   double rhoDisp1(double rho) {
605     return vdwPowers.rhoDisp1(rho);
606   }
607 
608   /**
609    * rhoDelta1.
610    *
611    * @param rhoDelta a double.
612    * @return a double.
613    */
614   double rhoDelta1(double rhoDelta) {
615     return vdwPowers.rhoDisp1(rhoDelta);
616   }
617 
618   /**
619    * Softcore vdW partial derivatives that are different between LJ and B14-7.
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    * LJ softcore vdW partial derivatives.
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    * Buffered 14-7 softcore vdW partial derivatives.
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 }