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.IntByReference; 43 import com.sun.jna.ptr.PointerByReference; 44 import edu.uiowa.jopenmm.OpenMM_Vec3; 45 46 import java.nio.DoubleBuffer; 47 import java.nio.IntBuffer; 48 import java.util.HashMap; 49 import java.util.Map; 50 51 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_Boolean.OpenMM_True; 52 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_addConstraint; 53 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_addForce; 54 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_addParticle; 55 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_create; 56 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_destroy; 57 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getConstraintParameters; 58 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getDefaultPeriodicBoxVectors; 59 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getForce; 60 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getNumConstraints; 61 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getNumForces; 62 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getNumParticles; 63 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getParticleMass; 64 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_getVirtualSite; 65 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_isVirtualSite; 66 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_removeConstraint; 67 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_removeForce; 68 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_setConstraintParameters; 69 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_setDefaultPeriodicBoxVectors; 70 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_setParticleMass; 71 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_setVirtualSite; 72 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_System_usesPeriodicBoundaryConditions; 73 74 /** 75 * This class represents a molecular system. The definition of a System involves 76 * four elements: 77 * 78 * <ul> 79 * <li>The set of particles in the system</li> 80 * <li>The forces acting on them</li> 81 * <li>Pairs of particles whose separation should be constrained to a fixed value</li> 82 * <li>For periodic systems, the dimensions of the periodic box</li> 83 * </ul> 84 * <p> 85 * The particles and constraints are defined directly by the System object, while 86 * forces are defined by objects that extend the Force class. After creating a 87 * System, call addParticle() once for each particle, addConstraint() for each constraint, 88 * and addForce() for each Force. 89 * <p> 90 * In addition, particles may be designated as "virtual sites". These are particles 91 * whose positions are computed automatically based on the positions of other particles. 92 * To define a virtual site, call setVirtualSite(), passing in a VirtualSite object 93 * that defines the rules for computing its position. 94 */ 95 public class System { 96 97 /** 98 * System pointer. 99 */ 100 private PointerByReference pointer; 101 102 /** 103 * Map to store Force instances using their Pointer as the key. 104 */ 105 private final Map<Pointer, Force> forceMap = new HashMap<>(); 106 107 /** 108 * Map to store VirtualSite instances using their Pointer as the key. 109 */ 110 private final Map<Pointer, VirtualSite> virtualSiteMap = new HashMap<>(); 111 112 /** 113 * Constructor. 114 */ 115 public System() { 116 pointer = OpenMM_System_create(); 117 } 118 119 /** 120 * Constructor. 121 * 122 * @param pointer The OpenMM System pointer. 123 */ 124 public System(PointerByReference pointer) { 125 this.pointer = pointer; 126 } 127 128 /** 129 * Add a constraint to the system. 130 * 131 * @param particle1 The first particle. 132 * @param particle2 The second particle. 133 * @param distance The distance between the particles. 134 * @return The index of the constraint that was added. 135 */ 136 public int addConstraint(int particle1, int particle2, double distance) { 137 return OpenMM_System_addConstraint(pointer, particle1, particle2, distance); 138 } 139 140 /** 141 * Add a force to the system. 142 * 143 * @param force The force to add. 144 * @return The index of the force that was added. 145 */ 146 public int addForce(Force force) { 147 if (force != null) { 148 int forceIndex = OpenMM_System_addForce(pointer, force.getPointer()); 149 force.setForceIndex(forceIndex); 150 forceMap.put(force.getPointer().getValue(), force); 151 return forceIndex; 152 } 153 return -1; 154 } 155 156 /** 157 * Add a particle to the System. If the mass is 0, Integrators will ignore 158 * the particle and not modify its position or velocity. This is most often 159 * used for virtual sites, but can also be used as a way to prevent a particle 160 * from moving. 161 * 162 * @param mass the mass of the particle (in atomic mass units) 163 * @return the index of the particle that was added 164 */ 165 public int addParticle(double mass) { 166 return OpenMM_System_addParticle(pointer, mass); 167 } 168 169 /** 170 * Destroy the system. 171 */ 172 public void destroy() { 173 if (pointer != null) { 174 OpenMM_System_destroy(pointer); 175 pointer = null; 176 } 177 } 178 179 /** 180 * Get the parameters defining a constraint. 181 * 182 * @param index The index of the constraint. 183 * @param particle1 The index of the first particle involved in the constraint (output). 184 * @param particle2 The index of the second particle involved in the constraint (output). 185 * @param distance The required distance between the two particles (output). 186 */ 187 public void getConstraintParameters(int index, IntByReference particle1, IntByReference particle2, DoubleByReference distance) { 188 OpenMM_System_getConstraintParameters(pointer, index, particle1, particle2, distance); 189 } 190 191 /** 192 * Get the parameters defining a constraint. 193 * 194 * @param index The index of the constraint. 195 * @param particle1 The index of the first particle involved in the constraint (output). 196 * @param particle2 The index of the second particle involved in the constraint (output). 197 * @param distance The required distance between the two particles (output). 198 */ 199 public void getConstraintParameters(int index, IntBuffer particle1, IntBuffer particle2, DoubleBuffer distance) { 200 OpenMM_System_getConstraintParameters(pointer, index, particle1, particle2, distance); 201 } 202 203 /** 204 * Get the default periodic box vectors. 205 * 206 * @param a The first vector (output). 207 * @param b The second vector (output). 208 * @param c The third vector (output). 209 */ 210 public void getDefaultPeriodicBoxVectors(OpenMM_Vec3 a, OpenMM_Vec3 b, OpenMM_Vec3 c) { 211 OpenMM_System_getDefaultPeriodicBoxVectors(pointer, a, b, c); 212 } 213 214 /** 215 * Get a force in the system. 216 * 217 * @param index The index of the force to get. 218 * @return The force object. 219 */ 220 public Force getForce(int index) { 221 PointerByReference forcePointer = OpenMM_System_getForce(pointer, index); 222 return forceMap.get(forcePointer.getValue()); 223 } 224 225 /** 226 * Get the number of constraints in the system. 227 * 228 * @return The number of constraints in the system. 229 */ 230 public int getNumConstraints() { 231 return OpenMM_System_getNumConstraints(pointer); 232 } 233 234 /** 235 * Get the number of forces in the system. 236 * 237 * @return The number of forces in the system. 238 */ 239 public int getNumForces() { 240 return OpenMM_System_getNumForces(pointer); 241 } 242 243 /** 244 * Get the number of particles in the system. 245 * 246 * @return The number of particles in the system. 247 */ 248 public int getNumParticles() { 249 return OpenMM_System_getNumParticles(pointer); 250 } 251 252 /** 253 * Get the mass (in atomic mass units) of a particle. If the mass is 0, Integrators will ignore 254 * the particle and not modify its position or velocity. This is most often 255 * used for virtual sites, but can also be used as a way to prevent a particle 256 * from moving. 257 * 258 * @param index the index of the particle for which to get the mass 259 * @return the mass of the particle (in atomic mass units) 260 */ 261 public double getParticleMass(int index) { 262 return OpenMM_System_getParticleMass(pointer, index); 263 } 264 265 /** 266 * Get the pointer to the system. 267 * 268 * @return The pointer to the system. 269 */ 270 public PointerByReference getPointer() { 271 return pointer; 272 } 273 274 /** 275 * Get the virtual site for a particle. 276 * 277 * @param index The index of the particle. 278 * @return The virtual site object. 279 */ 280 public VirtualSite getVirtualSite(int index) { 281 PointerByReference virtualSitePointer = OpenMM_System_getVirtualSite(pointer, index); 282 return virtualSiteMap.get(virtualSitePointer.getValue()); 283 } 284 285 /** 286 * Check if a particle is a virtual site. 287 * 288 * @param index The index of the particle. 289 * @return True if the particle is a virtual site. 290 */ 291 public boolean isVirtualSite(int index) { 292 int result = OpenMM_System_isVirtualSite(pointer, index); 293 return result != 0; 294 } 295 296 /** 297 * Remove a constraint from the system. 298 * 299 * @param index The index of the constraint to remove. 300 */ 301 public void removeConstraint(int index) { 302 OpenMM_System_removeConstraint(pointer, index); 303 } 304 305 /** 306 * Remove a force from the system. 307 * 308 * @param index The index of the force to remove. 309 */ 310 public void removeForce(int index) { 311 Force force = getForce(index); 312 forceMap.remove(force.getPointer().getValue()); 313 OpenMM_System_removeForce(pointer, index); 314 } 315 316 /** 317 * Set the parameters defining a constraint. 318 * 319 * @param index The index of the constraint. 320 * @param particle1 The index of the first particle involved in the constraint. 321 * @param particle2 The index of the second particle involved in the constraint. 322 * @param distance The required distance between the two particles. 323 */ 324 public void setConstraintParameters(int index, int particle1, int particle2, double distance) { 325 OpenMM_System_setConstraintParameters(pointer, index, particle1, particle2, distance); 326 } 327 328 /** 329 * Set the default periodic box vectors. 330 * 331 * @param a The first vector. 332 * @param b The second vector. 333 * @param c The third vector. 334 */ 335 public void setDefaultPeriodicBoxVectors(OpenMM_Vec3 a, OpenMM_Vec3 b, OpenMM_Vec3 c) { 336 OpenMM_System_setDefaultPeriodicBoxVectors(pointer, a, b, c); 337 } 338 339 /** 340 * Set the mass (in atomic mass units) of a particle. If the mass is 0, Integrators will ignore 341 * the particle and not modify its position or velocity. This is most often 342 * used for virtual sites, but can also be used as a way to prevent a particle 343 * from moving. 344 * 345 * @param index the index of the particle for which to set the mass 346 * @param mass the mass of the particle 347 */ 348 public void setParticleMass(int index, double mass) { 349 OpenMM_System_setParticleMass(pointer, index, mass); 350 } 351 352 /** 353 * Set the pointer to the system. 354 * 355 * @param pointer The pointer to the system. 356 */ 357 public void setPointer(PointerByReference pointer) { 358 this.pointer = pointer; 359 } 360 361 /** 362 * Set a particle to be a virtual site. 363 * 364 * @param index The index of the particle. 365 * @param virtualSite The virtual site object. 366 */ 367 public void setVirtualSite(int index, VirtualSite virtualSite) { 368 if (virtualSite != null) { 369 virtualSiteMap.put(virtualSite.getPointer().getValue(), virtualSite); 370 } 371 OpenMM_System_setVirtualSite(pointer, index, virtualSite.getPointer()); 372 } 373 374 /** 375 * Check if the system uses periodic boundary conditions. 376 * 377 * @return True if the system uses periodic boundary conditions. 378 */ 379 public boolean usesPeriodicBoundaryConditions() { 380 int result = OpenMM_System_usesPeriodicBoundaryConditions(pointer); 381 return result == OpenMM_True; 382 } 383 }