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 }