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.DoubleByReference;
42 import com.sun.jna.ptr.PointerByReference;
43
44 import java.nio.DoubleBuffer;
45
46 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True;
47 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_addBond;
48 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_addEnergyParameterDerivative;
49 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_addFunction;
50 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_addGlobalParameter;
51 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_addPerBondParameter;
52 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_addTabulatedFunction;
53 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_create;
54 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_destroy;
55 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getBondParameters;
56 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getEnergyFunction;
57 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getEnergyParameterDerivativeName;
58 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getFunctionParameters;
59 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getGlobalParameterDefaultValue;
60 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getGlobalParameterName;
61 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumBonds;
62 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumEnergyParameterDerivatives;
63 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumFunctions;
64 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumGlobalParameters;
65 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumParticlesPerBond;
66 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumPerBondParameters;
67 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getNumTabulatedFunctions;
68 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getPerBondParameterName;
69 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getTabulatedFunction;
70 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_getTabulatedFunctionName;
71 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setBondParameters;
72 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setEnergyFunction;
73 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setFunctionParameters;
74 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setGlobalParameterDefaultValue;
75 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setGlobalParameterName;
76 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setPerBondParameterName;
77 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_setUsesPeriodicBoundaryConditions;
78 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_updateParametersInContext;
79 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomCompoundBondForce_usesPeriodicBoundaryConditions;
80
81 /**
82 * This class supports a wide variety of bonded interactions. It defines a "bond" as a single energy term
83 * that depends on the positions of a fixed set of particles. The number of particles involved in a bond, and how
84 * the energy depends on their positions, is configurable. It may depend on the positions of individual particles,
85 * the distances between pairs of particles, the angles formed by sets of three particles, and the dihedral
86 * angles formed by sets of four particles.
87 * <p>
88 * We refer to the particles in a bond as p1, p2, p3, etc. For each bond, CustomCompoundBondForce evaluates a
89 * user supplied algebraic expression to determine the interaction energy. The expression may depend on the
90 * following variables and functions:
91 * <ul>
92 * <li>x1, y1, z1, x2, y2, z2, etc.: The x, y, and z coordinates of the particle positions. For example, x1
93 * is the x coordinate of particle p1, and y3 is the y coordinate of particle p3.</li>
94 * <li>distance(p1, p2): the distance between particles p1 and p2 (where "p1" and "p2" may be replaced by the names
95 * of whichever particles you want to calculate the distance between).</li>
96 * <li>angle(p1, p2, p3): the angle formed by the three specified particles.</li>
97 * <li>dihedral(p1, p2, p3, p4): the dihedral angle formed by the four specified particles, guaranteed to be in the range [-pi,+pi].</li>
98 * </ul>
99 * <p>
100 * The expression also may involve tabulated functions, and may depend on arbitrary
101 * global and per-bond parameters.
102 * <p>
103 * To use this class, create a CustomCompoundBondForce 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 addBond() to define bonds and specify their parameter values. After a bond has been added, you can
110 * modify its parameters by calling setBondParameters(). This will have no effect on Contexts that already exist unless
111 * you call updateParametersInContext().
112 * <p>
113 * As an example, the following code creates a CustomCompoundBondForce that implements a Urey-Bradley potential. This
114 * is an interaction between three particles that depends on the angle formed by p1-p2-p3, and on the distance between
115 * p1 and p3.
116 * <pre>
117 * {@code
118 * CustomCompoundBondForce* force = new CustomCompoundBondForce(3, "0.5*(kangle*(angle(p1,p2,p3)-theta0)^2+kbond*(distance(p1,p3)-r0)^2)");
119 * }
120 * </pre>
121 * <p>
122 * This force depends on four parameters: kangle, kbond, theta0, and r0. The following code defines these as per-bond parameters:
123 * <pre>
124 * {@code
125 * force->addPerBondParameter("kangle");
126 * force->addPerBondParameter("kbond");
127 * force->addPerBondParameter("theta0");
128 * force->addPerBondParameter("r0");
129 * }
130 * </pre>
131 * <p>
132 * This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
133 * Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
134 * computed. You can then query its value in a Context by calling getState() on it.
135 * <p>
136 * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ˆ (power), and the following
137 * 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
138 * 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.
139 * select(x,y,z) = z if x = 0, y otherwise.
140 * <p>
141 * This class also supports the functions pointdistance(x1, y1, z1, x2, y2, z2),
142 * pointangle(x1, y1, z1, x2, y2, z2, x3, y3, z3), and pointdihedral(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4).
143 * These functions are similar to distance(), angle(), and dihedral(), but the arguments are the
144 * coordinates of points to perform the calculation based on rather than the names of particles.
145 * This enables more flexible geometric calculations. For example, the following computes the distance
146 * from particle p1 to the midpoint between particles p2 and p3.
147 * <pre>
148 * {@code
149 * CustomCompoundBondForce* force = new CustomCompoundBondForce(3, "pointdistance(x1, y1, z1, (x2+x3)/2, (y2+y3)/2, (z2+z3)/2)");
150 * }
151 * </pre>
152 * <p>
153 * In addition, you can call addTabulatedFunction() to define a new function based on tabulated values. You specify the function by
154 * creating a TabulatedFunction object. That function can then appear in the expression.
155 */
156 public class CustomCompoundBondForce extends Force {
157
158 /**
159 * Create a CustomCompoundBondForce.
160 *
161 * @param numParticles The number of particles per bond.
162 * @param energy The energy expression for the force.
163 */
164 public CustomCompoundBondForce(int numParticles, String energy) {
165 super(OpenMM_CustomCompoundBondForce_create(numParticles, energy));
166 }
167
168 /**
169 * Add a bond to the force.
170 *
171 * @param particles The indices of the particles in the bond.
172 * @param parameters The bond parameters.
173 * @return The index of the bond that was added.
174 */
175 public int addBond(IntArray particles, DoubleArray parameters) {
176 return OpenMM_CustomCompoundBondForce_addBond(pointer, particles.getPointer(), parameters.getPointer());
177 }
178
179 /**
180 * Request that this Force compute the derivative of its energy with respect to a global parameter.
181 *
182 * @param name The name of the parameter to compute the derivative of the energy with respect to.
183 */
184 public void addEnergyParameterDerivative(String name) {
185 OpenMM_CustomCompoundBondForce_addEnergyParameterDerivative(pointer, name);
186 }
187
188 /**
189 * Add a tabulated function that may appear in the energy expression.
190 *
191 * @param name The name of the function as it appears in expressions.
192 * @param values The tabulated values of the function.
193 * @param min The minimum value of the independent variable for which the function is defined.
194 * @param max The maximum value of the independent variable for which the function is defined.
195 * @return The index of the function that was added.
196 * @deprecated This method exists only for backward compatibility. Use addTabulatedFunction() instead.
197 */
198 @Deprecated
199 public int addFunction(String name, PointerByReference values, double min, double max) {
200 return OpenMM_CustomCompoundBondForce_addFunction(pointer, name, values, min, max);
201 }
202
203 /**
204 * Add a global parameter that the interaction may depend on.
205 *
206 * @param name The name of the parameter.
207 * @param defaultValue The default value of the parameter.
208 * @return The index of the parameter that was added.
209 */
210 public int addGlobalParameter(String name, double defaultValue) {
211 return OpenMM_CustomCompoundBondForce_addGlobalParameter(pointer, name, defaultValue);
212 }
213
214 /**
215 * Add a per-bond parameter that the interaction may depend on.
216 *
217 * @param name The name of the parameter.
218 * @return The index of the parameter that was added.
219 */
220 public int addPerBondParameter(String name) {
221 return OpenMM_CustomCompoundBondForce_addPerBondParameter(pointer, name);
222 }
223
224 /**
225 * Add a tabulated function that may appear in the energy expression.
226 *
227 * @param name The name of the function as it appears in expressions.
228 * @param function A TabulatedFunction object defining the function.
229 * @return The index of the function that was added.
230 */
231 public int addTabulatedFunction(String name, PointerByReference function) {
232 return OpenMM_CustomCompoundBondForce_addTabulatedFunction(pointer, name, function);
233 }
234
235 /**
236 * Destroy the force.
237 */
238 @Override
239 public void destroy() {
240 if (pointer != null) {
241 OpenMM_CustomCompoundBondForce_destroy(pointer);
242 pointer = null;
243 }
244 }
245
246 /**
247 * Get the parameters for a bond.
248 *
249 * @param index The index of the bond.
250 * @param particles The indices of the particles in the bond.
251 * @param parameters The bond parameters.
252 */
253 public void getBondParameters(int index, IntArray particles, DoubleArray parameters) {
254 OpenMM_CustomCompoundBondForce_getBondParameters(pointer, index, particles.getPointer(), parameters.getPointer());
255 }
256
257 /**
258 * Get the energy expression for the force.
259 *
260 * @return The energy expression for the force.
261 */
262 public String getEnergyFunction() {
263 Pointer p = OpenMM_CustomCompoundBondForce_getEnergyFunction(pointer);
264 if (p == null) {
265 return null;
266 }
267 return p.getString(0);
268 }
269
270 /**
271 * Get the name of a parameter with respect to which the derivative of the energy should be computed.
272 *
273 * @param index The index of the parameter derivative.
274 * @return The name of the parameter.
275 */
276 public String getEnergyParameterDerivativeName(int index) {
277 Pointer p = OpenMM_CustomCompoundBondForce_getEnergyParameterDerivativeName(pointer, index);
278 if (p == null) {
279 return null;
280 }
281 return p.getString(0);
282 }
283
284 /**
285 * Get the parameters for a tabulated function.
286 *
287 * @param index The index of the function.
288 * @param name The name of the function.
289 * @param values The tabulated values.
290 * @param min The minimum value of the independent variable.
291 * @param max The maximum value of the independent variable.
292 */
293 public void getFunctionParameters(int index, PointerByReference name, PointerByReference values, DoubleBuffer min, DoubleBuffer max) {
294 OpenMM_CustomCompoundBondForce_getFunctionParameters(pointer, index, name, values, min, max);
295 }
296
297 /**
298 * Get the parameters for a tabulated function.
299 *
300 * @param index The index of the function.
301 * @param name The name of the function.
302 * @param values The tabulated values.
303 * @param min The minimum value of the independent variable.
304 * @param max The maximum value of the independent variable.
305 */
306 public void getFunctionParameters(int index, PointerByReference name, PointerByReference values, DoubleByReference min, DoubleByReference max) {
307 OpenMM_CustomCompoundBondForce_getFunctionParameters(pointer, index, name, values, min, max);
308 }
309
310 /**
311 * Get the default value of a global parameter.
312 *
313 * @param index The index of the parameter.
314 * @return The default value of the parameter.
315 */
316 public double getGlobalParameterDefaultValue(int index) {
317 return OpenMM_CustomCompoundBondForce_getGlobalParameterDefaultValue(pointer, index);
318 }
319
320 /**
321 * Get the name of a global parameter.
322 *
323 * @param index The index of the parameter.
324 * @return The name of the parameter.
325 */
326 public String getGlobalParameterName(int index) {
327 Pointer p = OpenMM_CustomCompoundBondForce_getGlobalParameterName(pointer, index);
328 if (p == null) {
329 return null;
330 }
331 return p.getString(0);
332 }
333
334 /**
335 * Get the number of bonds.
336 *
337 * @return The number of bonds.
338 */
339 public int getNumBonds() {
340 return OpenMM_CustomCompoundBondForce_getNumBonds(pointer);
341 }
342
343 /**
344 * Get the number of parameters with respect to which the derivative of the energy should be computed.
345 *
346 * @return The number of parameters.
347 */
348 public int getNumEnergyParameterDerivatives() {
349 return OpenMM_CustomCompoundBondForce_getNumEnergyParameterDerivatives(pointer);
350 }
351
352 /**
353 * Get the number of tabulated functions.
354 *
355 * @return The number of tabulated functions.
356 * @deprecated This method exists only for backward compatibility. Use getNumTabulatedFunctions() instead.
357 */
358 @Deprecated
359 public int getNumFunctions() {
360 return OpenMM_CustomCompoundBondForce_getNumFunctions(pointer);
361 }
362
363 /**
364 * Get the number of global parameters.
365 *
366 * @return The number of global parameters.
367 */
368 public int getNumGlobalParameters() {
369 return OpenMM_CustomCompoundBondForce_getNumGlobalParameters(pointer);
370 }
371
372 /**
373 * Get the number of particles per bond.
374 *
375 * @return The number of particles per bond.
376 */
377 public int getNumParticlesPerBond() {
378 return OpenMM_CustomCompoundBondForce_getNumParticlesPerBond(pointer);
379 }
380
381 /**
382 * Get the number of per-bond parameters.
383 *
384 * @return The number of per-bond parameters.
385 */
386 public int getNumPerBondParameters() {
387 return OpenMM_CustomCompoundBondForce_getNumPerBondParameters(pointer);
388 }
389
390 /**
391 * Get the number of tabulated functions.
392 *
393 * @return The number of tabulated functions.
394 */
395 public int getNumTabulatedFunctions() {
396 return OpenMM_CustomCompoundBondForce_getNumTabulatedFunctions(pointer);
397 }
398
399 /**
400 * Get the name of a per-bond parameter.
401 *
402 * @param index The index of the parameter.
403 * @return The name of the parameter.
404 */
405 public String getPerBondParameterName(int index) {
406 Pointer p = OpenMM_CustomCompoundBondForce_getPerBondParameterName(pointer, index);
407 if (p == null) {
408 return null;
409 }
410 return p.getString(0);
411 }
412
413 /**
414 * Get a reference to a tabulated function.
415 *
416 * @param index The index of the function.
417 * @return A reference to the function.
418 */
419 public PointerByReference getTabulatedFunction(int index) {
420 return OpenMM_CustomCompoundBondForce_getTabulatedFunction(pointer, index);
421 }
422
423 /**
424 * Get the name of a tabulated function.
425 *
426 * @param index The index of the function.
427 * @return The name of the function.
428 */
429 public String getTabulatedFunctionName(int index) {
430 Pointer p = OpenMM_CustomCompoundBondForce_getTabulatedFunctionName(pointer, index);
431 if (p == null) {
432 return null;
433 }
434 return p.getString(0);
435 }
436
437 /**
438 * Set the parameters for a bond.
439 *
440 * @param index The index of the bond.
441 * @param particles The indices of the particles in the bond.
442 * @param parameters The bond parameters.
443 */
444 public void setBondParameters(int index, IntArray particles, DoubleArray parameters) {
445 OpenMM_CustomCompoundBondForce_setBondParameters(pointer, index, particles.getPointer(), parameters.getPointer());
446 }
447
448 /**
449 * Set the energy expression for the force.
450 *
451 * @param energy The energy expression for the force.
452 */
453 public void setEnergyFunction(String energy) {
454 OpenMM_CustomCompoundBondForce_setEnergyFunction(pointer, energy);
455 }
456
457 /**
458 * Set the parameters for a tabulated function.
459 *
460 * @param index The index of the function.
461 * @param name The name of the function.
462 * @param values The tabulated values.
463 * @param min The minimum value of the independent variable.
464 * @param max The maximum value of the independent variable.
465 */
466 public void setFunctionParameters(int index, String name, PointerByReference values, double min, double max) {
467 OpenMM_CustomCompoundBondForce_setFunctionParameters(pointer, index, name, values, min, max);
468 }
469
470 /**
471 * Set the default value of a global parameter.
472 *
473 * @param index The index of the parameter.
474 * @param defaultValue The default value of the parameter.
475 */
476 public void setGlobalParameterDefaultValue(int index, double defaultValue) {
477 OpenMM_CustomCompoundBondForce_setGlobalParameterDefaultValue(pointer, index, defaultValue);
478 }
479
480 /**
481 * Set the name of a global parameter.
482 *
483 * @param index The index of the parameter.
484 * @param name The name of the parameter.
485 */
486 public void setGlobalParameterName(int index, String name) {
487 OpenMM_CustomCompoundBondForce_setGlobalParameterName(pointer, index, name);
488 }
489
490 /**
491 * Set the name of a per-bond parameter.
492 *
493 * @param index The index of the parameter.
494 * @param name The name of the parameter.
495 */
496 public void setPerBondParameterName(int index, String name) {
497 OpenMM_CustomCompoundBondForce_setPerBondParameterName(pointer, index, name);
498 }
499
500 /**
501 * Set whether this force should apply periodic boundary conditions when calculating displacements.
502 *
503 * @param periodic If true, periodic boundary conditions will be used.
504 */
505 public void setUsesPeriodicBoundaryConditions(boolean periodic) {
506 OpenMM_CustomCompoundBondForce_setUsesPeriodicBoundaryConditions(pointer, periodic ? 1 : 0);
507 }
508
509 /**
510 * Update the parameters in the context.
511 *
512 * @param context The context to update.
513 */
514 public void updateParametersInContext(Context context) {
515 if (context.hasContextPointer()) {
516 OpenMM_CustomCompoundBondForce_updateParametersInContext(pointer, context.getPointer());
517 }
518 }
519
520 /**
521 * Check if the force uses periodic boundary conditions.
522 *
523 * @return True if the force uses periodic boundary conditions.
524 */
525 @Override
526 public boolean usesPeriodicBoundaryConditions() {
527 int pbc = OpenMM_CustomCompoundBondForce_usesPeriodicBoundaryConditions(pointer);
528 return pbc == OpenMM_True;
529 }
530 }