Commit 8ecf9e35 authored by Peter Eastman's avatar Peter Eastman
Browse files

Created architecture for multiple time step integrators and completed reference implementation

parent d817b46b
...@@ -89,8 +89,9 @@ public: ...@@ -89,8 +89,9 @@ public:
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param includeForce true if forces should be computed * @param includeForce true if forces should be computed
* @param includeEnergy true if potential energy should be computed * @param includeEnergy true if potential energy should be computed
* @param groups a set of bit flags for which force groups to include
*/ */
virtual void beginComputation(ContextImpl& context, bool includeForce, bool includeEnergy) = 0; virtual void beginComputation(ContextImpl& context, bool includeForce, bool includeEnergy, int groups) = 0;
/** /**
* This is called at the end of each force/energy computation, after calcForcesAndEnergy() has been called on * This is called at the end of each force/energy computation, after calcForcesAndEnergy() has been called on
* every ForceImpl. * every ForceImpl.
...@@ -98,11 +99,12 @@ public: ...@@ -98,11 +99,12 @@ public:
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param includeForce true if forces should be computed * @param includeForce true if forces should be computed
* @param includeEnergy true if potential energy should be computed * @param includeEnergy true if potential energy should be computed
* @param groups a set of bit flags for which force groups to include
* @return the potential energy of the system. This value is added to all values returned by ForceImpls' * @return the potential energy of the system. This value is added to all values returned by ForceImpls'
* calcForcesAndEnergy() methods. That is, each force kernel may <i>either</i> return its contribution to the * calcForcesAndEnergy() methods. That is, each force kernel may <i>either</i> return its contribution to the
* energy directly, <i>or</i> add it to an internal buffer so that it will be included here. * energy directly, <i>or</i> add it to an internal buffer so that it will be included here.
*/ */
virtual double finishComputation(ContextImpl& context, bool includeForce, bool includeEnergy) = 0; virtual double finishComputation(ContextImpl& context, bool includeForce, bool includeEnergy, int groups) = 0;
}; };
/** /**
...@@ -486,9 +488,11 @@ public: ...@@ -486,9 +488,11 @@ public:
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param includeForces true if forces should be calculated * @param includeForces true if forces should be calculated
* @param includeEnergy true if the energy should be calculated * @param includeEnergy true if the energy should be calculated
* @param includeDirect true if direct space interactions should be included
* @param includeReciprocal true if reciprocal space interactions should be included
* @return the potential energy due to the force * @return the potential energy due to the force
*/ */
virtual double execute(ContextImpl& context, bool includeForces, bool includeEnergy) = 0; virtual double execute(ContextImpl& context, bool includeForces, bool includeEnergy, bool includeDirect, bool includeReciprocal) = 0;
}; };
/** /**
......
...@@ -97,6 +97,9 @@ namespace OpenMM { ...@@ -97,6 +97,9 @@ namespace OpenMM {
* freedom (the x, y, or z component of a particle's velocity).</li> * freedom (the x, y, or z component of a particle's velocity).</li>
* <li>f: (per-DOF, read-only) This is the current force acting on the degree of * <li>f: (per-DOF, read-only) This is the current force acting on the degree of
* freedom (the x, y, or z component of the force on a particle).</li> * freedom (the x, y, or z component of the force on a particle).</li>
* <li>f0, f1, f2, ...: (per-DOF, read-only) This is similar to f, but includes
* only the contribution from forces in one force group. A single computation
* step may only depend on a single force variable (f, f0, f1, etc.).</li>
* <li>m: (per-DOF, read-only) This is the mass of the particle the degree of * <li>m: (per-DOF, read-only) This is the mass of the particle the degree of
* freedom is associated with.</li> * freedom is associated with.</li>
* <li>uniform: (either global or per-DOF, read-only) This is a uniformly * <li>uniform: (either global or per-DOF, read-only) This is a uniformly
...@@ -162,6 +165,22 @@ namespace OpenMM { ...@@ -162,6 +165,22 @@ namespace OpenMM {
* risk invalidating the forces just before the first velocity update, thus * risk invalidating the forces just before the first velocity update, thus
* requiring two force evaluations per time step instead of one. * requiring two force evaluations per time step instead of one.
* *
* CustomIntegrator can be used to implement multiple time step integrators. The
* following example shows an r-RESPA integrator. It assumes the quickly changing
* forces are in force group 0 and the slowly changing ones are in force group 1.
* It evaluates the "fast" forces four times as often as the "slow" forces.
*
* <tt><pre>
* CustomIntegrator integrator(0.004);
* integrator.addComputePerDof("v", "v+0.5*dt*f1/m");
* for (int i = 0; i < 4; i++) {
* integrator.addComputePerDof("v", "v+0.5*(dt/4)*f0/m");
* integrator.addComputePerDof("x", "x+(dt/4)*v");
* integrator.addComputePerDof("v", "v+0.5*(dt/4)*f0/m");
* }
* integrator.addComputePerDof("v", "v+0.5*dt*f1/m");
* </pre></tt>
*
* Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following
* functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, step. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, step. All trigonometric functions
* are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. An expression * are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. An expression
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008 Stanford University and the Authors. * * Portions copyright (c) 2008-2012 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -51,13 +51,31 @@ class ForceImpl; ...@@ -51,13 +51,31 @@ class ForceImpl;
* <li>Define parameters which are stored in the Context and can be modified by the user</li> * <li>Define parameters which are stored in the Context and can be modified by the user</li>
* <li>Change the values of parameters defined by other Force objects at the start of each time step</li> * <li>Change the values of parameters defined by other Force objects at the start of each time step</li>
* </ul> * </ul>
*
* Forces may be organized into "force groups". This is used for multiple time step integration,
* and allows subsets of the Forces in a System to be evaluated at different times. By default,
* all Forces are in group 0. Call setForceGroup() to change this. Some Force subclasses may
* provide additional methods to further split their computations into multiple groups. Be aware
* that particular Platforms may place restrictions on the use of force groups, such as requiring
* all nonbonded forces to be in the same group.
*/ */
class OPENMM_EXPORT Force { class OPENMM_EXPORT Force {
public: public:
Force() {} Force() : forceGroup(0) {
}
virtual ~Force() { virtual ~Force() {
} }
/**
* Get the force group this Force belongs to.
*/
int getForceGroup() const;
/**
* Set the force group this Force belongs to.
*
* @param group the group index. Legal values are between 0 and 31 (inclusive).
*/
void setForceGroup(int group);
protected: protected:
friend class ContextImpl; friend class ContextImpl;
/** /**
...@@ -66,6 +84,8 @@ protected: ...@@ -66,6 +84,8 @@ protected:
* The ForceImpl will be deleted automatically when the Context is deleted. * The ForceImpl will be deleted automatically when the Context is deleted.
*/ */
virtual ForceImpl* createImpl() = 0; virtual ForceImpl* createImpl() = 0;
private:
int forceGroup;
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -263,6 +263,22 @@ public: ...@@ -263,6 +263,22 @@ public:
void setUseDispersionCorrection(bool useCorrection) { void setUseDispersionCorrection(bool useCorrection) {
useDispersionCorrection = useCorrection; useDispersionCorrection = useCorrection;
} }
/**
* Get the force group that reciprocal space interactions for Ewald or PME are included in. This allows multiple
* time step integrators to evaluate direct and reciprocal space interactions at different intervals: getForceGroup()
* specifies the group for direct space, and getReciprocalSpaceForceGroup() specifies the group for reciprocal space.
* The default value is 0.
*/
int getReciprocalSpaceForceGroup() const;
/**
* Set the force group that reciprocal space interactions for Ewald or PME are included in. This allows multiple
* time step integrators to evaluate direct and reciprocal space interactions at different intervals: setForceGroup()
* specifies the group for direct space, and setReciprocalSpaceForceGroup() specifies the group for reciprocal space.
* The default value is 0.
*
* @param group the group index. Legal values are between 0 and 31 (inclusive).
*/
void setReciprocalSpaceForceGroup(int group);
protected: protected:
ForceImpl* createImpl(); ForceImpl* createImpl();
private: private:
...@@ -271,6 +287,7 @@ private: ...@@ -271,6 +287,7 @@ private:
NonbondedMethod nonbondedMethod; NonbondedMethod nonbondedMethod;
double cutoffDistance, rfDielectric, ewaldErrorTol; double cutoffDistance, rfDielectric, ewaldErrorTol;
bool useDispersionCorrection; bool useDispersionCorrection;
int recipForceGroup;
void addExclusionsToSet(const std::vector<std::set<int> >& bonded12, std::set<int>& exclusions, int baseParticle, int fromParticle, int currentLevel) const; void addExclusionsToSet(const std::vector<std::set<int> >& bonded12, std::set<int>& exclusions, int baseParticle, int fromParticle, int currentLevel) const;
std::vector<ParticleInfo> particles; std::vector<ParticleInfo> particles;
std::vector<ExceptionInfo> exceptions; std::vector<ExceptionInfo> exceptions;
......
...@@ -53,7 +53,7 @@ public: ...@@ -53,7 +53,7 @@ public:
return owner; return owner;
} }
void updateContextState(ContextImpl& context); void updateContextState(ContextImpl& context);
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy) { double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
// This force doesn't apply forces to particles. // This force doesn't apply forces to particles.
return 0.0; return 0.0;
} }
......
...@@ -55,7 +55,7 @@ public: ...@@ -55,7 +55,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() { std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force field doesn't define any parameters. return std::map<std::string, double>(); // This force field doesn't define any parameters.
} }
......
...@@ -50,7 +50,7 @@ public: ...@@ -50,7 +50,7 @@ public:
return owner; return owner;
} }
void updateContextState(ContextImpl& context); void updateContextState(ContextImpl& context);
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy) { double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
// This force doesn't apply forces to particles. // This force doesn't apply forces to particles.
return 0.0; return 0.0;
} }
......
...@@ -181,9 +181,11 @@ public: ...@@ -181,9 +181,11 @@ public:
* *
* @param includeForces true if forces should be calculated * @param includeForces true if forces should be calculated
* @param includeEnergy true if the energy should be calculated * @param includeEnergy true if the energy should be calculated
* @param groups a set of bit flags for which force groups to include. Group i will be included
* if (groups&(1<<i)) != 0. The default value includes all groups.
* @return the potential energy of the system, or 0 if includeEnergy is false * @return the potential energy of the system, or 0 if includeEnergy is false
*/ */
double calcForcesAndEnergy(bool includeForces, bool includeEnergy); double calcForcesAndEnergy(bool includeForces, bool includeEnergy, int groups=0xFFFFFFFF);
/** /**
* Calculate the kinetic energy of the system (in kJ/mol). * Calculate the kinetic energy of the system (in kJ/mol).
*/ */
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
private: private:
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
std::vector<std::pair<int, int> > getBondedParticles() const; std::vector<std::pair<int, int> > getBondedParticles() const;
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
private: private:
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
private: private:
......
...@@ -59,7 +59,7 @@ public: ...@@ -59,7 +59,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
/** /**
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
private: private:
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters(); std::map<std::string, double> getDefaultParameters();
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
private: private:
......
...@@ -82,10 +82,12 @@ public: ...@@ -82,10 +82,12 @@ public:
* @param context the context in which the system is being simulated * @param context the context in which the system is being simulated
* @param includeForces true if forces should be calculated * @param includeForces true if forces should be calculated
* @param includeEnergy true if the energy should be calculated * @param includeEnergy true if the energy should be calculated
* @param groups a set of bit flags for which force groups to include. Group i should be included
* if (groups&(1<<i)) != 0.
* @return this force's contribution to the potential energy of the system, or 0 if this * @return this force's contribution to the potential energy of the system, or 0 if this
* force does not contribute to potential energy (or if includeEnergy is false) * force does not contribute to potential energy (or if includeEnergy is false)
*/ */
virtual double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy) = 0; virtual double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) = 0;
/** /**
* Get a map containing the default values for all adjustable parameters defined by this ForceImpl. These * Get a map containing the default values for all adjustable parameters defined by this ForceImpl. These
* parameters and their default values will automatically be added to the Context. * parameters and their default values will automatically be added to the Context.
......
...@@ -53,7 +53,7 @@ public: ...@@ -53,7 +53,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() { std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force field doesn't define any parameters. return std::map<std::string, double>(); // This force field doesn't define any parameters.
} }
......
...@@ -62,7 +62,7 @@ public: ...@@ -62,7 +62,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() { std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force field doesn't define any parameters. return std::map<std::string, double>(); // This force field doesn't define any parameters.
} }
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() { std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force field doesn't define any parameters. return std::map<std::string, double>(); // This force field doesn't define any parameters.
} }
......
...@@ -56,7 +56,7 @@ public: ...@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) { void updateContextState(ContextImpl& context) {
// This force field doesn't update the state directly. // This force field doesn't update the state directly.
} }
double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy); double calcForcesAndEnergy(ContextImpl& context, bool includeForces, bool includeEnergy, int groups);
std::map<std::string, double> getDefaultParameters() { std::map<std::string, double> getDefaultParameters() {
return std::map<std::string, double>(); // This force field doesn't define any parameters. return std::map<std::string, double>(); // This force field doesn't define any parameters.
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment