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 }