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 43 import java.nio.IntBuffer; 44 45 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True; 46 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addBond; 47 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addEnergyParameterDerivative; 48 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addGlobalParameter; 49 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_addPerBondParameter; 50 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_create; 51 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_destroy; 52 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getBondParameters; 53 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getEnergyFunction; 54 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getEnergyParameterDerivativeName; 55 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getGlobalParameterDefaultValue; 56 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getGlobalParameterName; 57 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumBonds; 58 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumEnergyParameterDerivatives; 59 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumGlobalParameters; 60 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getNumPerBondParameters; 61 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_getPerBondParameterName; 62 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setBondParameters; 63 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setEnergyFunction; 64 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setGlobalParameterDefaultValue; 65 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setGlobalParameterName; 66 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setPerBondParameterName; 67 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_setUsesPeriodicBoundaryConditions; 68 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_updateParametersInContext; 69 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CustomBondForce_usesPeriodicBoundaryConditions; 70 71 /** 72 * This class implements bonded interactions between pairs of particles. Unlike HarmonicBondForce, the functional form 73 * of the interaction is completely customizable, and may involve arbitrary algebraic expressions. 74 * It may depend on the distance between particles, as well as on arbitrary global and 75 * per-bond parameters. 76 * <p> 77 * To use this class, create a CustomBondForce object, passing an algebraic expression to the constructor 78 * that defines the interaction energy between each pair of bonded particles. The expression may depend on r, the distance 79 * between the particles, as well as on any parameters you choose. Then call addPerBondParameter() to define per-bond 80 * parameters, and addGlobalParameter() to define global parameters. The values of per-bond parameters are specified as 81 * part of the system definition, while values of global parameters may be modified during a simulation by calling Context::setParameter(). 82 * Finally, call addBond() once for each bond. After a bond has been added, you can modify its parameters by calling setBondParameters(). 83 * This will have no effect on Contexts that already exist unless you call updateParametersInContext(). 84 * <p> 85 * As an example, the following code creates a CustomBondForce that implements a harmonic potential: 86 * <p> 87 * <pre> 88 * {@code 89 * CustomBondForce force = new CustomBondForce("0.5*k*(r-r0)^2"); 90 * } 91 * </pre> 92 * <p> 93 * This force depends on two parameters: the spring constant k and equilibrium distance r0. The following code defines these parameters: 94 * <p> 95 * <pre> 96 * {@code 97 * force.addPerBondParameter("k"); 98 * force.addPerBondParameter("r0"); 99 * } 100 * </pre> 101 * <p> 102 * This class also has the ability to compute derivatives of the potential energy with respect to global parameters. 103 * Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be 104 * computed. You can then query its value in a Context by calling getState() on it. 105 * <p> 106 * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following 107 * 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 108 * 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. 109 * select(x,y,z) = z if x = 0, y otherwise. 110 */ 111 public class CustomBondForce extends Force { 112 113 /** 114 * Create a CustomBondForce. 115 * 116 * @param energy an algebraic expression giving the interaction energy between two bonded particles as a function 117 * of r, the distance between them 118 */ 119 public CustomBondForce(String energy) { 120 super(OpenMM_CustomBondForce_create(energy)); 121 } 122 123 /** 124 * Add a bond term to the force field. 125 * 126 * @param i1 the index of the first particle connected by the bond 127 * @param i2 the index of the second particle connected by the bond 128 * @param parameters the list of parameters for the new bond 129 * @return the index of the bond that was added 130 */ 131 public int addBond(int i1, int i2, DoubleArray parameters) { 132 return OpenMM_CustomBondForce_addBond(pointer, i1, i2, parameters.getPointer()); 133 } 134 135 /** 136 * Request that this Force compute the derivative of its energy with respect to a global parameter. 137 * The parameter must have already been added with addGlobalParameter(). 138 * 139 * @param name the name of the parameter 140 */ 141 public void addEnergyParameterDerivative(String name) { 142 OpenMM_CustomBondForce_addEnergyParameterDerivative(pointer, name); 143 } 144 145 /** 146 * Add a new global parameter that the interaction may depend on. The default value provided to 147 * this method is the initial value of the parameter in newly created Contexts. You can change 148 * the value at any time by calling setParameter() on the Context. 149 * 150 * @param name the name of the parameter 151 * @param value the default value of the parameter 152 * @return the index of the parameter that was added 153 */ 154 public int addGlobalParameter(String name, double value) { 155 return OpenMM_CustomBondForce_addGlobalParameter(pointer, name, value); 156 } 157 158 /** 159 * Add a new per-bond parameter that the interaction may depend on. 160 * 161 * @param name the name of the parameter 162 * @return the index of the parameter that was added 163 */ 164 public int addPerBondParameter(String name) { 165 return OpenMM_CustomBondForce_addPerBondParameter(pointer, name); 166 } 167 168 /** 169 * Destroy the OpenMM CustomBondForce. 170 */ 171 @Override 172 public void destroy() { 173 if (pointer != null) { 174 OpenMM_CustomBondForce_destroy(pointer); 175 pointer = null; 176 } 177 } 178 179 /** 180 * Get the force field parameters for a bond term. 181 * 182 * @param index the index of the bond for which to get parameters 183 * @param i1 the index of the first particle connected by the bond 184 * @param i2 the index of the second particle connected by the bond 185 * @param parameters the list of parameters for the bond 186 */ 187 public void getBondParameters(int index, IntBuffer i1, IntBuffer i2, DoubleArray parameters) { 188 OpenMM_CustomBondForce_getBondParameters(pointer, index, i1, i2, parameters.getPointer()); 189 } 190 191 /** 192 * Get the force field parameters for a bond term. 193 * 194 * @param index the index of the bond for which to get parameters 195 * @param i1 the index of the first particle connected by the bond 196 * @param i2 the index of the second particle connected by the bond 197 * @param parameters the list of parameters for the bond 198 */ 199 public void getBondParameters(int index, IntByReference i1, IntByReference i2, DoubleArray parameters) { 200 OpenMM_CustomBondForce_getBondParameters(pointer, index, i1, i2, parameters.getPointer()); 201 } 202 203 /** 204 * Get the algebraic expression that gives the interaction energy for each bond 205 * 206 * @return the energy function expression 207 */ 208 public String getEnergyFunction() { 209 Pointer p = OpenMM_CustomBondForce_getEnergyFunction(pointer); 210 if (p == null) { 211 return null; 212 } 213 return p.getString(0); 214 } 215 216 /** 217 * Get the name of a global parameter with respect to which this Force should compute the 218 * derivative of the energy. 219 * 220 * @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives() 221 * @return the parameter name 222 */ 223 public String getEnergyParameterDerivativeName(int index) { 224 Pointer p = OpenMM_CustomBondForce_getEnergyParameterDerivativeName(pointer, index); 225 if (p == null) { 226 return null; 227 } 228 return p.getString(0); 229 } 230 231 /** 232 * Get the default value of a global parameter. 233 * 234 * @param index The index of the parameter. 235 * @return The default value of the parameter. 236 */ 237 public double getGlobalParameterDefaultValue(int index) { 238 return OpenMM_CustomBondForce_getGlobalParameterDefaultValue(pointer, index); 239 } 240 241 /** 242 * Get the name of a global parameter. 243 * 244 * @param index The index of the parameter. 245 * @return The name of the parameter. 246 */ 247 public String getGlobalParameterName(int index) { 248 Pointer p = OpenMM_CustomBondForce_getGlobalParameterName(pointer, index); 249 if (p == null) { 250 return null; 251 } 252 return p.getString(0); 253 } 254 255 /** 256 * Get the number of bonds for which force field parameters have been defined. 257 * 258 * @return the number of bonds 259 */ 260 public int getNumBonds() { 261 return OpenMM_CustomBondForce_getNumBonds(pointer); 262 } 263 264 /** 265 * Get the number of parameters with respect to which the derivative of the energy should be computed. 266 * 267 * @return The number of parameters. 268 */ 269 public int getNumEnergyParameterDerivatives() { 270 return OpenMM_CustomBondForce_getNumEnergyParameterDerivatives(pointer); 271 } 272 273 /** 274 * Get the number of global parameters. 275 * 276 * @return The number of global parameters. 277 */ 278 public int getNumGlobalParameters() { 279 return OpenMM_CustomBondForce_getNumGlobalParameters(pointer); 280 } 281 282 /** 283 * Get the number of per-bond parameters. 284 * 285 * @return The number of per-bond parameters. 286 */ 287 public int getNumPerBondParameters() { 288 return OpenMM_CustomBondForce_getNumPerBondParameters(pointer); 289 } 290 291 /** 292 * Get the name of a per-bond parameter. 293 * 294 * @param index The index of the parameter. 295 * @return The name of the parameter. 296 */ 297 public String getPerBondParameterName(int index) { 298 Pointer p = OpenMM_CustomBondForce_getPerBondParameterName(pointer, index); 299 if (p == null) { 300 return null; 301 } 302 return p.getString(0); 303 } 304 305 /** 306 * Set the parameters for one bond in the OpenMM System. 307 * 308 * @param index The index of the bond. 309 * @param i1 The index of the first atom. 310 * @param i2 The index of the second atom. 311 * @param parameters The bond parameters. 312 */ 313 public void setBondParameters(int index, int i1, int i2, DoubleArray parameters) { 314 OpenMM_CustomBondForce_setBondParameters(pointer, index, i1, i2, parameters.getPointer()); 315 } 316 317 /** 318 * Set the energy function expression. 319 * 320 * @param energy The energy function expression. 321 */ 322 public void setEnergyFunction(String energy) { 323 OpenMM_CustomBondForce_setEnergyFunction(pointer, energy); 324 } 325 326 /** 327 * Set the default value of a global parameter. 328 * 329 * @param index The index of the parameter. 330 * @param value The default value of the parameter. 331 */ 332 public void setGlobalParameterDefaultValue(int index, double value) { 333 OpenMM_CustomBondForce_setGlobalParameterDefaultValue(pointer, index, value); 334 } 335 336 /** 337 * Set the name of a global parameter. 338 * 339 * @param index The index of the parameter. 340 * @param name The name of the parameter. 341 */ 342 public void setGlobalParameterName(int index, String name) { 343 OpenMM_CustomBondForce_setGlobalParameterName(pointer, index, name); 344 } 345 346 /** 347 * Set the name of a per-bond parameter. 348 * 349 * @param index The index of the parameter. 350 * @param name The name of the parameter. 351 */ 352 public void setPerBondParameterName(int index, String name) { 353 OpenMM_CustomBondForce_setPerBondParameterName(pointer, index, name); 354 } 355 356 /** 357 * Set whether this force uses periodic boundary conditions. 358 * 359 * @param periodic If true, periodic boundary conditions will be used. 360 */ 361 public void setUsesPeriodicBoundaryConditions(boolean periodic) { 362 OpenMM_CustomBondForce_setUsesPeriodicBoundaryConditions(pointer, periodic ? 1 : 0); 363 } 364 365 /** 366 * Update the parameters in the OpenMM Context. 367 * 368 * @param context The OpenMM Context. 369 */ 370 public void updateParametersInContext(Context context) { 371 if (context.hasContextPointer()) { 372 OpenMM_CustomBondForce_updateParametersInContext(pointer, context.getPointer()); 373 } 374 } 375 376 /** 377 * Check if the force uses periodic boundary conditions. 378 * 379 * @return True if the force uses periodic boundary conditions. 380 */ 381 @Override 382 public boolean usesPeriodicBoundaryConditions() { 383 int pbc = OpenMM_CustomBondForce_usesPeriodicBoundaryConditions(pointer); 384 return pbc == OpenMM_True; 385 } 386 }