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