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.Pointer;
41  import com.sun.jna.ptr.IntByReference;
42  
43  import java.nio.IntBuffer;
44  
45  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True;
46  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addBond;
47  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addEnergyParameterDerivative;
48  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addGlobalParameter;
49  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addPerBondParameter;
50  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_create;
51  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_destroy;
52  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getBondParameters;
53  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getEnergyFunction;
54  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getEnergyParameterDerivativeName;
55  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getGlobalParameterDefaultValue;
56  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getGlobalParameterName;
57  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumBonds;
58  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumEnergyParameterDerivatives;
59  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumGlobalParameters;
60  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumPerBondParameters;
61  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getPerBondParameterName;
62  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setBondParameters;
63  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setEnergyFunction;
64  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setGlobalParameterDefaultValue;
65  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setGlobalParameterName;
66  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setPerBondParameterName;
67  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setUsesPeriodicBoundaryConditions;
68  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_updateParametersInContext;
69  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_usesPeriodicBoundaryConditions;
70  
71  /**
72   * This class implements bonded interactions between pairs of particles. Unlike HarmonicBondForce, the functional form
73   * of the interaction is completely customizable, and may involve arbitrary algebraic expressions.
74   * It may depend on the distance between particles, as well as on arbitrary global and
75   * per-bond parameters.
76   * <p>
77   * To use this class, create a CustomBondForce object, passing an algebraic expression to the constructor
78   * that defines the interaction energy between each pair of bonded particles. The expression may depend on r, the distance
79   * between the particles, as well as on any parameters you choose. Then call addPerBondParameter() to define per-bond
80   * parameters, and addGlobalParameter() to define global parameters. The values of per-bond parameters are specified as
81   * part of the system definition, while values of global parameters may be modified during a simulation by calling Context::setParameter().
82   * Finally, call addBond() once for each bond. After a bond has been added, you can modify its parameters by calling setBondParameters().
83   * This will have no effect on Contexts that already exist unless you call updateParametersInContext().
84   * <p>
85   * As an example, the following code creates a CustomBondForce that implements a harmonic potential:
86   * <p>
87   * &lt;pre&gt;
88   * {@code
89   * CustomBondForce force = new CustomBondForce("0.5*k*(r-r0)^2");
90   * }
91   * &lt;/pre&gt;
92   * <p>
93   * This force depends on two parameters: the spring constant k and equilibrium distance r0. The following code defines these parameters:
94   * <p>
95   * &lt;pre&gt;
96   * {@code
97   * force.addPerBondParameter("k");
98   * force.addPerBondParameter("r0");
99   * }
100  * &lt;/pre&gt;
101  * <p>
102  * This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
103  * Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
104  * computed. You can then query its value in a Context by calling getState() on it.
105  * <p>
106  * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following
107  * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, atan2, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
108  * are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. delta(x) = 1 if x is 0, 0 otherwise.
109  * select(x,y,z) = z if x = 0, y otherwise.
110  */
111 public class CustomBondForce extends Force {
112 
113   /**
114    * Create a CustomBondForce.
115    *
116    * @param energy an algebraic expression giving the interaction energy between two bonded particles as a function
117    *               of r, the distance between them
118    */
119   public CustomBondForce(String energy) {
120     super(OpenMM_CustomBondForce_create(energy));
121   }
122 
123   /**
124    * Add a bond term to the force field.
125    *
126    * @param i1         the index of the first particle connected by the bond
127    * @param i2         the index of the second particle connected by the bond
128    * @param parameters the list of parameters for the new bond
129    * @return the index of the bond that was added
130    */
131   public int addBond(int i1, int i2, DoubleArray parameters) {
132     return OpenMM_CustomBondForce_addBond(pointer, i1, i2, parameters.getPointer());
133   }
134 
135   /**
136    * Request that this Force compute the derivative of its energy with respect to a global parameter.
137    * The parameter must have already been added with addGlobalParameter().
138    *
139    * @param name the name of the parameter
140    */
141   public void addEnergyParameterDerivative(String name) {
142     OpenMM_CustomBondForce_addEnergyParameterDerivative(pointer, name);
143   }
144 
145   /**
146    * Add a new global parameter that the interaction may depend on. The default value provided to
147    * this method is the initial value of the parameter in newly created Contexts. You can change
148    * the value at any time by calling setParameter() on the Context.
149    *
150    * @param name  the name of the parameter
151    * @param value the default value of the parameter
152    * @return the index of the parameter that was added
153    */
154   public int addGlobalParameter(String name, double value) {
155     return OpenMM_CustomBondForce_addGlobalParameter(pointer, name, value);
156   }
157 
158   /**
159    * Add a new per-bond parameter that the interaction may depend on.
160    *
161    * @param name the name of the parameter
162    * @return the index of the parameter that was added
163    */
164   public int addPerBondParameter(String name) {
165     return OpenMM_CustomBondForce_addPerBondParameter(pointer, name);
166   }
167 
168   /**
169    * Destroy the OpenMM CustomBondForce.
170    */
171   @Override
172   public void destroy() {
173     if (pointer != null) {
174       OpenMM_CustomBondForce_destroy(pointer);
175       pointer = null;
176     }
177   }
178 
179   /**
180    * Get the force field parameters for a bond term.
181    *
182    * @param index      the index of the bond for which to get parameters
183    * @param i1         the index of the first particle connected by the bond
184    * @param i2         the index of the second particle connected by the bond
185    * @param parameters the list of parameters for the bond
186    */
187   public void getBondParameters(int index, IntBuffer i1, IntBuffer i2, DoubleArray parameters) {
188     OpenMM_CustomBondForce_getBondParameters(pointer, index, i1, i2, parameters.getPointer());
189   }
190 
191   /**
192    * Get the force field parameters for a bond term.
193    *
194    * @param index      the index of the bond for which to get parameters
195    * @param i1         the index of the first particle connected by the bond
196    * @param i2         the index of the second particle connected by the bond
197    * @param parameters the list of parameters for the bond
198    */
199   public void getBondParameters(int index, IntByReference i1, IntByReference i2, DoubleArray parameters) {
200     OpenMM_CustomBondForce_getBondParameters(pointer, index, i1, i2, parameters.getPointer());
201   }
202 
203   /**
204    * Get the algebraic expression that gives the interaction energy for each bond
205    *
206    * @return the energy function expression
207    */
208   public String getEnergyFunction() {
209     Pointer p = OpenMM_CustomBondForce_getEnergyFunction(pointer);
210     if (p == null) {
211       return null;
212     }
213     return p.getString(0);
214   }
215 
216   /**
217    * Get the name of a global parameter with respect to which this Force should compute the
218    * derivative of the energy.
219    *
220    * @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
221    * @return the parameter name
222    */
223   public String getEnergyParameterDerivativeName(int index) {
224     Pointer p = OpenMM_CustomBondForce_getEnergyParameterDerivativeName(pointer, index);
225     if (p == null) {
226       return null;
227     }
228     return p.getString(0);
229   }
230 
231   /**
232    * Get the default value of a global parameter.
233    *
234    * @param index The index of the parameter.
235    * @return The default value of the parameter.
236    */
237   public double getGlobalParameterDefaultValue(int index) {
238     return OpenMM_CustomBondForce_getGlobalParameterDefaultValue(pointer, index);
239   }
240 
241   /**
242    * Get the name of a global parameter.
243    *
244    * @param index The index of the parameter.
245    * @return The name of the parameter.
246    */
247   public String getGlobalParameterName(int index) {
248     Pointer p = OpenMM_CustomBondForce_getGlobalParameterName(pointer, index);
249     if (p == null) {
250       return null;
251     }
252     return p.getString(0);
253   }
254 
255   /**
256    * Get the number of bonds for which force field parameters have been defined.
257    *
258    * @return the number of bonds
259    */
260   public int getNumBonds() {
261     return OpenMM_CustomBondForce_getNumBonds(pointer);
262   }
263 
264   /**
265    * Get the number of parameters with respect to which the derivative of the energy should be computed.
266    *
267    * @return The number of parameters.
268    */
269   public int getNumEnergyParameterDerivatives() {
270     return OpenMM_CustomBondForce_getNumEnergyParameterDerivatives(pointer);
271   }
272 
273   /**
274    * Get the number of global parameters.
275    *
276    * @return The number of global parameters.
277    */
278   public int getNumGlobalParameters() {
279     return OpenMM_CustomBondForce_getNumGlobalParameters(pointer);
280   }
281 
282   /**
283    * Get the number of per-bond parameters.
284    *
285    * @return The number of per-bond parameters.
286    */
287   public int getNumPerBondParameters() {
288     return OpenMM_CustomBondForce_getNumPerBondParameters(pointer);
289   }
290 
291   /**
292    * Get the name of a per-bond parameter.
293    *
294    * @param index The index of the parameter.
295    * @return The name of the parameter.
296    */
297   public String getPerBondParameterName(int index) {
298     Pointer p = OpenMM_CustomBondForce_getPerBondParameterName(pointer, index);
299     if (p == null) {
300       return null;
301     }
302     return p.getString(0);
303   }
304 
305   /**
306    * Set the parameters for one bond in the OpenMM System.
307    *
308    * @param index      The index of the bond.
309    * @param i1         The index of the first atom.
310    * @param i2         The index of the second atom.
311    * @param parameters The bond parameters.
312    */
313   public void setBondParameters(int index, int i1, int i2, DoubleArray parameters) {
314     OpenMM_CustomBondForce_setBondParameters(pointer, index, i1, i2, parameters.getPointer());
315   }
316 
317   /**
318    * Set the energy function expression.
319    *
320    * @param energy The energy function expression.
321    */
322   public void setEnergyFunction(String energy) {
323     OpenMM_CustomBondForce_setEnergyFunction(pointer, energy);
324   }
325 
326   /**
327    * Set the default value of a global parameter.
328    *
329    * @param index The index of the parameter.
330    * @param value The default value of the parameter.
331    */
332   public void setGlobalParameterDefaultValue(int index, double value) {
333     OpenMM_CustomBondForce_setGlobalParameterDefaultValue(pointer, index, value);
334   }
335 
336   /**
337    * Set the name of a global parameter.
338    *
339    * @param index The index of the parameter.
340    * @param name  The name of the parameter.
341    */
342   public void setGlobalParameterName(int index, String name) {
343     OpenMM_CustomBondForce_setGlobalParameterName(pointer, index, name);
344   }
345 
346   /**
347    * Set the name of a per-bond parameter.
348    *
349    * @param index The index of the parameter.
350    * @param name  The name of the parameter.
351    */
352   public void setPerBondParameterName(int index, String name) {
353     OpenMM_CustomBondForce_setPerBondParameterName(pointer, index, name);
354   }
355 
356   /**
357    * Set whether this force uses periodic boundary conditions.
358    *
359    * @param periodic If true, periodic boundary conditions will be used.
360    */
361   public void setUsesPeriodicBoundaryConditions(boolean periodic) {
362     OpenMM_CustomBondForce_setUsesPeriodicBoundaryConditions(pointer, periodic ? 1 : 0);
363   }
364 
365   /**
366    * Update the parameters in the OpenMM Context.
367    *
368    * @param context The OpenMM Context.
369    */
370   public void updateParametersInContext(Context context) {
371     if (context.hasContextPointer()) {
372       OpenMM_CustomBondForce_updateParametersInContext(pointer, context.getPointer());
373     }
374   }
375 
376   /**
377    * Check if the force uses periodic boundary conditions.
378    *
379    * @return True if the force uses periodic boundary conditions.
380    */
381   @Override
382   public boolean usesPeriodicBoundaryConditions() {
383     int pbc = OpenMM_CustomBondForce_usesPeriodicBoundaryConditions(pointer);
384     return pbc == OpenMM_True;
385   }
386 }