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 static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True;
41  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_addBond;
42  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_addEnergyParameterDerivative;
43  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_addGlobalParameter;
44  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_addGroup;
45  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_addPerBondParameter;
46  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_create;
47  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_destroy;
48  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getBondParameters;
49  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getEnergyFunction;
50  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getEnergyParameterDerivativeName;
51  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getGlobalParameterDefaultValue;
52  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getGlobalParameterName;
53  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getGroupParameters;
54  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumBonds;
55  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumEnergyParameterDerivatives;
56  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumFunctions;
57  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumGlobalParameters;
58  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumGroups;
59  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumGroupsPerBond;
60  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumPerBondParameters;
61  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getNumTabulatedFunctions;
62  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_getPerBondParameterName;
63  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setBondParameters;
64  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setEnergyFunction;
65  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setGlobalParameterDefaultValue;
66  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setGlobalParameterName;
67  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setGroupParameters;
68  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setPerBondParameterName;
69  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_setUsesPeriodicBoundaryConditions;
70  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_updateParametersInContext;
71  import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCentroidBondForce_usesPeriodicBoundaryConditions;
72  
73  /**
74   * This class is similar to CustomCompoundBondForce, but instead of applying forces between individual particles,
75   * it applies them between the centers of groups of particles.  This is useful for a variety of purposes, such as
76   * restraints to keep two molecules from moving too far apart.
77   * <p>
78   * When using this class, you define groups of particles, and the center of each group is calculated as a weighted
79   * average of the particle positions.  By default, the particle masses are used as weights, so the center position
80   * is the center of mass.  You can optionally specify different weights to use.  You then add bonds just as with
81   * CustomCompoundBondForce, but instead of specifying the particles that make up a bond, you specify the groups.
82   * <p>
83   * When creating a CustomCentroidBondForce, you specify the number of groups involved in a bond, and an expression
84   * for the energy of each bond.  It may depend on the center positions of individual groups, the distances between
85   * the centers of pairs of groups, the angles formed by sets of three groups, and the dihedral angles formed by
86   * sets of four groups.
87   * <p>
88   * We refer to the groups in a bond as g1, g2, g3, etc.  For each bond, CustomCentroidBondForce evaluates a
89   * user supplied algebraic expression to determine the interaction energy.  The expression may depend on the
90   * following variables and functions:
91   *
92   * <ul>
93   * <li>x1, y1, z1, x2, y2, z2, etc.: The x, y, and z coordinates of the centers of the groups.  For example, x1
94   * is the x coordinate of the center of group g1, and y3 is the y coordinate of the center of group g3.</li>
95   * <li>distance(g1, g2): the distance between the centers of groups g1 and g2 (where "g1" and "g2" may be replaced
96   * by the names of whichever groups you want to calculate the distance between).</li>
97   * <li>angle(g1, g2, g3): the angle formed by the centers of the three specified groups.</li>
98   * <li>dihedral(g1, g2, g3, g4): the dihedral angle formed by the centers of the four specified groups.</li>
99   * </ul>
100  * <p>
101  * The expression also may involve tabulated functions, and may depend on arbitrary global and per-bond parameters.
102  * <p>
103  * To use this class, create a CustomCentroidBondForce object, passing an algebraic expression to the constructor
104  * that defines the interaction energy of each bond.  Then call addPerBondParameter() to define per-bond
105  * parameters and addGlobalParameter() to define global parameters.  The values of per-bond parameters are specified
106  * as part of the system definition, while values of global parameters may be modified during a simulation by calling
107  * Context::setParameter().
108  * <p>
109  * Next call addGroup() to define the particle groups.  Each group is specified by the particles it contains, and
110  * the weights to use when computing the center position.
111  * <p>
112  * Then call addBond() to define bonds and specify their parameter values.  After a bond has been added, you can
113  * modify its parameters by calling setBondParameters().  This will have no effect on Contexts that already exist unless
114  * you call updateParametersInContext().
115  * <p>
116  * As an example, the following code creates a CustomCentroidBondForce that implements a harmonic force between the
117  * centers of mass of two groups of particles.
118  *
119  * <pre>
120  *   {@code
121  *    CustomCentroidBondForce* force = new CustomCentroidBondForce(2, "0.5*k*distance(g1,g2)^2");
122  *    force->addPerBondParameter("k");
123  *    force->addGroup(particles1);
124  *    force->addGroup(particles2);
125  *    vector<int> bondGroups;
126  *    bondGroups.push_back(0);
127  *    bondGroups.push_back(1);
128  *    vector<double> bondParameters;
129  *    bondParameters.push_back(k);
130  *    force->addBond(bondGroups, bondParameters);
131  *    }
132  * </pre>
133  * <p>
134  * This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
135  * Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
136  * computed.  You can then query its value in a Context by calling getState() on it.
137  * <p>
138  * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following
139  * 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
140  * 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.
141  * select(x,y,z) = z if x = 0, y otherwise.
142  * <p>
143  * This class also supports the functions pointdistance(x1, y1, z1, x2, y2, z2),
144  * pointangle(x1, y1, z1, x2, y2, z2, x3, y3, z3), and pointdihedral(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4).
145  * These functions are similar to distance(), angle(), and dihedral(), but the arguments are the
146  * coordinates of points to perform the calculation based on rather than the names of groups.
147  * This enables more flexible geometric calculations.  For example, the following computes the distance
148  * from group g1 to the midpoint between groups g2 and g3.
149  *
150  * <pre>
151  *   {@code
152  *    CustomCentroidBondForce* force = new CustomCentroidBondForce(3, "pointdistance(x1, y1, z1, (x2+x3)/2, (y2+y3)/2, (z2+z3)/2)");
153  *   }
154  * </pre>
155  * <p>
156  * In addition, you can call addTabulatedFunction() to define a new function based on tabulated values.  You specify the function by
157  * creating a TabulatedFunction object.  That function can then appear in the expression.
158  */
159 public class CustomCentroidBondForce extends Force {
160 
161   /**
162    * Create a CustomCentroidBondForce.
163    *
164    * @param numGroups the number of groups used to define each bond
165    * @param energy    an algebraic expression giving the interaction energy of each bond as a function
166    *                  of particle positions, inter-particle distances, angles, and dihedrals, and any global
167    *                  and per-bond parameters
168    */
169   public CustomCentroidBondForce(int numGroups, String energy) {
170     pointer = OpenMM_CustomCentroidBondForce_create(numGroups, energy);
171   }
172 
173   /**
174    * Get the number of groups used to define each bond.
175    */
176   public int getNumGroupsPerBond() {
177     return OpenMM_CustomCentroidBondForce_getNumGroupsPerBond(pointer);
178   }
179 
180   /**
181    * Get the number of particle groups that have been defined.
182    */
183   public int getNumGroups() {
184     return OpenMM_CustomCentroidBondForce_getNumGroups(pointer);
185   }
186 
187   /**
188    * Get the number of bonds for which force field parameters have been defined.
189    */
190   public int getNumBonds() {
191     return OpenMM_CustomCentroidBondForce_getNumBonds(pointer);
192   }
193 
194   /**
195    * Get the number of per-bond parameters that the interaction depends on.
196    */
197   public int getNumPerBondParameters() {
198     return OpenMM_CustomCentroidBondForce_getNumPerBondParameters(pointer);
199   }
200 
201   /**
202    * Get the number of global parameters that the interaction depends on.
203    */
204   public int getNumGlobalParameters() {
205     return OpenMM_CustomCentroidBondForce_getNumGlobalParameters(pointer);
206   }
207 
208   /**
209    * Get the number of global parameters with respect to which the derivative of the energy
210    * should be computed.
211    */
212   public int getNumEnergyParameterDerivatives() {
213     return OpenMM_CustomCentroidBondForce_getNumEnergyParameterDerivatives(pointer);
214   }
215 
216   /**
217    * Get the number of tabulated functions that have been defined.
218    */
219   public int getNumTabulatedFunctions() {
220     return OpenMM_CustomCentroidBondForce_getNumTabulatedFunctions(pointer);
221   }
222 
223   /**
224    * Get the number of tabulated functions that have been defined.
225    *
226    * @deprecated This method exists only for backward compatibility.  Use getNumTabulatedFunctions() instead.
227    */
228   @Deprecated
229   public int getNumFunctions() {
230     return OpenMM_CustomCentroidBondForce_getNumFunctions(pointer);
231   }
232 
233   /**
234    * Get the algebraic expression that gives the interaction energy of each bond
235    */
236   public String getEnergyFunction() {
237     return OpenMM_CustomCentroidBondForce_getEnergyFunction(pointer).getString(0);
238   }
239 
240   /**
241    * Set the algebraic expression that gives the interaction energy of each bond
242    */
243   public void setEnergyFunction(String energy) {
244     OpenMM_CustomCentroidBondForce_setEnergyFunction(pointer, energy);
245   }
246 
247   /**
248    * Add a new per-bond parameter that the interaction may depend on.
249    *
250    * @param name the name of the parameter
251    * @return the index of the parameter that was added
252    */
253   public int addPerBondParameter(String name) {
254     return OpenMM_CustomCentroidBondForce_addPerBondParameter(pointer, name);
255   }
256 
257   /**
258    * Get the name of a per-bond parameter.
259    *
260    * @param index the index of the parameter for which to get the name
261    * @return the parameter name
262    */
263   public String getPerBondParameterName(int index) {
264     return OpenMM_CustomCentroidBondForce_getPerBondParameterName(pointer, index).getString(0);
265   }
266 
267   /**
268    * Set the name of a per-bond parameter.
269    *
270    * @param index the index of the parameter for which to set the name
271    * @param name  the name of the parameter
272    */
273   public void setPerBondParameterName(int index, String name) {
274     OpenMM_CustomCentroidBondForce_setPerBondParameterName(pointer, index, name);
275   }
276 
277   /**
278    * Add a new global parameter that the interaction may depend on.  The default value provided to
279    * this method is the initial value of the parameter in newly created Contexts.  You can change
280    * the value at any time by calling setParameter() on the Context.
281    *
282    * @param name         the name of the parameter
283    * @param defaultValue the default value of the parameter
284    * @return the index of the parameter that was added
285    */
286   public int addGlobalParameter(String name, double defaultValue) {
287     return OpenMM_CustomCentroidBondForce_addGlobalParameter(pointer, name, defaultValue);
288   }
289 
290   /**
291    * Get the name of a global parameter.
292    *
293    * @param index the index of the parameter for which to get the name
294    * @return the parameter name
295    */
296   public String getGlobalParameterName(int index) {
297     return OpenMM_CustomCentroidBondForce_getGlobalParameterName(pointer, index).getString(0);
298   }
299 
300   /**
301    * Set the name of a global parameter.
302    *
303    * @param index the index of the parameter for which to set the name
304    * @param name  the name of the parameter
305    */
306   public void setGlobalParameterName(int index, String name) {
307     OpenMM_CustomCentroidBondForce_setGlobalParameterName(pointer, index, name);
308   }
309 
310   /**
311    * Get the default value of a global parameter.
312    *
313    * @param index the index of the parameter for which to get the default value
314    * @return the parameter default value
315    */
316   public double getGlobalParameterDefaultValue(int index) {
317     return OpenMM_CustomCentroidBondForce_getGlobalParameterDefaultValue(pointer, index);
318   }
319 
320   /**
321    * Set the default value of a global parameter.
322    *
323    * @param index        the index of the parameter for which to set the default value
324    * @param defaultValue the default value of the parameter
325    */
326   public void setGlobalParameterDefaultValue(int index, double defaultValue) {
327     OpenMM_CustomCentroidBondForce_setGlobalParameterDefaultValue(pointer, index, defaultValue);
328   }
329 
330   /**
331    * Request that this Force compute the derivative of its energy with respect to a global parameter.
332    * The parameter must have already been added with addGlobalParameter().
333    *
334    * @param name the name of the parameter
335    */
336   public void addEnergyParameterDerivative(String name) {
337     OpenMM_CustomCentroidBondForce_addEnergyParameterDerivative(pointer, name);
338   }
339 
340   /**
341    * Get the name of a global parameter with respect to which this Force should compute the
342    * derivative of the energy.
343    *
344    * @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
345    * @return the parameter name
346    */
347   public String getEnergyParameterDerivativeName(int index) {
348     return OpenMM_CustomCentroidBondForce_getEnergyParameterDerivativeName(pointer, index).getString(0);
349   }
350 
351   /**
352    * Add a particle group.
353    *
354    * @param particles the indices of the particles to include in the group
355    * @param weights   the weight to use for each particle when computing the center position.
356    *                  If this is omitted, then particle masses will be used as weights.
357    * @return the index of the group that was added
358    */
359   public int addGroup(IntArray particles, DoubleArray weights) {
360     return OpenMM_CustomCentroidBondForce_addGroup(pointer, particles.getPointer(), weights.getPointer());
361   }
362 
363   /**
364    * Get the properties of a group.
365    *
366    * @param index     the index of the group to get
367    * @param particles the indices of the particles in the group
368    * @param weights   the weight used for each particle when computing the center position.
369    *                  If no weights were specified, this vector will be empty indicating that particle
370    *                  masses should be used as weights.
371    */
372   public void getGroupParameters(int index, IntArray particles, DoubleArray weights) {
373     OpenMM_CustomCentroidBondForce_getGroupParameters(pointer, index, particles.getPointer(), weights.getPointer());
374   }
375 
376   /**
377    * Set the properties of a group.
378    *
379    * @param index     the index of the group to set
380    * @param particles the indices of the particles in the group
381    * @param weights   the weight to use for each particle when computing the center position.
382    *                  If this is omitted, then particle masses will be used as weights.
383    */
384   public void setGroupParameters(int index, IntArray particles, DoubleArray weights) {
385     OpenMM_CustomCentroidBondForce_setGroupParameters(pointer, index, particles.getPointer(), weights.getPointer());
386   }
387 
388   /**
389    * Add a bond to the force
390    *
391    * @param groups     the indices of the groups the bond depends on
392    * @param parameters the list of per-bond parameter values for the new bond
393    * @return the index of the bond that was added
394    */
395   public int addBond(IntArray groups, DoubleArray parameters) {
396     return OpenMM_CustomCentroidBondForce_addBond(pointer, groups.getPointer(), parameters.getPointer());
397   }
398 
399   /**
400    * Get the properties of a bond.
401    *
402    * @param index      the index of the bond to get
403    * @param groups     the indices of the groups in the bond
404    * @param parameters the list of per-bond parameter values for the bond
405    */
406   public void getBondParameters(int index, IntArray groups, DoubleArray parameters) {
407     OpenMM_CustomCentroidBondForce_getBondParameters(pointer, index, groups.getPointer(), parameters.getPointer());
408   }
409 
410   /**
411    * Set the properties of a bond.
412    *
413    * @param index      the index of the bond to set
414    * @param groups     the indices of the groups in the bond
415    * @param parameters the list of per-bond parameter values for the bond
416    */
417   public void setBondParameters(int index, IntArray groups, DoubleArray parameters) {
418     OpenMM_CustomCentroidBondForce_setBondParameters(pointer, index, groups.getPointer(), parameters.getPointer());
419   }
420 
421 
422   /**
423    * Update the per-bond parameters and tabulated functions in a Context to match those stored in this Force object.  This method provides
424    * an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
425    * Simply call setBondParameters() to modify this object's parameters, then call updateParametersInContext()
426    * to copy them over to the Context.
427    * <p>
428    * This method has several limitations.  The only information it updates is the values of per-bond parameters and tabulated
429    * functions.  All other aspects of the Force (such as the energy function) are unaffected and can only be changed by reinitializing
430    * the Context.  Neither the definitions of groups nor the set of groups involved in a bond can be changed, nor can new
431    * bonds be added.  Also, while the tabulated values of a function can change, everything else about it (its dimensions,
432    * the data range) must not be changed.
433    *
434    * @param context the OpenMM context.
435    */
436   public void updateParametersInContext(Context context) {
437     if (context.hasContextPointer()) {
438       OpenMM_CustomCentroidBondForce_updateParametersInContext(pointer, context.getPointer());
439     }
440   }
441 
442   /**
443    * Set whether this force should apply periodic boundary conditions when calculating displacements.
444    * Usually this is not appropriate for bonded forces, but there are situations when it can be useful.
445    *
446    * @param periodic 1 if periodic boundary conditions should be used, 0 if not.
447    */
448   public void setUsesPeriodicBoundaryConditions(int periodic) {
449     OpenMM_CustomCentroidBondForce_setUsesPeriodicBoundaryConditions(pointer, periodic);
450   }
451 
452   /**
453    * Returns whether this force makes use of periodic boundary
454    * conditions.
455    *
456    * @return true if force uses PBC and false otherwise
457    */
458   public boolean usesPeriodicBoundaryConditions() {
459     int pbc = OpenMM_CustomCentroidBondForce_usesPeriodicBoundaryConditions(pointer);
460     return pbc == OpenMM_True;
461   }
462 
463   /**
464    * Destroy the OpenMM CustomCentroidBondForce.
465    */
466   public void destroy() {
467     OpenMM_CustomCentroidBondForce_destroy(pointer);
468   }
469 
470 }