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:
* @param context the context in which to execute this kernel
* @param includeForce true if forces 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
* every ForceImpl.
......@@ -98,11 +99,12 @@ public:
* @param context the context in which to execute this kernel
* @param includeForce true if forces 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'
* 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.
*/
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:
* @param context the context in which to execute this kernel
* @param includeForces true if forces 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
*/
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 {
* 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
* 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
* freedom is associated with.</li>
* <li>uniform: (either global or per-DOF, read-only) This is a uniformly
......@@ -162,6 +165,22 @@ namespace OpenMM {
* risk invalidating the forces just before the first velocity update, thus
* 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
* 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
......
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* 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 *
* Contributors: *
* *
......@@ -51,13 +51,31 @@ class ForceImpl;
* <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>
* </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 {
public:
Force() {}
Force() : forceGroup(0) {
}
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:
friend class ContextImpl;
/**
......@@ -66,6 +84,8 @@ protected:
* The ForceImpl will be deleted automatically when the Context is deleted.
*/
virtual ForceImpl* createImpl() = 0;
private:
int forceGroup;
};
} // namespace OpenMM
......
......@@ -263,6 +263,22 @@ public:
void setUseDispersionCorrection(bool 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:
ForceImpl* createImpl();
private:
......@@ -271,6 +287,7 @@ private:
NonbondedMethod nonbondedMethod;
double cutoffDistance, rfDielectric, ewaldErrorTol;
bool useDispersionCorrection;
int recipForceGroup;
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<ExceptionInfo> exceptions;
......
......@@ -53,7 +53,7 @@ public:
return owner;
}
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.
return 0.0;
}
......
......@@ -55,7 +55,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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() {
return std::map<std::string, double>(); // This force field doesn't define any parameters.
}
......
......@@ -50,7 +50,7 @@ public:
return owner;
}
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.
return 0.0;
}
......
......@@ -181,9 +181,11 @@ public:
*
* @param includeForces true if forces 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
*/
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).
*/
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
private:
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
std::vector<std::pair<int, int> > getBondedParticles() const;
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
private:
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
private:
......
......@@ -59,7 +59,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
/**
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
private:
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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::vector<std::string> getKernelNames();
private:
......
......@@ -82,10 +82,12 @@ public:
* @param context the context in which the system is being simulated
* @param includeForces true if forces 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
* 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
* parameters and their default values will automatically be added to the Context.
......
......@@ -53,7 +53,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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() {
return std::map<std::string, double>(); // This force field doesn't define any parameters.
}
......
......@@ -62,7 +62,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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() {
return std::map<std::string, double>(); // This force field doesn't define any parameters.
}
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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() {
return std::map<std::string, double>(); // This force field doesn't define any parameters.
}
......
......@@ -56,7 +56,7 @@ public:
void updateContextState(ContextImpl& context) {
// 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() {
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