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.openmm;
39  
40  import com.sun.jna.ptr.DoubleByReference;
41  import com.sun.jna.ptr.IntByReference;
42  
43  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True;
44  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_addException;
45  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_addParticle;
46  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_create;
47  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_createExceptionsFromBonds;
48  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_destroy;
49  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_getCutoffDistance;
50  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_getExceptionParameters;
51  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_getNumExceptions;
52  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_getNumParticles;
53  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_getParticleParameters;
54  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setCutoffDistance;
55  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setExceptionParameters;
56  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setNonbondedMethod;
57  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setPMEParameters;
58  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setParticleParameters;
59  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setSwitchingDistance;
60  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setUseDispersionCorrection;
61  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_setUseSwitchingFunction;
62  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_updateParametersInContext;
63  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_NonbondedForce_usesPeriodicBoundaryConditions;
64  
65  /**
66   * This class implements nonbonded interactions between particles, including a Coulomb force to represent
67   * electrostatics and a Lennard-Jones force to represent van der Waals interactions. It optionally supports
68   * periodic boundary conditions and cutoffs for long range interactions. Lennard-Jones interactions are
69   * calculated with the Lorentz-Berthelot combining rule: it uses the arithmetic mean of the sigmas and the
70   * geometric mean of the epsilons for the two interacting particles.
71   * <p>
72   * To use this class, create a NonbondedForce object, then call addParticle() once for each particle in the
73   * System to define its parameters. The number of particles for which you define nonbonded parameters must
74   * be exactly equal to the number of particles in the System, or else an exception will be thrown when you
75   * try to create a Context. After a particle has been added, you can modify its force field parameters
76   * by calling setParticleParameters(). This will have no effect on Contexts that already exist unless you
77   * call updateParametersInContext().
78   * <p>
79   * NonbondedForce also lets you specify "exceptions", particular pairs of particles whose interactions should be
80   * computed based on different parameters than those defined for the individual particles. This can be used to
81   * completely exclude certain interactions from the force calculation, or to alter how they interact with each other.
82   * <p>
83   * Many molecular force fields omit Coulomb and Lennard-Jones interactions between particles separated by one
84   * or two bonds, while using modified parameters for those separated by three bonds (known as "1-4 interactions").
85   * This class provides a convenience method for this case called createExceptionsFromBonds(). You pass to it
86   * a list of bonds and the scale factors to use for 1-4 interactions. It identifies all pairs of particles which
87   * are separated by 1, 2, or 3 bonds, then automatically creates exceptions for them.
88   * <p>
89   * When using a cutoff, by default Lennard-Jones interactions are sharply truncated at the cutoff distance.
90   * Optionally you can instead use a switching function to make the interaction smoothly go to zero over a finite
91   * distance range. To enable this, call setUseSwitchingFunction(). You must also call setSwitchingDistance()
92   * to specify the distance at which the interaction should begin to decrease. The switching distance must be
93   * less than the cutoff distance.
94   * <p>
95   * Another optional feature of this class (enabled by default) is to add a contribution to the energy which approximates
96   * the effect of all Lennard-Jones interactions beyond the cutoff in a periodic system. When running a simulation
97   * at constant pressure, this can improve the quality of the result. Call setUseDispersionCorrection() to set whether
98   * this should be used.
99   * <p>
100  * In some applications, it is useful to be able to inexpensively change the parameters of small groups of particles.
101  * Usually this is done to interpolate between two sets of parameters. For example, a titratable group might have
102  * two states it can exist in, each described by a different set of parameters for the atoms that make up the
103  * group. You might then want to smoothly interpolate between the two states. This is done by first calling
104  * addGlobalParameter() to define a Context parameter, then addParticleParameterOffset() to create a "parameter offset"
105  * that depends on the Context parameter. Each offset defines the following:
106  * <ul>
107  * <li>A Context parameter used to interpolate between the states.</li>
108  * <li>A single particle whose parameters are influenced by the Context parameter.</li>
109  * <li>Three scale factors (chargeScale, sigmaScale, and epsilonScale) that specify how the Context parameter
110  * affects the particle.</li>
111  * </ul>
112  * <p>
113  * The "effective" parameters for a particle (those used to compute forces) are given by
114  * <pre>{@code
115  * charge = baseCharge + param*chargeScale
116  * sigma = baseSigma + param*sigmaScale
117  * epsilon = baseEpsilon + param*epsilonScale
118  * }</pre>
119  * where the "base" values are the ones specified by addParticle() and "param" is the current value
120  * of the Context parameter. A single Context parameter can apply offsets to multiple particles,
121  * and multiple parameters can be used to apply offsets to the same particle. Parameters can also be used
122  * to modify exceptions in exactly the same way by calling addExceptionParameterOffset().
123  */
124 public class NonbondedForce extends Force {
125 
126   /**
127    * Create a new NonbondedForce.
128    */
129   public NonbondedForce() {
130     super(OpenMM_NonbondedForce_create());
131   }
132 
133   /**
134    * Add an exception to the force.
135    *
136    * @param particle1  The index of the first particle.
137    * @param particle2  The index of the second particle.
138    * @param chargeProd The charge product.
139    * @param sigma      The sigma vdW parameter.
140    * @param epsilon    The epsilon vdW parameter.
141    * @param replace    If true, replace any existing exception.
142    * @return The index of the exception that was added.
143    */
144   public int addException(int particle1, int particle2, double chargeProd, double sigma, double epsilon, boolean replace) {
145     return OpenMM_NonbondedForce_addException(pointer, particle1, particle2, chargeProd, sigma, epsilon, replace ? 1 : 0);
146   }
147 
148   /**
149    * Add a particle.
150    *
151    * @param charge The atomic charge.
152    * @param sigma  The vdW sigma.
153    * @param eps    The vdW eps.
154    * @return The index of the particle that was added.
155    */
156   public int addParticle(double charge, double sigma, double eps) {
157     return OpenMM_NonbondedForce_addParticle(pointer, charge, sigma, eps);
158   }
159 
160   /**
161    * Create exceptions from bonds.
162    *
163    * @param bondArray      The bond array.
164    * @param coulomb14Scale The coulomb 1-4 scale.
165    * @param lj14Scale      The LJ 1-4 scale.
166    */
167   public void createExceptionsFromBonds(BondArray bondArray, double coulomb14Scale, double lj14Scale) {
168     OpenMM_NonbondedForce_createExceptionsFromBonds(pointer, bondArray.getPointer(), coulomb14Scale, lj14Scale);
169   }
170 
171   /**
172    * Destroy the force.
173    */
174   @Override
175   public void destroy() {
176     if (pointer != null) {
177       OpenMM_NonbondedForce_destroy(pointer);
178       pointer = null;
179     }
180   }
181 
182   /**
183    * Get the cutoff distance.
184    *
185    * @return The cutoff distance.
186    */
187   public double getCutoffDistance() {
188     return OpenMM_NonbondedForce_getCutoffDistance(pointer);
189   }
190 
191   /**
192    * Get the exception parameters.
193    *
194    * @param index      The exception index.
195    * @param particle1  The first particle.
196    * @param particle2  The second particle.
197    * @param chargeProd The charge product.
198    * @param sigma      The sigma vdW parameter.
199    * @param eps        The eps vdW parameter.
200    */
201   public void getExceptionParameters(int index, IntByReference particle1, IntByReference particle2,
202                                      DoubleByReference chargeProd, DoubleByReference sigma, DoubleByReference eps) {
203     OpenMM_NonbondedForce_getExceptionParameters(pointer, index, particle1, particle2, chargeProd, sigma, eps);
204   }
205 
206   /**
207    * Get the number of exceptions.
208    *
209    * @return The number of exceptions.
210    */
211   public int getNumExceptions() {
212     return OpenMM_NonbondedForce_getNumExceptions(pointer);
213   }
214 
215   /**
216    * Get the number of particles.
217    *
218    * @return The number of particles.
219    */
220   public int getNumParticles() {
221     return OpenMM_NonbondedForce_getNumParticles(pointer);
222   }
223 
224   /**
225    * Get the particle parameters.
226    *
227    * @param index  The particle index.
228    * @param charge The atomic charge.
229    * @param sigma  The vdW sigma.
230    * @param eps    The vdW eps.
231    */
232   public void getParticleParameters(int index, DoubleByReference charge, DoubleByReference sigma, DoubleByReference eps) {
233     OpenMM_NonbondedForce_getParticleParameters(pointer, index, charge, sigma, eps);
234   }
235 
236   /**
237    * Set the cutoff distance.
238    *
239    * @param cutoffDistance The cutoff distance.
240    */
241   public void setCutoffDistance(double cutoffDistance) {
242     OpenMM_NonbondedForce_setCutoffDistance(pointer, cutoffDistance);
243   }
244 
245   /**
246    * Set the exception parameters.
247    *
248    * @param index      The exception index.
249    * @param particle1  The first particle.
250    * @param particle2  The second particle.
251    * @param chargeProd The charge product.
252    * @param sigma      The sigma vdW parameter.
253    * @param eps        The eps vdW parameter.
254    */
255   public void setExceptionParameters(int index, int particle1, int particle2, double chargeProd, double sigma, double eps) {
256     OpenMM_NonbondedForce_setExceptionParameters(pointer, index, particle1, particle2, chargeProd, sigma, eps);
257   }
258 
259   /**
260    * Set the nonbonded method.
261    *
262    * @param method The nonbonded method.
263    */
264   public void setNonbondedMethod(int method) {
265     OpenMM_NonbondedForce_setNonbondedMethod(pointer, method);
266   }
267 
268   /**
269    * Set the PME parameters.
270    *
271    * @param aEwald The Ewald alpha.
272    * @param nx     The PME grid size in x.
273    * @param ny     The PME grid size in y.
274    * @param nz     The PME grid size in z.
275    */
276   public void setPMEParameters(double aEwald, int nx, int ny, int nz) {
277     OpenMM_NonbondedForce_setPMEParameters(pointer, aEwald, nx, ny, nz);
278   }
279 
280   /**
281    * Set the particle parameters.
282    *
283    * @param index  The particle index.
284    * @param charge The atomic charge.
285    * @param sigma  The vdW sigma.
286    * @param eps    The vdW eps.
287    */
288   public void setParticleParameters(int index, double charge, double sigma, double eps) {
289     OpenMM_NonbondedForce_setParticleParameters(pointer, index, charge, sigma, eps);
290   }
291 
292   /**
293    * Set the switching distance.
294    *
295    * @param switchingDistance The switching distance.
296    */
297   public void setSwitchingDistance(double switchingDistance) {
298     OpenMM_NonbondedForce_setSwitchingDistance(pointer, switchingDistance);
299   }
300 
301   /**
302    * Set if a dispersion correction will be used.
303    *
304    * @param useDispersionCorrection The dispersion correction flag.
305    */
306   public void setUseDispersionCorrection(int useDispersionCorrection) {
307     OpenMM_NonbondedForce_setUseDispersionCorrection(pointer, useDispersionCorrection);
308   }
309 
310   /**
311    * Set if a switching function will be used.
312    *
313    * @param useSwitchingFunction The switching distance flag.
314    */
315   public void setUseSwitchingFunction(int useSwitchingFunction) {
316     OpenMM_NonbondedForce_setUseSwitchingFunction(pointer, useSwitchingFunction);
317   }
318 
319   /**
320    * Update the parameters in the context.
321    *
322    * @param context The context.
323    */
324   public void updateParametersInContext(Context context) {
325     if (context.hasContextPointer()) {
326       OpenMM_NonbondedForce_updateParametersInContext(pointer, context.getPointer());
327     }
328   }
329 
330   /**
331    * Check if the force uses periodic boundary conditions.
332    *
333    * @return True if the force uses periodic boundary conditions.
334    */
335   @Override
336   public boolean usesPeriodicBoundaryConditions() {
337     int pbc = OpenMM_NonbondedForce_usesPeriodicBoundaryConditions(pointer);
338     return pbc == OpenMM_True;
339   }
340 }