Commit 3adfe31f authored by Peter Eastman's avatar Peter Eastman
Browse files

Implemented VariableVerletIntegrator::stepTo()

parent 63539a8b
...@@ -441,8 +441,9 @@ public: ...@@ -441,8 +441,9 @@ public:
* *
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param integrator the VerletIntegrator this kernel is being used for * @param integrator the VerletIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced
*/ */
virtual void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator) = 0; virtual void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) = 0;
}; };
/** /**
......
...@@ -56,14 +56,14 @@ public: ...@@ -56,14 +56,14 @@ public:
} }
/** /**
* Get the size of each time step, in picoseconds. If this integrator uses variable time steps, * Get the size of each time step, in picoseconds. If this integrator uses variable time steps,
* this is the initial step size that will be attempted for the next step. * the size of the most recent step is returned.
*/ */
double getStepSize() const { double getStepSize() const {
return stepSize; return stepSize;
} }
/** /**
* Set the size of each time step, in picoseconds. If this integrator uses variable time steps, * Set the size of each time step, in picoseconds. If this integrator uses variable time steps,
* this is the initial step size that will be attempted for the next step. * the effect of calling this method is undefined, and it may simply be ignored.
*/ */
void setStepSize(double size) { void setStepSize(double size) {
stepSize = size; stepSize = size;
......
...@@ -78,12 +78,21 @@ public: ...@@ -78,12 +78,21 @@ public:
void setErrorTolerance(double tol) { void setErrorTolerance(double tol) {
errorTol = tol; errorTol = tol;
} }
/** /**
* Advance a simulation through time by taking a series of time steps. * Advance a simulation through time by taking a series of time steps.
* *
* @param steps the number of time steps to take * @param steps the number of time steps to take
*/ */
void step(int steps); void step(int steps);
/**
* Advance a simulation through time by taking a series of steps until a specified time is
* reached. When this method returns, the simulation time will exactly equal the time which
* was specified. If you call this method and specify a time that is earlier than the
* current time, it will return without doing anything.
*
* @param time the time to which the simulation should be advanced
*/
void stepTo(double time);
protected: protected:
/** /**
* This will be called by the OpenMMContext when it is created. It informs the Integrator * This will be called by the OpenMMContext when it is created. It informs the Integrator
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "openmm/OpenMMContext.h" #include "openmm/OpenMMContext.h"
#include "openmm/internal/OpenMMContextImpl.h" #include "openmm/internal/OpenMMContextImpl.h"
#include "openmm/kernels.h" #include "openmm/kernels.h"
#include <limits>
#include <string> #include <string>
using namespace OpenMM; using namespace OpenMM;
...@@ -59,7 +60,14 @@ void VariableVerletIntegrator::step(int steps) { ...@@ -59,7 +60,14 @@ void VariableVerletIntegrator::step(int steps) {
for (int i = 0; i < steps; ++i) { for (int i = 0; i < steps; ++i) {
context->updateContextState(); context->updateContextState();
context->calcForces(); context->calcForces();
dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this); dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this, std::numeric_limits<double>::infinity());
} }
} }
void VariableVerletIntegrator::stepTo(double time) {
while (time > context->getTime()) {
context->updateContextState();
context->calcForces();
dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this, time);
}
}
...@@ -562,7 +562,7 @@ void CudaIntegrateVariableVerletStepKernel::initialize(const System& system, con ...@@ -562,7 +562,7 @@ void CudaIntegrateVariableVerletStepKernel::initialize(const System& system, con
prevErrorTol = -1.0; prevErrorTol = -1.0;
} }
void CudaIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator) { void CudaIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
_gpuContext* gpu = data.gpu; _gpuContext* gpu = data.gpu;
double errorTol = integrator.getErrorTolerance(); double errorTol = integrator.getErrorTolerance();
if (errorTol != prevErrorTol) { if (errorTol != prevErrorTol) {
...@@ -572,7 +572,8 @@ void CudaIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, ...@@ -572,7 +572,8 @@ void CudaIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context,
gpuSetConstants(gpu); gpuSetConstants(gpu);
prevErrorTol = errorTol; prevErrorTol = errorTol;
} }
kSelectVerletStepSize(gpu); float maxStepSize = maxTime-data.time;
kSelectVerletStepSize(gpu, maxStepSize);
kVerletUpdatePart1(gpu); kVerletUpdatePart1(gpu);
kApplyFirstShake(gpu); kApplyFirstShake(gpu);
kApplyFirstSettle(gpu); kApplyFirstSettle(gpu);
...@@ -583,6 +584,8 @@ void CudaIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, ...@@ -583,6 +584,8 @@ void CudaIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context,
kVerletUpdatePart2(gpu); kVerletUpdatePart2(gpu);
gpu->psStepSize->Download(); gpu->psStepSize->Download();
data.time += (*gpu->psStepSize)[0].y; data.time += (*gpu->psStepSize)[0].y;
if ((*gpu->psStepSize)[0].y == maxStepSize)
data.time = maxTime; // Avoid round-off error
data.stepCount++; data.stepCount++;
} }
......
...@@ -393,8 +393,9 @@ public: ...@@ -393,8 +393,9 @@ public:
* *
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param integrator the VerletIntegrator this kernel is being used for * @param integrator the VerletIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced
*/ */
void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator); void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime);
private: private:
CudaPlatform::PlatformData& data; CudaPlatform::PlatformData& data;
double prevErrorTol; double prevErrorTol;
......
...@@ -50,7 +50,7 @@ extern void kLangevinUpdatePart1(gpuContext gpu); ...@@ -50,7 +50,7 @@ extern void kLangevinUpdatePart1(gpuContext gpu);
extern void kLangevinUpdatePart2(gpuContext gpu); extern void kLangevinUpdatePart2(gpuContext gpu);
extern void kVerletUpdatePart1(gpuContext gpu); extern void kVerletUpdatePart1(gpuContext gpu);
extern void kVerletUpdatePart2(gpuContext gpu); extern void kVerletUpdatePart2(gpuContext gpu);
extern void kSelectVerletStepSize(gpuContext gpu); extern void kSelectVerletStepSize(gpuContext gpu, float maxTimeStep);
extern void kBrownianUpdatePart1(gpuContext gpu); extern void kBrownianUpdatePart1(gpuContext gpu);
extern void kBrownianUpdatePart2(gpuContext gpu); extern void kBrownianUpdatePart2(gpuContext gpu);
......
...@@ -89,7 +89,7 @@ void kVerletUpdatePart2(gpuContext gpu) ...@@ -89,7 +89,7 @@ void kVerletUpdatePart2(gpuContext gpu)
} }
} }
__global__ void kSelectVerletStepSize_kernel() __global__ void kSelectVerletStepSize_kernel(float maxStepSize)
{ {
// Calculate the error. // Calculate the error.
...@@ -121,14 +121,16 @@ __global__ void kSelectVerletStepSize_kernel() ...@@ -121,14 +121,16 @@ __global__ void kSelectVerletStepSize_kernel()
newStepSize = min(newStepSize, oldStepSize*2.0f); // For safety, limit how quickly dt can increase. newStepSize = min(newStepSize, oldStepSize*2.0f); // For safety, limit how quickly dt can increase.
if (newStepSize > oldStepSize && newStepSize < 1.1f*oldStepSize) if (newStepSize > oldStepSize && newStepSize < 1.1f*oldStepSize)
newStepSize = oldStepSize; // Keeping dt constant between steps improves the behavior of the integrator. newStepSize = oldStepSize; // Keeping dt constant between steps improves the behavior of the integrator.
if (newStepSize > maxStepSize)
newStepSize = maxStepSize;
cSim.pStepSize[0].y = newStepSize; cSim.pStepSize[0].y = newStepSize;
} }
} }
void kSelectVerletStepSize(gpuContext gpu) void kSelectVerletStepSize(gpuContext gpu, float maxTimeStep)
{ {
// printf("kSelectVerletStepSize\n"); // printf("kSelectVerletStepSize\n");
kSelectVerletStepSize_kernel<<<1, gpu->sim.update_threads_per_block, sizeof(float)*gpu->sim.update_threads_per_block>>>(); kSelectVerletStepSize_kernel<<<1, gpu->sim.update_threads_per_block, sizeof(float)*gpu->sim.update_threads_per_block>>>(maxTimeStep);
LAUNCHERROR("kSelectVerletStepSize"); LAUNCHERROR("kSelectVerletStepSize");
} }
......
...@@ -136,6 +136,14 @@ void testConstraints() { ...@@ -136,6 +136,14 @@ void testConstraints() {
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1);
integrator.step(1); integrator.step(1);
} }
double finalTime = context.getState(State::Positions).getTime();
ASSERT(finalTime > 0.1);
// Now try the stepTo() method.
finalTime += 0.5;
integrator.stepTo(finalTime);
ASSERT_EQUAL(finalTime, context.getState(State::Positions).getTime());
} }
void testConstrainedClusters() { void testConstrainedClusters() {
...@@ -198,6 +206,7 @@ void testConstrainedClusters() { ...@@ -198,6 +206,7 @@ void testConstrainedClusters() {
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05);
integrator.step(1); integrator.step(1);
} }
ASSERT(context.getState(State::Positions).getTime() > 0.1);
} }
int main() { int main() {
......
...@@ -62,8 +62,9 @@ private: ...@@ -62,8 +62,9 @@ private:
class ReferencePlatform::PlatformData { class ReferencePlatform::PlatformData {
public: public:
PlatformData() : time(0.0) { PlatformData() : time(0.0), stepCount(0) {
} }
int stepCount;
double time; double time;
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -71,6 +71,6 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla ...@@ -71,6 +71,6 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla
if (name == CalcKineticEnergyKernel::Name()) if (name == CalcKineticEnergyKernel::Name())
return new ReferenceCalcKineticEnergyKernel(name, platform); return new ReferenceCalcKineticEnergyKernel(name, platform);
if (name == RemoveCMMotionKernel::Name()) if (name == RemoveCMMotionKernel::Name())
return new ReferenceRemoveCMMotionKernel(name, platform); return new ReferenceRemoveCMMotionKernel(name, platform, data);
throw OpenMMException( (std::string("Tried to create kernel with illegal kernel name '") + name + "'").c_str() ); throw OpenMMException( (std::string("Tried to create kernel with illegal kernel name '") + name + "'").c_str() );
} }
...@@ -655,6 +655,7 @@ void ReferenceIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, con ...@@ -655,6 +655,7 @@ void ReferenceIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, con
} }
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses); dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += stepSize; data.time += stepSize;
data.stepCount++;
} }
ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() { ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() {
...@@ -719,6 +720,7 @@ void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, c ...@@ -719,6 +720,7 @@ void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, c
} }
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses); dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += stepSize; data.time += stepSize;
data.stepCount++;
} }
ReferenceIntegrateBrownianStepKernel::~ReferenceIntegrateBrownianStepKernel() { ReferenceIntegrateBrownianStepKernel::~ReferenceIntegrateBrownianStepKernel() {
...@@ -782,6 +784,7 @@ void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, c ...@@ -782,6 +784,7 @@ void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, c
} }
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses); dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += stepSize; data.time += stepSize;
data.stepCount++;
} }
ReferenceIntegrateVariableVerletStepKernel::~ReferenceIntegrateVariableVerletStepKernel() { ReferenceIntegrateVariableVerletStepKernel::~ReferenceIntegrateVariableVerletStepKernel() {
...@@ -815,7 +818,7 @@ void ReferenceIntegrateVariableVerletStepKernel::initialize(const System& system ...@@ -815,7 +818,7 @@ void ReferenceIntegrateVariableVerletStepKernel::initialize(const System& system
} }
} }
void ReferenceIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator) { void ReferenceIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
double errorTol = integrator.getErrorTolerance(); double errorTol = integrator.getErrorTolerance();
RealOpenMM** posData = ((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData(); RealOpenMM** posData = ((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData();
RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData(); RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
...@@ -834,8 +837,12 @@ void ReferenceIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& cont ...@@ -834,8 +837,12 @@ void ReferenceIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& cont
dynamics->setReferenceConstraintAlgorithm(constraints); dynamics->setReferenceConstraintAlgorithm(constraints);
prevErrorTol = errorTol; prevErrorTol = errorTol;
} }
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses); RealOpenMM maxStepSize = (RealOpenMM) (maxTime-data.time);
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses, maxStepSize);
data.time += dynamics->getDeltaT(); data.time += dynamics->getDeltaT();
if (dynamics->getDeltaT() == maxStepSize)
data.time = maxTime; // Avoid round-off error
data.stepCount++;
} }
ReferenceApplyAndersenThermostatKernel::~ReferenceApplyAndersenThermostatKernel() { ReferenceApplyAndersenThermostatKernel::~ReferenceApplyAndersenThermostatKernel() {
...@@ -888,8 +895,7 @@ void ReferenceRemoveCMMotionKernel::initialize(const System& system, const CMMot ...@@ -888,8 +895,7 @@ void ReferenceRemoveCMMotionKernel::initialize(const System& system, const CMMot
} }
void ReferenceRemoveCMMotionKernel::execute(OpenMMContextImpl& context) { void ReferenceRemoveCMMotionKernel::execute(OpenMMContextImpl& context) {
int step = (int)std::floor(context.getTime()/context.getIntegrator().getStepSize()); if (data.stepCount%frequency != 0)
if (step%frequency != 0)
return; return;
RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData(); RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
......
...@@ -463,8 +463,9 @@ public: ...@@ -463,8 +463,9 @@ public:
* *
* @param context the context in which to execute this kernel * @param context the context in which to execute this kernel
* @param integrator the VerletIntegrator this kernel is being used for * @param integrator the VerletIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced
*/ */
void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator); void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime);
private: private:
ReferencePlatform::PlatformData& data; ReferencePlatform::PlatformData& data;
ReferenceVariableVerletDynamics* dynamics; ReferenceVariableVerletDynamics* dynamics;
...@@ -530,7 +531,7 @@ private: ...@@ -530,7 +531,7 @@ private:
*/ */
class ReferenceRemoveCMMotionKernel : public RemoveCMMotionKernel { class ReferenceRemoveCMMotionKernel : public RemoveCMMotionKernel {
public: public:
ReferenceRemoveCMMotionKernel(std::string name, const Platform& platform) : RemoveCMMotionKernel(name, platform) { ReferenceRemoveCMMotionKernel(std::string name, const Platform& platform, ReferencePlatform::PlatformData& data) : RemoveCMMotionKernel(name, platform), data(data) {
} }
/** /**
* Initialize the kernel, setting up the particle masses. * Initialize the kernel, setting up the particle masses.
...@@ -546,6 +547,7 @@ public: ...@@ -546,6 +547,7 @@ public:
*/ */
void execute(OpenMMContextImpl& context); void execute(OpenMMContextImpl& context);
private: private:
ReferencePlatform::PlatformData& data;
std::vector<double> masses; std::vector<double> masses;
int frequency; int frequency;
}; };
......
...@@ -131,6 +131,7 @@ int ReferenceVariableVerletDynamics::printParameters( std::stringstream& message ...@@ -131,6 +131,7 @@ int ReferenceVariableVerletDynamics::printParameters( std::stringstream& message
@param velocities velocities @param velocities velocities
@param forces forces @param forces forces
@param masses atom masses @param masses atom masses
@param maxStepSize maximum time step
@return ReferenceDynamics::DefaultReturn @return ReferenceDynamics::DefaultReturn
...@@ -138,7 +139,7 @@ int ReferenceVariableVerletDynamics::printParameters( std::stringstream& message ...@@ -138,7 +139,7 @@ int ReferenceVariableVerletDynamics::printParameters( std::stringstream& message
int ReferenceVariableVerletDynamics::update( int numberOfAtoms, RealOpenMM** atomCoordinates, int ReferenceVariableVerletDynamics::update( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities, RealOpenMM** velocities,
RealOpenMM** forces, RealOpenMM* masses ){ RealOpenMM** forces, RealOpenMM* masses, RealOpenMM maxStepSize ){
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
...@@ -195,6 +196,8 @@ int ReferenceVariableVerletDynamics::update( int numberOfAtoms, RealOpenMM** ato ...@@ -195,6 +196,8 @@ int ReferenceVariableVerletDynamics::update( int numberOfAtoms, RealOpenMM** ato
newStepSize = std::min(newStepSize, getDeltaT()*2.0f); // For safety, limit how quickly dt can increase. newStepSize = std::min(newStepSize, getDeltaT()*2.0f); // For safety, limit how quickly dt can increase.
if (newStepSize > getDeltaT() && newStepSize < 1.2f*getDeltaT()) if (newStepSize > getDeltaT() && newStepSize < 1.2f*getDeltaT())
newStepSize = getDeltaT(); // Keeping dt constant between steps improves the behavior of the integrator. newStepSize = getDeltaT(); // Keeping dt constant between steps improves the behavior of the integrator.
if (newStepSize > maxStepSize)
newStepSize = maxStepSize;
RealOpenMM vstep = 0.5f*(newStepSize+getDeltaT()); // The time interval by which to advance the velocities RealOpenMM vstep = 0.5f*(newStepSize+getDeltaT()); // The time interval by which to advance the velocities
setDeltaT(newStepSize); setDeltaT(newStepSize);
for (int i = 0; i < numberOfAtoms; ++i) { for (int i = 0; i < numberOfAtoms; ++i) {
......
...@@ -97,13 +97,14 @@ class ReferenceVariableVerletDynamics : public ReferenceDynamics { ...@@ -97,13 +97,14 @@ class ReferenceVariableVerletDynamics : public ReferenceDynamics {
@param velocities velocities @param velocities velocities
@param forces forces @param forces forces
@param masses atom masses @param masses atom masses
@param maxStepSize maximum time step
@return ReferenceDynamics::DefaultReturn @return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
int update( int numberOfAtoms, RealOpenMM** atomCoordinates, int update( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities, RealOpenMM** forces, RealOpenMM* masses ); RealOpenMM** velocities, RealOpenMM** forces, RealOpenMM* masses, RealOpenMM maxStepSize );
}; };
......
...@@ -133,7 +133,14 @@ void testConstraints() { ...@@ -133,7 +133,14 @@ void testConstraints() {
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1);
integrator.step(1); integrator.step(1);
} }
ASSERT(context.getState(State::Positions).getTime() > 0.1); double finalTime = context.getState(State::Positions).getTime();
ASSERT(finalTime > 0.1);
// Now try the stepTo() method.
finalTime += 0.5;
integrator.stepTo(finalTime);
ASSERT_EQUAL(finalTime, context.getState(State::Positions).getTime());
} }
void testConstrainedClusters() { void testConstrainedClusters() {
......
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