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  import com.sun.jna.ptr.PointerByReference;
43  
44  import java.nio.IntBuffer;
45  
46  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True;
47  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_addEnergyParameterDerivative;
48  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_addGlobalParameter;
49  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_addPerTorsionParameter;
50  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_addTorsion;
51  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_create;
52  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_destroy;
53  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getEnergyFunction;
54  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getEnergyParameterDerivativeName;
55  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getGlobalParameterDefaultValue;
56  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getGlobalParameterName;
57  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getNumEnergyParameterDerivatives;
58  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getNumGlobalParameters;
59  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getNumPerTorsionParameters;
60  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getNumTorsions;
61  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getPerTorsionParameterName;
62  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_getTorsionParameters;
63  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_setEnergyFunction;
64  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_setGlobalParameterDefaultValue;
65  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_setGlobalParameterName;
66  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_setPerTorsionParameterName;
67  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_setTorsionParameters;
68  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_setUsesPeriodicBoundaryConditions;
69  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_updateParametersInContext;
70  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomTorsionForce_usesPeriodicBoundaryConditions;
71  
72  /**
73   * This class implements interactions between sets of four particles that depend on the torsion angle between them.
74   * Unlike PeriodicTorsionForce, the functional form of the interaction is completely customizable, and may
75   * involve arbitrary algebraic expressions.  In addition to the angle formed by the particles, it may depend
76   * on arbitrary global and per-torsion parameters.
77   *
78   * <p>To use this class, create a CustomTorsionForce object, passing an algebraic expression to the constructor
79   * that defines the interaction energy between each set of particles.  The expression may depend on theta, the torsion angle
80   * formed by the particles, as well as on any parameters you choose.  Then call addPerTorsionParameter() to define per-torsion
81   * parameters, and addGlobalParameter() to define global parameters.  The values of per-torsion parameters are specified as
82   * part of the system definition, while values of global parameters may be modified during a simulation by calling Context::setParameter().
83   * Finally, call addTorsion() once for each torsion.  After an torsion has been added, you can modify its parameters by calling setTorsionParameters().
84   * This will have no effect on Contexts that already exist unless you call updateParametersInContext().
85   * Note that theta is guaranteed to be in the range [-pi,+pi], which may cause issues with force discontinuities if the energy function does not respect this domain.
86   *
87   * <p>As an example, the following code creates a CustomTorsionForce that implements a periodic potential:
88   *
89   * <pre>{@code
90   * CustomTorsionForce force = new CustomTorsionForce("0.5*k*(1-cos(theta-theta0))");
91   * }</pre>
92   *
93   * <p>This force depends on two parameters: the spring constant k and equilibrium angle theta0.  The following code defines these parameters:
94   *
95   * <pre>{@code
96   * force.addPerTorsionParameter("k");
97   * force.addPerTorsionParameter("theta0");
98   * }</pre>
99   *
100  * <p>If a harmonic restraint is desired, it is important to be careful of the domain for theta, using an idiom like this:
101  *
102  * <pre>{@code
103  * CustomTorsionForce force = new CustomTorsionForce("0.5*k*min(dtheta, 2*pi-dtheta)^2; dtheta = abs(theta-theta0); pi = 3.1415926535");
104  * }</pre>
105  *
106  * <p>This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
107  * Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
108  * computed.  You can then query its value in a Context by calling getState() on it.
109  *
110  * <p>Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following
111  * 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
112  * are defined in radians, and log is the natural logarithm.  step(x) = 0 if x &lt; 0, 1 otherwise.  delta(x) = 1 if x = 0, 0 otherwise.
113  * select(x,y,z) = z if x = 0, y otherwise.
114  */
115 public class CustomTorsionForce extends Force {
116 
117   /**
118    * Create a CustomTorsionForce.
119    *
120    * @param energy The algebraic expression that gives the interaction energy of each torsion as a function of theta, the torsion angle.
121    */
122   public CustomTorsionForce(String energy) {
123     super(OpenMM_CustomTorsionForce_create(energy));
124   }
125 
126   /**
127    * Request that this Force compute the derivative of its energy with respect to a global parameter.
128    *
129    * @param name The name of the parameter.
130    */
131   public void addEnergyParameterDerivative(String name) {
132     OpenMM_CustomTorsionForce_addEnergyParameterDerivative(pointer, name);
133   }
134 
135   /**
136    * Request that this Force compute the derivative of its energy with respect to a global parameter.
137    *
138    * @param name The name of the parameter.
139    */
140   public void addEnergyParameterDerivative(Pointer name) {
141     OpenMM_CustomTorsionForce_addEnergyParameterDerivative(pointer, name);
142   }
143 
144   /**
145    * Add a new global parameter that the interaction may depend on.
146    *
147    * @param name         The name of the parameter.
148    * @param defaultValue The default value of the parameter.
149    * @return The index of the parameter that was added.
150    */
151   public int addGlobalParameter(String name, double defaultValue) {
152     return OpenMM_CustomTorsionForce_addGlobalParameter(pointer, name, defaultValue);
153   }
154 
155   /**
156    * Add a new global parameter that the interaction may depend on.
157    *
158    * @param name         The name of the parameter.
159    * @param defaultValue The default value of the parameter.
160    * @return The index of the parameter that was added.
161    */
162   public int addGlobalParameter(Pointer name, double defaultValue) {
163     return OpenMM_CustomTorsionForce_addGlobalParameter(pointer, name, defaultValue);
164   }
165 
166   /**
167    * Add a new per-torsion parameter that the interaction may depend on.
168    *
169    * @param name The name of the parameter.
170    * @return The index of the parameter that was added.
171    */
172   public int addPerTorsionParameter(String name) {
173     return OpenMM_CustomTorsionForce_addPerTorsionParameter(pointer, name);
174   }
175 
176   /**
177    * Add a new per-torsion parameter that the interaction may depend on.
178    *
179    * @param name The name of the parameter.
180    * @return The index of the parameter that was added.
181    */
182   public int addPerTorsionParameter(Pointer name) {
183     return OpenMM_CustomTorsionForce_addPerTorsionParameter(pointer, name);
184   }
185 
186   /**
187    * Add a torsion to the Force.
188    *
189    * @param particle1  The index of the first particle forming the torsion.
190    * @param particle2  The index of the second particle forming the torsion.
191    * @param particle3  The index of the third particle forming the torsion.
192    * @param particle4  The index of the fourth particle forming the torsion.
193    * @param parameters The list of parameters for the new torsion.
194    * @return The index of the torsion that was added.
195    */
196   public int addTorsion(int particle1, int particle2, int particle3, int particle4, PointerByReference parameters) {
197     return OpenMM_CustomTorsionForce_addTorsion(pointer, particle1, particle2, particle3, particle4, parameters);
198   }
199 
200   /**
201    * Destroy the force.
202    */
203   @Override
204   public void destroy() {
205     if (pointer != null) {
206       OpenMM_CustomTorsionForce_destroy(pointer);
207       pointer = null;
208     }
209   }
210 
211   /**
212    * Get the algebraic expression that gives the interaction energy of each torsion.
213    *
214    * @return The energy expression.
215    */
216   public String getEnergyFunction() {
217     Pointer p = OpenMM_CustomTorsionForce_getEnergyFunction(pointer);
218     if (p == null) {
219       return null;
220     }
221     return p.getString(0);
222   }
223 
224   /**
225    * Get the name of a parameter with respect to which the derivative of the energy should be computed.
226    *
227    * @param index The index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives().
228    * @return The parameter name.
229    */
230   public String getEnergyParameterDerivativeName(int index) {
231     Pointer p = OpenMM_CustomTorsionForce_getEnergyParameterDerivativeName(pointer, index);
232     if (p == null) {
233       return null;
234     }
235     return p.getString(0);
236   }
237 
238   /**
239    * Get the default value of a global parameter.
240    *
241    * @param index The index of the parameter for which to get the default value.
242    * @return The parameter default value.
243    */
244   public double getGlobalParameterDefaultValue(int index) {
245     return OpenMM_CustomTorsionForce_getGlobalParameterDefaultValue(pointer, index);
246   }
247 
248   /**
249    * Get the name of a global parameter.
250    *
251    * @param index The index of the parameter for which to get the name.
252    * @return The parameter name.
253    */
254   public String getGlobalParameterName(int index) {
255     Pointer p = OpenMM_CustomTorsionForce_getGlobalParameterName(pointer, index);
256     if (p == null) {
257       return null;
258     }
259     return p.getString(0);
260   }
261 
262   /**
263    * Get the number of parameters with respect to which the derivative of the energy should be computed.
264    *
265    * @return The number of parameters.
266    */
267   public int getNumEnergyParameterDerivatives() {
268     return OpenMM_CustomTorsionForce_getNumEnergyParameterDerivatives(pointer);
269   }
270 
271   /**
272    * Get the number of global parameters that the interaction depends on.
273    *
274    * @return The number of parameters.
275    */
276   public int getNumGlobalParameters() {
277     return OpenMM_CustomTorsionForce_getNumGlobalParameters(pointer);
278   }
279 
280   /**
281    * Get the number of per-torsion parameters that the interaction depends on.
282    *
283    * @return The number of parameters.
284    */
285   public int getNumPerTorsionParameters() {
286     return OpenMM_CustomTorsionForce_getNumPerTorsionParameters(pointer);
287   }
288 
289   /**
290    * Get the number of torsions for which force field parameters have been defined.
291    *
292    * @return The number of torsions.
293    */
294   public int getNumTorsions() {
295     return OpenMM_CustomTorsionForce_getNumTorsions(pointer);
296   }
297 
298   /**
299    * Get the name of a per-torsion parameter.
300    *
301    * @param index The index of the parameter for which to get the name.
302    * @return The parameter name.
303    */
304   public String getPerTorsionParameterName(int index) {
305     Pointer p = OpenMM_CustomTorsionForce_getPerTorsionParameterName(pointer, index);
306     if (p == null) {
307       return null;
308     }
309     return p.getString(0);
310   }
311 
312   /**
313    * Get the force field parameters for a torsion.
314    *
315    * @param index      The index of the torsion for which to get parameters.
316    * @param particle1  The index of the first particle forming the torsion (output).
317    * @param particle2  The index of the second particle forming the torsion (output).
318    * @param particle3  The index of the third particle forming the torsion (output).
319    * @param particle4  The index of the fourth particle forming the torsion (output).
320    * @param parameters The list of parameters (output).
321    */
322   public void getTorsionParameters(int index, IntByReference particle1, IntByReference particle2,
323                                    IntByReference particle3, IntByReference particle4, PointerByReference parameters) {
324     OpenMM_CustomTorsionForce_getTorsionParameters(pointer, index, particle1, particle2, particle3, particle4, parameters);
325   }
326 
327   /**
328    * Get the force field parameters for a torsion.
329    *
330    * @param index      The index of the torsion for which to get parameters.
331    * @param particle1  The index of the first particle forming the torsion (output).
332    * @param particle2  The index of the second particle forming the torsion (output).
333    * @param particle3  The index of the third particle forming the torsion (output).
334    * @param particle4  The index of the fourth particle forming the torsion (output).
335    * @param parameters The list of parameters (output).
336    */
337   public void getTorsionParameters(int index, IntBuffer particle1, IntBuffer particle2,
338                                    IntBuffer particle3, IntBuffer particle4, PointerByReference parameters) {
339     OpenMM_CustomTorsionForce_getTorsionParameters(pointer, index, particle1, particle2, particle3, particle4, parameters);
340   }
341 
342   /**
343    * Set the algebraic expression that gives the interaction energy of each torsion.
344    *
345    * @param energy The energy expression.
346    */
347   public void setEnergyFunction(String energy) {
348     OpenMM_CustomTorsionForce_setEnergyFunction(pointer, energy);
349   }
350 
351   /**
352    * Set the algebraic expression that gives the interaction energy of each torsion.
353    *
354    * @param energy The energy expression.
355    */
356   public void setEnergyFunction(Pointer energy) {
357     OpenMM_CustomTorsionForce_setEnergyFunction(pointer, energy);
358   }
359 
360   /**
361    * Set the default value of a global parameter.
362    *
363    * @param index        The index of the parameter for which to set the default value.
364    * @param defaultValue The default value of the parameter.
365    */
366   public void setGlobalParameterDefaultValue(int index, double defaultValue) {
367     OpenMM_CustomTorsionForce_setGlobalParameterDefaultValue(pointer, index, defaultValue);
368   }
369 
370   /**
371    * Set the name of a global parameter.
372    *
373    * @param index The index of the parameter for which to set the name.
374    * @param name  The name of the parameter.
375    */
376   public void setGlobalParameterName(int index, String name) {
377     OpenMM_CustomTorsionForce_setGlobalParameterName(pointer, index, name);
378   }
379 
380   /**
381    * Set the name of a global parameter.
382    *
383    * @param index The index of the parameter for which to set the name.
384    * @param name  The name of the parameter.
385    */
386   public void setGlobalParameterName(int index, Pointer name) {
387     OpenMM_CustomTorsionForce_setGlobalParameterName(pointer, index, name);
388   }
389 
390   /**
391    * Set the name of a per-torsion parameter.
392    *
393    * @param index The index of the parameter for which to set the name.
394    * @param name  The name of the parameter.
395    */
396   public void setPerTorsionParameterName(int index, String name) {
397     OpenMM_CustomTorsionForce_setPerTorsionParameterName(pointer, index, name);
398   }
399 
400   /**
401    * Set the name of a per-torsion parameter.
402    *
403    * @param index The index of the parameter for which to set the name.
404    * @param name  The name of the parameter.
405    */
406   public void setPerTorsionParameterName(int index, Pointer name) {
407     OpenMM_CustomTorsionForce_setPerTorsionParameterName(pointer, index, name);
408   }
409 
410   /**
411    * Set the force field parameters for a torsion.
412    *
413    * @param index      The index of the torsion for which to set parameters.
414    * @param particle1  The index of the first particle forming the torsion.
415    * @param particle2  The index of the second particle forming the torsion.
416    * @param particle3  The index of the third particle forming the torsion.
417    * @param particle4  The index of the fourth particle forming the torsion.
418    * @param parameters The list of parameters for the torsion.
419    */
420   public void setTorsionParameters(int index, int particle1, int particle2, int particle3, int particle4, PointerByReference parameters) {
421     OpenMM_CustomTorsionForce_setTorsionParameters(pointer, index, particle1, particle2, particle3, particle4, parameters);
422   }
423 
424   /**
425    * Set whether this force should apply periodic boundary conditions when calculating displacements.
426    *
427    * @param periodic If true, periodic boundary conditions will be applied.
428    */
429   public void setUsesPeriodicBoundaryConditions(boolean periodic) {
430     OpenMM_CustomTorsionForce_setUsesPeriodicBoundaryConditions(pointer, periodic ? 1 : 0);
431   }
432 
433   /**
434    * Update the per-torsion parameters in a Context to match those stored in this Force object.
435    *
436    * @param context The Context in which to update the parameters.
437    */
438   public void updateParametersInContext(Context context) {
439     if (context.hasContextPointer()) {
440       OpenMM_CustomTorsionForce_updateParametersInContext(pointer, context.getPointer());
441     }
442   }
443 
444   /**
445    * Check if the force uses periodic boundary conditions.
446    *
447    * @return True if the force uses periodic boundary conditions.
448    */
449   @Override
450   public boolean usesPeriodicBoundaryConditions() {
451     int pbc = OpenMM_CustomTorsionForce_usesPeriodicBoundaryConditions(pointer);
452     return pbc == OpenMM_True;
453   }
454 }