"vscode:/vscode.git/clone" did not exist on "909125ffd5ac28b54fbe318d35a1de2c5d2a67b8"
Commit 761b4bbf authored by Peter Eastman's avatar Peter Eastman
Browse files

Variable time step integrators correctly report the size of the last step...

Variable time step integrators correctly report the size of the last step taken.  Also improved accuracy of integration unit tests.
parent 420fac9c
...@@ -780,8 +780,9 @@ public: ...@@ -780,8 +780,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 LangevinIntegrator this kernel is being used for * @param integrator the LangevinIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
virtual void execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) = 0; virtual double execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) = 0;
}; };
/** /**
...@@ -807,8 +808,9 @@ public: ...@@ -807,8 +808,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 * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
virtual void execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) = 0; virtual double execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) = 0;
}; };
/** /**
......
...@@ -69,7 +69,7 @@ void VariableLangevinIntegrator::step(int steps) { ...@@ -69,7 +69,7 @@ void VariableLangevinIntegrator::step(int steps) {
for (int i = 0; i < steps; ++i) { for (int i = 0; i < steps; ++i) {
context->updateContextState(); context->updateContextState();
context->calcForcesAndEnergy(true, false); context->calcForcesAndEnergy(true, false);
dynamic_cast<IntegrateVariableLangevinStepKernel&>(kernel.getImpl()).execute(*context, *this, std::numeric_limits<double>::infinity()); setStepSize(dynamic_cast<IntegrateVariableLangevinStepKernel&>(kernel.getImpl()).execute(*context, *this, std::numeric_limits<double>::infinity()));
} }
} }
...@@ -77,6 +77,6 @@ void VariableLangevinIntegrator::stepTo(double time) { ...@@ -77,6 +77,6 @@ void VariableLangevinIntegrator::stepTo(double time) {
while (time > context->getTime()) { while (time > context->getTime()) {
context->updateContextState(); context->updateContextState();
context->calcForcesAndEnergy(true, false); context->calcForcesAndEnergy(true, false);
dynamic_cast<IntegrateVariableLangevinStepKernel&>(kernel.getImpl()).execute(*context, *this, time); setStepSize(dynamic_cast<IntegrateVariableLangevinStepKernel&>(kernel.getImpl()).execute(*context, *this, time));
} }
} }
...@@ -64,7 +64,7 @@ void VariableVerletIntegrator::step(int steps) { ...@@ -64,7 +64,7 @@ void VariableVerletIntegrator::step(int steps) {
for (int i = 0; i < steps; ++i) { for (int i = 0; i < steps; ++i) {
context->updateContextState(); context->updateContextState();
context->calcForcesAndEnergy(true, false); context->calcForcesAndEnergy(true, false);
dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this, std::numeric_limits<double>::infinity()); setStepSize(dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this, std::numeric_limits<double>::infinity()));
} }
} }
...@@ -72,6 +72,6 @@ void VariableVerletIntegrator::stepTo(double time) { ...@@ -72,6 +72,6 @@ void VariableVerletIntegrator::stepTo(double time) {
while (time > context->getTime()) { while (time > context->getTime()) {
context->updateContextState(); context->updateContextState();
context->calcForcesAndEnergy(true, false); context->calcForcesAndEnergy(true, false);
dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this, time); setStepSize(dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this, time));
} }
} }
...@@ -1343,7 +1343,7 @@ void CudaIntegrateVariableVerletStepKernel::initialize(const System& system, con ...@@ -1343,7 +1343,7 @@ void CudaIntegrateVariableVerletStepKernel::initialize(const System& system, con
prevErrorTol = -1.0; prevErrorTol = -1.0;
} }
void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) { double CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& 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) {
...@@ -1368,6 +1368,7 @@ void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const ...@@ -1368,6 +1368,7 @@ void CudaIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const
if ((*gpu->psStepSize)[0].y == maxStepSize) if ((*gpu->psStepSize)[0].y == maxStepSize)
data.time = maxTime; // Avoid round-off error data.time = maxTime; // Avoid round-off error
data.stepCount++; data.stepCount++;
return (*gpu->psStepSize)[0].y;
} }
CudaIntegrateVariableLangevinStepKernel::~CudaIntegrateVariableLangevinStepKernel() { CudaIntegrateVariableLangevinStepKernel::~CudaIntegrateVariableLangevinStepKernel() {
...@@ -1383,7 +1384,7 @@ void CudaIntegrateVariableLangevinStepKernel::initialize(const System& system, c ...@@ -1383,7 +1384,7 @@ void CudaIntegrateVariableLangevinStepKernel::initialize(const System& system, c
prevErrorTol = -1.0; prevErrorTol = -1.0;
} }
void CudaIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) { double CudaIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) {
_gpuContext* gpu = data.gpu; _gpuContext* gpu = data.gpu;
double temperature = integrator.getTemperature(); double temperature = integrator.getTemperature();
double friction = integrator.getFriction(); double friction = integrator.getFriction();
...@@ -1415,6 +1416,7 @@ void CudaIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, cons ...@@ -1415,6 +1416,7 @@ void CudaIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, cons
if ((*gpu->psStepSize)[0].y == maxStepSize) if ((*gpu->psStepSize)[0].y == maxStepSize)
data.time = maxTime; // Avoid round-off error data.time = maxTime; // Avoid round-off error
data.stepCount++; data.stepCount++;
return (*gpu->psStepSize)[0].y;
} }
CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() { CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
......
...@@ -734,8 +734,9 @@ public: ...@@ -734,8 +734,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 * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
void execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime); double execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime);
private: private:
CudaPlatform::PlatformData& data; CudaPlatform::PlatformData& data;
double prevErrorTol; double prevErrorTol;
...@@ -762,8 +763,9 @@ public: ...@@ -762,8 +763,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 VariableLangevinIntegrator this kernel is being used for * @param integrator the VariableLangevinIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
void execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime); double execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime);
private: private:
CudaPlatform::PlatformData& data; CudaPlatform::PlatformData& data;
double prevTemp, prevFriction, prevErrorTol; double prevTemp, prevFriction, prevErrorTol;
......
...@@ -50,6 +50,23 @@ using namespace std; ...@@ -50,6 +50,23 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
/**
* Compute the energy of a state, taking into account the half step offset between
* positions and velocities.
*/
static double computeEnergy(const State& state, const System& system, double dt) {
const vector<Vec3>& v = state.getVelocities();
const vector<Vec3>& f = state.getForces();
double energy = 0.0;
for (int i = 0; i < system.getNumParticles(); i++) {
double m = system.getParticleMass(i);
Vec3 vel = v[i]+f[i]*(0.5*dt/m);
energy += 0.5*m*vel.dot(vel);
}
return energy+state.getPotentialEnergy();
}
void testSingleBond() { void testSingleBond() {
CudaPlatform platform; CudaPlatform platform;
System system; System system;
...@@ -121,7 +138,7 @@ void testConstraints() { ...@@ -121,7 +138,7 @@ void testConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < numConstraints; ++j) { for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -131,11 +148,11 @@ void testConstraints() { ...@@ -131,11 +148,11 @@ void testConstraints() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4); ASSERT_EQUAL_TOL(distance, dist, 1e-4);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
double finalTime = context.getState(State::Positions).getTime(); double finalTime = context.getState(State::Positions).getTime();
...@@ -193,7 +210,7 @@ void testConstrainedClusters() { ...@@ -193,7 +210,7 @@ void testConstrainedClusters() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -203,11 +220,11 @@ void testConstrainedClusters() { ...@@ -203,11 +220,11 @@ void testConstrainedClusters() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
ASSERT(context.getState(State::Positions).getTime() > 0.1); ASSERT(context.getState(State::Positions).getTime() > 0.1);
......
...@@ -50,6 +50,23 @@ using namespace std; ...@@ -50,6 +50,23 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
/**
* Compute the energy of a state, taking into account the half step offset between
* positions and velocities.
*/
static double computeEnergy(const State& state, const System& system, double dt) {
const vector<Vec3>& v = state.getVelocities();
const vector<Vec3>& f = state.getForces();
double energy = 0.0;
for (int i = 0; i < system.getNumParticles(); i++) {
double m = system.getParticleMass(i);
Vec3 vel = v[i]+f[i]*(0.5*dt/m);
energy += 0.5*m*vel.dot(vel);
}
return energy+state.getPotentialEnergy();
}
void testSingleBond() { void testSingleBond() {
CudaPlatform platform; CudaPlatform platform;
System system; System system;
...@@ -121,7 +138,7 @@ void testConstraints() { ...@@ -121,7 +138,7 @@ void testConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < numConstraints; ++j) { for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -131,11 +148,11 @@ void testConstraints() { ...@@ -131,11 +148,11 @@ void testConstraints() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4); ASSERT_EQUAL_TOL(distance, dist, 1e-4);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
} }
...@@ -145,7 +162,7 @@ void testConstrainedClusters() { ...@@ -145,7 +162,7 @@ void testConstrainedClusters() {
const double temp = 500.0; const double temp = 500.0;
CudaPlatform platform; CudaPlatform platform;
System system; System system;
VerletIntegrator integrator(0.002); VerletIntegrator integrator(0.001);
integrator.setConstraintTolerance(1e-5); integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce(); NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) { for (int i = 0; i < numParticles; ++i) {
...@@ -185,7 +202,7 @@ void testConstrainedClusters() { ...@@ -185,7 +202,7 @@ void testConstrainedClusters() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -195,11 +212,11 @@ void testConstrainedClusters() { ...@@ -195,11 +212,11 @@ void testConstrainedClusters() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
} }
......
...@@ -3400,7 +3400,7 @@ void OpenCLIntegrateVariableVerletStepKernel::initialize(const System& system, c ...@@ -3400,7 +3400,7 @@ void OpenCLIntegrateVariableVerletStepKernel::initialize(const System& system, c
blockSize = std::min(std::min(256, system.getNumParticles()), (int) cl.getDevice().getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>()); blockSize = std::min(std::min(256, system.getNumParticles()), (int) cl.getDevice().getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>());
} }
void OpenCLIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) { double OpenCLIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
OpenCLIntegrationUtilities& integration = cl.getIntegrationUtilities(); OpenCLIntegrationUtilities& integration = cl.getIntegrationUtilities();
int numAtoms = cl.getNumAtoms(); int numAtoms = cl.getNumAtoms();
if (!hasInitializedKernels) { if (!hasInitializedKernels) {
...@@ -3452,6 +3452,7 @@ void OpenCLIntegrateVariableVerletStepKernel::execute(ContextImpl& context, cons ...@@ -3452,6 +3452,7 @@ void OpenCLIntegrateVariableVerletStepKernel::execute(ContextImpl& context, cons
time = maxTime; // Avoid round-off error time = maxTime; // Avoid round-off error
cl.setTime(time); cl.setTime(time);
cl.setStepCount(cl.getStepCount()+1); cl.setStepCount(cl.getStepCount()+1);
return dt;
} }
OpenCLIntegrateVariableLangevinStepKernel::~OpenCLIntegrateVariableLangevinStepKernel() { OpenCLIntegrateVariableLangevinStepKernel::~OpenCLIntegrateVariableLangevinStepKernel() {
...@@ -3475,7 +3476,7 @@ void OpenCLIntegrateVariableLangevinStepKernel::initialize(const System& system, ...@@ -3475,7 +3476,7 @@ void OpenCLIntegrateVariableLangevinStepKernel::initialize(const System& system,
blockSize = std::min(blockSize, (int) cl.getDevice().getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>()); blockSize = std::min(blockSize, (int) cl.getDevice().getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>());
} }
void OpenCLIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) { double OpenCLIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) {
OpenCLIntegrationUtilities& integration = cl.getIntegrationUtilities(); OpenCLIntegrationUtilities& integration = cl.getIntegrationUtilities();
int numAtoms = cl.getNumAtoms(); int numAtoms = cl.getNumAtoms();
if (!hasInitializedKernels) { if (!hasInitializedKernels) {
...@@ -3530,6 +3531,7 @@ void OpenCLIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, co ...@@ -3530,6 +3531,7 @@ void OpenCLIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, co
time = maxTime; // Avoid round-off error time = maxTime; // Avoid round-off error
cl.setTime(time); cl.setTime(time);
cl.setStepCount(cl.getStepCount()+1); cl.setStepCount(cl.getStepCount()+1);
return dt;
} }
class OpenCLIntegrateCustomStepKernel::ReorderListener : public OpenCLContext::ReorderListener { class OpenCLIntegrateCustomStepKernel::ReorderListener : public OpenCLContext::ReorderListener {
......
...@@ -875,8 +875,9 @@ public: ...@@ -875,8 +875,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 * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
void execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime); double execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime);
private: private:
OpenCLContext& cl; OpenCLContext& cl;
bool hasInitializedKernels; bool hasInitializedKernels;
...@@ -906,8 +907,9 @@ public: ...@@ -906,8 +907,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 VariableLangevinIntegrator this kernel is being used for * @param integrator the VariableLangevinIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
void execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime); double execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime);
private: private:
OpenCLContext& cl; OpenCLContext& cl;
bool hasInitializedKernels; bool hasInitializedKernels;
......
...@@ -50,6 +50,23 @@ using namespace std; ...@@ -50,6 +50,23 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
/**
* Compute the energy of a state, taking into account the half step offset between
* positions and velocities.
*/
static double computeEnergy(const State& state, const System& system, double dt) {
const vector<Vec3>& v = state.getVelocities();
const vector<Vec3>& f = state.getForces();
double energy = 0.0;
for (int i = 0; i < system.getNumParticles(); i++) {
double m = system.getParticleMass(i);
Vec3 vel = v[i]+f[i]*(0.5*dt/m);
energy += 0.5*m*vel.dot(vel);
}
return energy+state.getPotentialEnergy();
}
void testSingleBond() { void testSingleBond() {
OpenCLPlatform platform; OpenCLPlatform platform;
System system; System system;
...@@ -121,7 +138,7 @@ void testConstraints() { ...@@ -121,7 +138,7 @@ void testConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < numConstraints; ++j) { for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -131,11 +148,11 @@ void testConstraints() { ...@@ -131,11 +148,11 @@ void testConstraints() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4); ASSERT_EQUAL_TOL(distance, dist, 1e-4);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
double finalTime = context.getState(State::Positions).getTime(); double finalTime = context.getState(State::Positions).getTime();
...@@ -193,7 +210,7 @@ void testConstrainedClusters() { ...@@ -193,7 +210,7 @@ void testConstrainedClusters() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -203,11 +220,11 @@ void testConstrainedClusters() { ...@@ -203,11 +220,11 @@ void testConstrainedClusters() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
ASSERT(context.getState(State::Positions).getTime() > 0.1); ASSERT(context.getState(State::Positions).getTime() > 0.1);
......
...@@ -50,6 +50,23 @@ using namespace std; ...@@ -50,6 +50,23 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
/**
* Compute the energy of a state, taking into account the half step offset between
* positions and velocities.
*/
static double computeEnergy(const State& state, const System& system, double dt) {
const vector<Vec3>& v = state.getVelocities();
const vector<Vec3>& f = state.getForces();
double energy = 0.0;
for (int i = 0; i < system.getNumParticles(); i++) {
double m = system.getParticleMass(i);
Vec3 vel = v[i]+f[i]*(0.5*dt/m);
energy += 0.5*m*vel.dot(vel);
}
return energy+state.getPotentialEnergy();
}
void testSingleBond() { void testSingleBond() {
OpenCLPlatform platform; OpenCLPlatform platform;
System system; System system;
...@@ -121,7 +138,7 @@ void testConstraints() { ...@@ -121,7 +138,7 @@ void testConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < numConstraints; ++j) { for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -131,11 +148,11 @@ void testConstraints() { ...@@ -131,11 +148,11 @@ void testConstraints() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4); ASSERT_EQUAL_TOL(distance, dist, 1e-4);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
} }
...@@ -145,7 +162,7 @@ void testConstrainedClusters() { ...@@ -145,7 +162,7 @@ void testConstrainedClusters() {
const double temp = 500.0; const double temp = 500.0;
OpenCLPlatform platform; OpenCLPlatform platform;
System system; System system;
VerletIntegrator integrator(0.002); VerletIntegrator integrator(0.001);
integrator.setConstraintTolerance(1e-5); integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce(); NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) { for (int i = 0; i < numParticles; ++i) {
...@@ -185,7 +202,7 @@ void testConstrainedClusters() { ...@@ -185,7 +202,7 @@ void testConstrainedClusters() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -195,11 +212,11 @@ void testConstrainedClusters() { ...@@ -195,11 +212,11 @@ void testConstrainedClusters() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
} }
......
...@@ -1447,7 +1447,7 @@ void ReferenceIntegrateVariableLangevinStepKernel::initialize(const System& syst ...@@ -1447,7 +1447,7 @@ void ReferenceIntegrateVariableLangevinStepKernel::initialize(const System& syst
SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) integrator.getRandomNumberSeed()); SimTKOpenMMUtilities::setRandomNumberSeed((unsigned int) integrator.getRandomNumberSeed());
} }
void ReferenceIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) { double ReferenceIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime) {
double temperature = integrator.getTemperature(); double temperature = integrator.getTemperature();
double friction = integrator.getFriction(); double friction = integrator.getFriction();
double errorTol = integrator.getErrorTolerance(); double errorTol = integrator.getErrorTolerance();
...@@ -1478,6 +1478,7 @@ void ReferenceIntegrateVariableLangevinStepKernel::execute(ContextImpl& context, ...@@ -1478,6 +1478,7 @@ void ReferenceIntegrateVariableLangevinStepKernel::execute(ContextImpl& context,
if (dynamics->getDeltaT() == maxStepSize) if (dynamics->getDeltaT() == maxStepSize)
data.time = maxTime; // Avoid round-off error data.time = maxTime; // Avoid round-off error
data.stepCount++; data.stepCount++;
return dynamics->getDeltaT();
} }
ReferenceIntegrateVariableVerletStepKernel::~ReferenceIntegrateVariableVerletStepKernel() { ReferenceIntegrateVariableVerletStepKernel::~ReferenceIntegrateVariableVerletStepKernel() {
...@@ -1509,7 +1510,7 @@ void ReferenceIntegrateVariableVerletStepKernel::initialize(const System& system ...@@ -1509,7 +1510,7 @@ void ReferenceIntegrateVariableVerletStepKernel::initialize(const System& system
} }
} }
void ReferenceIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) { double ReferenceIntegrateVariableVerletStepKernel::execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime) {
double errorTol = integrator.getErrorTolerance(); double errorTol = integrator.getErrorTolerance();
vector<RealVec>& posData = extractPositions(context); vector<RealVec>& posData = extractPositions(context);
vector<RealVec>& velData = extractVelocities(context); vector<RealVec>& velData = extractVelocities(context);
...@@ -1535,6 +1536,7 @@ void ReferenceIntegrateVariableVerletStepKernel::execute(ContextImpl& context, c ...@@ -1535,6 +1536,7 @@ void ReferenceIntegrateVariableVerletStepKernel::execute(ContextImpl& context, c
if (dynamics->getDeltaT() == maxStepSize) if (dynamics->getDeltaT() == maxStepSize)
data.time = maxTime; // Avoid round-off error data.time = maxTime; // Avoid round-off error
data.stepCount++; data.stepCount++;
return dynamics->getDeltaT();
} }
ReferenceIntegrateCustomStepKernel::~ReferenceIntegrateCustomStepKernel() { ReferenceIntegrateCustomStepKernel::~ReferenceIntegrateCustomStepKernel() {
......
...@@ -836,8 +836,9 @@ public: ...@@ -836,8 +836,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 LangevinIntegrator this kernel is being used for * @param integrator the LangevinIntegrator this kernel is being used for
* @param maxTime the maximum time beyond which the simulation should not be advanced * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
void execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime); double execute(ContextImpl& context, const VariableLangevinIntegrator& integrator, double maxTime);
private: private:
ReferencePlatform::PlatformData& data; ReferencePlatform::PlatformData& data;
ReferenceVariableStochasticDynamics* dynamics; ReferenceVariableStochasticDynamics* dynamics;
...@@ -871,8 +872,9 @@ public: ...@@ -871,8 +872,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 * @param maxTime the maximum time beyond which the simulation should not be advanced
* @return the size of the step that was taken
*/ */
void execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime); double execute(ContextImpl& context, const VariableVerletIntegrator& integrator, double maxTime);
private: private:
ReferencePlatform::PlatformData& data; ReferencePlatform::PlatformData& data;
ReferenceVariableVerletDynamics* dynamics; ReferenceVariableVerletDynamics* dynamics;
......
...@@ -50,6 +50,23 @@ using namespace std; ...@@ -50,6 +50,23 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
/**
* Compute the energy of a state, taking into account the half step offset between
* positions and velocities.
*/
static double computeEnergy(const State& state, const System& system, double dt) {
const vector<Vec3>& v = state.getVelocities();
const vector<Vec3>& f = state.getForces();
double energy = 0.0;
for (int i = 0; i < system.getNumParticles(); i++) {
double m = system.getParticleMass(i);
Vec3 vel = v[i]+f[i]*(0.5*dt/m);
energy += 0.5*m*vel.dot(vel);
}
return energy+state.getPotentialEnergy();
}
void testSingleBond() { void testSingleBond() {
ReferencePlatform platform; ReferencePlatform platform;
System system; System system;
...@@ -118,7 +135,7 @@ void testConstraints() { ...@@ -118,7 +135,7 @@ void testConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -128,11 +145,11 @@ void testConstraints() { ...@@ -128,11 +145,11 @@ void testConstraints() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
double finalTime = context.getState(State::Positions).getTime(); double finalTime = context.getState(State::Positions).getTime();
...@@ -190,7 +207,7 @@ void testConstrainedClusters() { ...@@ -190,7 +207,7 @@ void testConstrainedClusters() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -200,11 +217,11 @@ void testConstrainedClusters() { ...@@ -200,11 +217,11 @@ void testConstrainedClusters() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
ASSERT(context.getState(State::Positions).getTime() > 0.1); ASSERT(context.getState(State::Positions).getTime() > 0.1);
......
...@@ -50,6 +50,23 @@ using namespace std; ...@@ -50,6 +50,23 @@ using namespace std;
const double TOL = 1e-5; const double TOL = 1e-5;
/**
* Compute the energy of a state, taking into account the half step offset between
* positions and velocities.
*/
static double computeEnergy(const State& state, const System& system, double dt) {
const vector<Vec3>& v = state.getVelocities();
const vector<Vec3>& f = state.getForces();
double energy = 0.0;
for (int i = 0; i < system.getNumParticles(); i++) {
double m = system.getParticleMass(i);
Vec3 vel = v[i]+f[i]*(0.5*dt/m);
energy += 0.5*m*vel.dot(vel);
}
return energy+state.getPotentialEnergy();
}
void testSingleBond() { void testSingleBond() {
ReferencePlatform platform; ReferencePlatform platform;
System system; System system;
...@@ -117,7 +134,7 @@ void testConstraints() { ...@@ -117,7 +134,7 @@ void testConstraints() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -127,11 +144,11 @@ void testConstraints() { ...@@ -127,11 +144,11 @@ void testConstraints() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
} }
...@@ -141,7 +158,7 @@ void testConstrainedClusters() { ...@@ -141,7 +158,7 @@ void testConstrainedClusters() {
const double temp = 500.0; const double temp = 500.0;
ReferencePlatform platform; ReferencePlatform platform;
System system; System system;
VerletIntegrator integrator(0.002); VerletIntegrator integrator(0.001);
integrator.setConstraintTolerance(1e-5); integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce(); NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) { for (int i = 0; i < numParticles; ++i) {
...@@ -181,7 +198,7 @@ void testConstrainedClusters() { ...@@ -181,7 +198,7 @@ void testConstrainedClusters() {
double initialEnergy = 0.0; double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy); State state = context.getState(State::Positions | State::Energy | State::Velocities | State::Forces);
for (int j = 0; j < system.getNumConstraints(); ++j) { for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
...@@ -191,11 +208,11 @@ void testConstrainedClusters() { ...@@ -191,11 +208,11 @@ void testConstrainedClusters() {
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 2e-5); ASSERT_EQUAL_TOL(distance, dist, 2e-5);
} }
double energy = state.getKineticEnergy()+state.getPotentialEnergy(); double energy = computeEnergy(state, system, integrator.getStepSize());
if (i == 1) if (i == 1)
initialEnergy = energy; initialEnergy = energy;
else if (i > 1) else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05); ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1); integrator.step(1);
} }
} }
......
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