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 < 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 }