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 }