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 }