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.ptr.PointerByReference;
41
42 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_addIntegrator;
43 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_create;
44 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_destroy;
45 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_getConstraintTolerance;
46 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_getCurrentIntegrator;
47 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_getIntegrationForceGroups;
48 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_getIntegrator;
49 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_getNumIntegrators;
50 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_getStepSize;
51 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_setConstraintTolerance;
52 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_setCurrentIntegrator;
53 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_setIntegrationForceGroups;
54 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_setStepSize;
55 import static edu.uiowa.jopenmm.OpenMMLibrary.OpenMM_CompoundIntegrator_step;
56
57 /**
58 * This class allows you to use multiple integration algorithms within a single simulation,
59 * switching back and forth between them. To use it, create whatever other Integrators
60 * you need, then add all of them to a CompoundIntegrator:
61 * <pre>
62 * CompoundIntegrator compoundIntegrator = new CompoundIntegrator();
63 * compoundIntegrator.addIntegrator(new VerletIntegrator(0.001));
64 * compoundIntegrator.addIntegrator(new LangevinIntegrator(300.0, 1.0, 0.001));
65 * </pre>
66 * <p>
67 * Next create a Context, specifying the CompoundIntegrator as the Integrator to use for
68 * the Context:
69 * <pre>
70 * Context context = new Context(system, compoundIntegrator);
71 * </pre>
72 * <p>
73 * Finally, call setCurrentIntegrator() to set which Integrator is active. That one will
74 * be used for all calls to step() until the next time you change it.
75 * <pre>
76 * compoundIntegrator.setCurrentIntegrator(0);
77 * compoundIntegrator.step(1000); // Take 1000 steps of Verlet dynamics
78 * compoundIntegrator.setCurrentIntegrator(1);
79 * compoundIntegrator.step(1000); // Take 1000 steps of Langevin dynamics
80 * </pre>
81 * <p>
82 * When switching between integrators, it is important to make sure they are compatible with
83 * each other, and that they will interpret the positions and velocities in the same way.
84 * Remember that leapfrog style integrators assume the positions and velocities are offset
85 * from each other by half a time step. When switching between a leapfrog and non-leapfrog
86 * integrator, you must first adjust the velocities to avoid introducing error. This is also
87 * true when switching between two leapfrog integrators that use different step sizes,
88 * since they will interpret the velocities as corresponding to different times.
89 */
90 public class CompoundIntegrator extends Integrator {
91
92 /**
93 * Create a CompoundIntegrator.
94 */
95 public CompoundIntegrator() {
96 super(OpenMM_CompoundIntegrator_create());
97 }
98
99 /**
100 * Add an Integrator to this CompoundIntegrator. The Integrator object should have
101 * been created on the heap with the "new" operator. The CompoundIntegrator takes over
102 * ownership of it, and deletes it when the CompoundIntegrator itself is deleted.
103 * All Integrators must be added before the Context is created.
104 *
105 * @param integrator the Integrator to add
106 * @return the index of the Integrator that was added
107 */
108 public int addIntegrator(Integrator integrator) {
109 return OpenMM_CompoundIntegrator_addIntegrator(pointer, integrator.getPointer());
110 }
111
112 /**
113 * Destroy the integrator.
114 */
115 @Override
116 public void destroy() {
117 if (pointer != null) {
118 OpenMM_CompoundIntegrator_destroy(pointer);
119 pointer = null;
120 }
121 }
122
123 /**
124 * Get the distance tolerance within which constraints are maintained, as a fraction of the constrained distance.
125 * This method calls getConstraintTolerance() on whichever Integrator has been set as current.
126 */
127 @Override
128 public double getConstraintTolerance() {
129 return OpenMM_CompoundIntegrator_getConstraintTolerance(pointer);
130 }
131
132 /**
133 * Get the index of the current Integrator.
134 */
135 public int getCurrentIntegrator() {
136 return OpenMM_CompoundIntegrator_getCurrentIntegrator(pointer);
137 }
138
139 /**
140 * Get which force groups to use for integration. By default, all force groups
141 * are included. This is interpreted as a set of bit flags: the forces from group i
142 * will be included if (groups&(1<<i)) != 0.
143 * <p>
144 * This method returns the integration force groups for the current Integrator.
145 */
146 @Override
147 public int getIntegrationForceGroups() {
148 return OpenMM_CompoundIntegrator_getIntegrationForceGroups(pointer);
149 }
150
151 /**
152 * Get a reference to one of the Integrators that have been added to this CompoundIntegrator.
153 *
154 * @param index the index of the Integrator to get
155 */
156 public PointerByReference getIntegrator(int index) {
157 return OpenMM_CompoundIntegrator_getIntegrator(pointer, index);
158 }
159
160 /**
161 * Get the number of Integrators that have been added to this CompoundIntegrator.
162 */
163 public int getNumIntegrators() {
164 return OpenMM_CompoundIntegrator_getNumIntegrators(pointer);
165 }
166
167 /**
168 * Get the size of each time step, in picoseconds. This method calls getStepSize() on
169 * whichever Integrator has been set as current.
170 *
171 * @return the step size, measured in ps
172 */
173 @Override
174 public double getStepSize() {
175 return OpenMM_CompoundIntegrator_getStepSize(pointer);
176 }
177
178 /**
179 * Set the distance tolerance within which constraints are maintained, as a fraction of the constrained distance.
180 * This method calls setConstraintTolerance() on whichever Integrator has been set as current.
181 */
182 @Override
183 public void setConstraintTolerance(double tol) {
184 OpenMM_CompoundIntegrator_setConstraintTolerance(pointer, tol);
185 }
186
187 /**
188 * Set the current Integrator.
189 *
190 * @param index the index of the Integrator to use
191 */
192 public void setCurrentIntegrator(int index) {
193 OpenMM_CompoundIntegrator_setCurrentIntegrator(pointer, index);
194 }
195
196 /**
197 * Set which force groups to use for integration. By default, all force groups
198 * are included. This is interpreted as a set of bit flags: the forces from group i
199 * will be included if (groups&(1<<i)) != 0.
200 * <p>
201 * Calling this method sets the integration force groups for all Integrators
202 * contained in this CompoundIntegrator.
203 */
204 @Override
205 public void setIntegrationForceGroups(int groups) {
206 OpenMM_CompoundIntegrator_setIntegrationForceGroups(pointer, groups);
207 }
208
209 /**
210 * Set the size of each time step, in picoseconds. This method calls setStepSize() on
211 * whichever Integrator has been set as current.
212 *
213 * @param size the step size, measured in ps
214 */
215 @Override
216 public void setStepSize(double size) {
217 OpenMM_CompoundIntegrator_setStepSize(pointer, size);
218 }
219
220 /**
221 * Advance a simulation through time by taking a series of time steps. This method
222 * calls step() on whichever Integrator has been set as current.
223 *
224 * @param steps the number of time steps to take
225 */
226 @Override
227 public void step(int steps) {
228 OpenMM_CompoundIntegrator_step(pointer, steps);
229 }
230 }