Commit 09786e4b authored by Peter Eastman's avatar Peter Eastman
Browse files

Created VariableVerletIntegrator

parent eb6ebc43
......@@ -32,6 +32,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/VariableVerletIntegrator.h"
#include "openmm/AndersenThermostat.h"
#include "openmm/BrownianIntegrator.h"
#include "openmm/CMMotionRemover.h"
......@@ -417,6 +418,32 @@ public:
virtual void execute(OpenMMContextImpl& context, const BrownianIntegrator& integrator) = 0;
};
/**
* This kernel is invoked by VariableVerletIntegrator to take one time step.
*/
class IntegrateVariableVerletStepKernel : public KernelImpl {
public:
static std::string Name() {
return "IntegrateVariableVerletStep";
}
IntegrateVariableVerletStepKernel(std::string name, const Platform& platform) : KernelImpl(name, platform) {
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param integrator the VariableVerletIntegrator this kernel will be used for
*/
virtual void initialize(const System& system, const VariableVerletIntegrator& integrator) = 0;
/**
* Execute the kernel.
*
* @param context the context in which to execute this kernel
* @param integrator the VerletIntegrator this kernel is being used for
*/
virtual void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator) = 0;
};
/**
* This kernel is invoked by AndersenThermostat at the start of each time step to adjust the particle velocities.
*/
......
......@@ -32,6 +32,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/VariableVerletIntegrator.h"
#include "openmm/AndersenThermostat.h"
#include "openmm/BrownianIntegrator.h"
#include "openmm/CMMotionRemover.h"
......
#ifndef OPENMM_VARIABLEVERLETINTEGRATOR_H_
#define OPENMM_VARIABLEVERLETINTEGRATOR_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "Integrator.h"
#include "openmm/Kernel.h"
#include "internal/windowsExport.h"
namespace OpenMM {
/**
* This is an error contolled, variable time step Integrator that simulates a System using the
* velocity Verlet algorithm. It compares the result of the Verlet integrator to that of an
* explicit Euler integrator, takes the difference between the two as a measure of the integration
* error in each time step, and continuously adjusts the step size to keep the error below a
* specified tolerance. This allows it to take larger steps on average than a fixed step size
* integrator, while still maintaining comparable accuracy and stability.
*
* It is best not to think of the value of the accuracy parameter as having any absolute meaning.
* It is just an adjustable parameter that affects the step size and integration accuracy. You
* should try different values to find the largest value that produces a trajectory sufficiently
* accurate for your purposes. 0.001 is often a good starting point.
*
* Unlike a fixed step size Verlet integrator, variable step size Verlet is not symplectic. This
* means that at a given accuracy level, energy is not as precisely conserved over long time periods.
* This makes it most appropriate for constant temperate simulations. In constant energy simulations
* where precise energy conservation over long time periods is important, a fixed step size Verlet
* integrator may be more appropriate.
*/
class OPENMM_EXPORT VariableVerletIntegrator : public Integrator {
public:
/**
* Create a VariableVerletIntegrator.
*
* @param stepSize the initial step size to use (in picoseconds)
* @param accuracy the required accuracy
*/
VariableVerletIntegrator(double stepSize, double accuracy);
/**
* Get the required accuracy.
*/
double getAccuracy() const {
return accuracy;
}
/**
* Set the required accuracy.
*/
void setAccuracy(double acc) {
accuracy = acc;
}
/**
* Advance a simulation through time by taking a series of time steps.
*
* @param steps the number of time steps to take
*/
void step(int steps);
protected:
/**
* This will be called by the OpenMMContext when it is created. It informs the Integrator
* of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the OpenMMContext.
*/
void initialize(OpenMMContextImpl& context);
/**
* Get the names of all Kernels used by this Integrator.
*/
std::vector<std::string> getKernelNames();
private:
double accuracy;
OpenMMContextImpl* context;
Kernel kernel;
};
} // namespace OpenMM
#endif /*OPENMM_VARIABLEVERLETINTEGRATOR_H_*/
......@@ -65,6 +65,5 @@ void BrownianIntegrator::step(int steps) {
context->updateContextState();
context->calcForces();
dynamic_cast<IntegrateBrownianStepKernel&>(kernel.getImpl()).execute(*context, *this);
context->setTime(context->getTime()+getStepSize());
}
}
......@@ -65,6 +65,5 @@ void LangevinIntegrator::step(int steps) {
context->updateContextState();
context->calcForces();
dynamic_cast<IntegrateLangevinStepKernel&>(kernel.getImpl()).execute(*context, *this);
context->setTime(context->getTime()+getStepSize());
}
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/VariableVerletIntegrator.h"
#include "openmm/OpenMMContext.h"
#include "openmm/internal/OpenMMContextImpl.h"
#include "openmm/kernels.h"
#include <string>
using namespace OpenMM;
using std::string;
using std::vector;
VariableVerletIntegrator::VariableVerletIntegrator(double stepSize, double accuracy) : accuracy(accuracy) {
setStepSize(stepSize);
setConstraintTolerance(1e-4);
}
void VariableVerletIntegrator::initialize(OpenMMContextImpl& contextRef) {
context = &contextRef;
kernel = context->getPlatform().createKernel(IntegrateVariableVerletStepKernel::Name(), contextRef);
dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).initialize(contextRef.getSystem(), *this);
}
vector<string> VariableVerletIntegrator::getKernelNames() {
std::vector<std::string> names;
names.push_back(IntegrateVariableVerletStepKernel::Name());
return names;
}
void VariableVerletIntegrator::step(int steps) {
for (int i = 0; i < steps; ++i) {
context->updateContextState();
context->calcForces();
dynamic_cast<IntegrateVariableVerletStepKernel&>(kernel.getImpl()).execute(*context, *this);
}
}
......@@ -61,6 +61,5 @@ void VerletIntegrator::step(int steps) {
context->updateContextState();
context->calcForces();
dynamic_cast<IntegrateVerletStepKernel&>(kernel.getImpl()).execute(*context, *this);
context->setTime(context->getTime()+getStepSize());
}
}
......@@ -250,5 +250,5 @@ void BrookIntegrateLangevinStepKernel::execute( OpenMMContextImpl& context, cons
_brookLangevinDynamics->update( *(_openMMBrookInterface.getParticlePositions()), *(_openMMBrookInterface.getParticleVelocities()),
*(_openMMBrookInterface.getParticleForces()), *_brookShakeAlgorithm, *_brookRandomNumberGenerator );
_openMMBrookInterface->setTime(_openMMBrookInterface->getTime(integrator.getStepSize()));
}
......@@ -202,6 +202,5 @@ void BrookIntegrateVerletStepKernel::execute( OpenMMContextImpl& context, const
_brookVerletDynamics->update( *(_openMMBrookInterface.getParticlePositions()), *(_openMMBrookInterface.getParticleVelocities()),
*(_openMMBrookInterface.getParticleForces()), *_brookShakeAlgorithm );
_openMMBrookInterface->setTime(_openMMBrookInterface->getTime(stepSize));
}
......@@ -458,6 +458,7 @@ void CudaIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, const Ve
gpu->bCalculateCM = true;
}
kVerletUpdatePart2(gpu);
data.time += stepSize;
}
CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
......@@ -500,6 +501,7 @@ void CudaIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, const
kApplySecondShake(gpu);
kApplySecondSettle(gpu);
kApplySecondCCMA(gpu);
data.time += stepSize;
}
CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
......@@ -539,6 +541,7 @@ void CudaIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, const
gpu->bCalculateCM = true;
}
kBrownianUpdatePart2(gpu);
data.time += stepSize;
}
CudaApplyAndersenThermostatKernel::~CudaApplyAndersenThermostatKernel() {
......
......@@ -59,11 +59,13 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla
if (name == CalcGBVIForceKernel::Name())
return new ReferenceCalcGBVIForceKernel(name, platform);
if (name == IntegrateVerletStepKernel::Name())
return new ReferenceIntegrateVerletStepKernel(name, platform);
return new ReferenceIntegrateVerletStepKernel(name, platform, data);
if (name == IntegrateLangevinStepKernel::Name())
return new ReferenceIntegrateLangevinStepKernel(name, platform);
return new ReferenceIntegrateLangevinStepKernel(name, platform, data);
if (name == IntegrateBrownianStepKernel::Name())
return new ReferenceIntegrateBrownianStepKernel(name, platform);
return new ReferenceIntegrateBrownianStepKernel(name, platform, data);
if (name == IntegrateVariableVerletStepKernel::Name())
return new ReferenceIntegrateVariableVerletStepKernel(name, platform, data);
if (name == ApplyAndersenThermostatKernel::Name())
return new ReferenceApplyAndersenThermostatKernel(name, platform);
if (name == CalcKineticEnergyKernel::Name())
......
......@@ -33,6 +33,7 @@
#include "ReferenceFloatStreamImpl.h"
#include "gbsa/CpuObc.h"
#include "gbsa/CpuGBVI.h"
#include "SimTKReference/ReferenceVariableVerletDynamics.h"
#include "SimTKReference/ReferenceAndersenThermostat.h"
#include "SimTKReference/ReferenceAngleBondIxn.h"
#include "SimTKReference/ReferenceBondForce.h"
......@@ -639,6 +640,7 @@ void ReferenceIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, con
prevStepSize = stepSize;
}
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += stepSize;
}
ReferenceIntegrateLangevinStepKernel::~ReferenceIntegrateLangevinStepKernel() {
......@@ -702,6 +704,7 @@ void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, c
prevStepSize = stepSize;
}
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += stepSize;
}
ReferenceIntegrateBrownianStepKernel::~ReferenceIntegrateBrownianStepKernel() {
......@@ -764,6 +767,63 @@ void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, c
prevStepSize = stepSize;
}
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += stepSize;
}
ReferenceIntegrateVariableVerletStepKernel::~ReferenceIntegrateVariableVerletStepKernel() {
if (dynamics)
delete dynamics;
if (constraints)
delete constraints;
if (masses)
delete[] masses;
if (constraintIndices)
disposeIntArray(constraintIndices, numConstraints);
if (constraintDistances)
delete[] constraintDistances;
}
void ReferenceIntegrateVariableVerletStepKernel::initialize(const System& system, const VariableVerletIntegrator& integrator) {
int numParticles = system.getNumParticles();
masses = new RealOpenMM[numParticles];
for (int i = 0; i < numParticles; ++i)
masses[i] = static_cast<RealOpenMM>(system.getParticleMass(i));
numConstraints = system.getNumConstraints();
constraintIndices = allocateIntArray(numConstraints, 2);
constraintDistances = new RealOpenMM[numConstraints];
for (int i = 0; i < numConstraints; ++i) {
int particle1, particle2;
double distance;
system.getConstraintParameters(i, particle1, particle2, distance);
constraintIndices[i][0] = particle1;
constraintIndices[i][1] = particle2;
constraintDistances[i] = static_cast<RealOpenMM>(distance);
}
}
void ReferenceIntegrateVariableVerletStepKernel::execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator) {
double stepSize = integrator.getStepSize();
double accuracy = integrator.getAccuracy();
RealOpenMM** posData = ((ReferenceFloatStreamImpl&) context.getPositions().getImpl()).getData();
RealOpenMM** velData = ((ReferenceFloatStreamImpl&) context.getVelocities().getImpl()).getData();
RealOpenMM** forceData = const_cast<RealOpenMM**>(((ReferenceFloatStreamImpl&) context.getForces().getImpl()).getData()); // Reference code needs to be made const correct
if (dynamics == 0 || stepSize != prevStepSize || accuracy != prevAccuracy) {
// Recreate the computation objects with the new parameters.
if (dynamics) {
delete dynamics;
delete constraints;
}
dynamics = new ReferenceVariableVerletDynamics(context.getSystem().getNumParticles(), static_cast<RealOpenMM>(stepSize), accuracy);
vector<ReferenceCCMAAlgorithm::AngleInfo> angles;
findAnglesForCCMA(context.getSystem(), angles);
constraints = new ReferenceCCMAAlgorithm(context.getSystem().getNumParticles(), numConstraints, constraintIndices, constraintDistances, masses, angles, (RealOpenMM)integrator.getConstraintTolerance());
dynamics->setReferenceConstraintAlgorithm(constraints);
prevStepSize = stepSize;
prevAccuracy = accuracy;
}
dynamics->update(context.getSystem().getNumParticles(), posData, velData, forceData, masses);
data.time += dynamics->getLastStepSize();
}
ReferenceApplyAndersenThermostatKernel::~ReferenceApplyAndersenThermostatKernel() {
......
......@@ -43,6 +43,7 @@ class ReferenceAndersenThermostat;
class ReferenceBrownianDynamics;
class ReferenceStochasticDynamics;
class ReferenceConstraintAlgorithm;
class ReferenceVariableVerletDynamics;
class ReferenceVerletDynamics;
namespace OpenMM {
......@@ -343,8 +344,8 @@ private:
*/
class ReferenceIntegrateVerletStepKernel : public IntegrateVerletStepKernel {
public:
ReferenceIntegrateVerletStepKernel(std::string name, const Platform& platform) : IntegrateVerletStepKernel(name, platform),
dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
ReferenceIntegrateVerletStepKernel(std::string name, const Platform& platform, ReferencePlatform::PlatformData& data) : IntegrateVerletStepKernel(name, platform),
data(data), dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
}
~ReferenceIntegrateVerletStepKernel();
/**
......@@ -362,6 +363,7 @@ public:
*/
void execute(OpenMMContextImpl& context, const VerletIntegrator& integrator);
private:
ReferencePlatform::PlatformData& data;
ReferenceVerletDynamics* dynamics;
ReferenceConstraintAlgorithm* constraints;
RealOpenMM* masses;
......@@ -376,8 +378,8 @@ private:
*/
class ReferenceIntegrateLangevinStepKernel : public IntegrateLangevinStepKernel {
public:
ReferenceIntegrateLangevinStepKernel(std::string name, const Platform& platform) : IntegrateLangevinStepKernel(name, platform),
dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
ReferenceIntegrateLangevinStepKernel(std::string name, const Platform& platform, ReferencePlatform::PlatformData& data) : IntegrateLangevinStepKernel(name, platform),
data(data), dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
}
~ReferenceIntegrateLangevinStepKernel();
/**
......@@ -395,6 +397,7 @@ public:
*/
void execute(OpenMMContextImpl& context, const LangevinIntegrator& integrator);
private:
ReferencePlatform::PlatformData& data;
ReferenceStochasticDynamics* dynamics;
ReferenceConstraintAlgorithm* constraints;
RealOpenMM* masses;
......@@ -409,8 +412,8 @@ private:
*/
class ReferenceIntegrateBrownianStepKernel : public IntegrateBrownianStepKernel {
public:
ReferenceIntegrateBrownianStepKernel(std::string name, const Platform& platform) : IntegrateBrownianStepKernel(name, platform),
dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
ReferenceIntegrateBrownianStepKernel(std::string name, const Platform& platform, ReferencePlatform::PlatformData& data) : IntegrateBrownianStepKernel(name, platform),
data(data), dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
}
~ReferenceIntegrateBrownianStepKernel();
/**
......@@ -428,6 +431,7 @@ public:
*/
void execute(OpenMMContextImpl& context, const BrownianIntegrator& integrator);
private:
ReferencePlatform::PlatformData& data;
ReferenceBrownianDynamics* dynamics;
ReferenceConstraintAlgorithm* constraints;
RealOpenMM* masses;
......@@ -437,6 +441,40 @@ private:
double prevTemp, prevFriction, prevStepSize;
};
/**
* This kernel is invoked by VariableVerletIntegrator to take one time step.
*/
class ReferenceIntegrateVariableVerletStepKernel : public IntegrateVariableVerletStepKernel {
public:
ReferenceIntegrateVariableVerletStepKernel(std::string name, const Platform& platform, ReferencePlatform::PlatformData& data) : IntegrateVariableVerletStepKernel(name, platform),
data(data), dynamics(0), constraints(0), masses(0), constraintDistances(0), constraintIndices(0) {
}
~ReferenceIntegrateVariableVerletStepKernel();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param integrator the VerletIntegrator this kernel will be used for
*/
void initialize(const System& system, const VariableVerletIntegrator& integrator);
/**
* Execute the kernel.
*
* @param context the context in which to execute this kernel
* @param integrator the VerletIntegrator this kernel is being used for
*/
void execute(OpenMMContextImpl& context, const VariableVerletIntegrator& integrator);
private:
ReferencePlatform::PlatformData& data;
ReferenceVariableVerletDynamics* dynamics;
ReferenceConstraintAlgorithm* constraints;
RealOpenMM* masses;
RealOpenMM* constraintDistances;
int** constraintIndices;
int numConstraints;
double prevStepSize, prevAccuracy;
};
/**
* This kernel is invoked by AndersenThermostat at the start of each time step to adjust the particle velocities.
*/
......
......@@ -51,6 +51,7 @@ ReferencePlatform::ReferencePlatform() {
registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory);
registerKernelFactory(IntegrateBrownianStepKernel::Name(), factory);
registerKernelFactory(IntegrateVariableVerletStepKernel::Name(), factory);
registerKernelFactory(ApplyAndersenThermostatKernel::Name(), factory);
registerKernelFactory(CalcKineticEnergyKernel::Name(), factory);
registerKernelFactory(RemoveCMMotionKernel::Name(), factory);
......
......@@ -362,6 +362,23 @@ RealOpenMM ReferenceDynamics::getDeltaT( void ) const {
return _deltaT;
}
/**---------------------------------------------------------------------------------------
Set delta t
--------------------------------------------------------------------------------------- */
void ReferenceDynamics::setDeltaT( RealOpenMM deltaT ) {
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceDynamics::setDeltaT";
// ---------------------------------------------------------------------------------------
_deltaT = deltaT;
}
/**---------------------------------------------------------------------------------------
Get temperature
......
......@@ -164,7 +164,7 @@ class ReferenceDynamics {
--------------------------------------------------------------------------------------- */
~ReferenceDynamics( );
virtual ~ReferenceDynamics( );
/**---------------------------------------------------------------------------------------
......@@ -206,6 +206,14 @@ class ReferenceDynamics {
RealOpenMM getDeltaT( void ) const;
/**---------------------------------------------------------------------------------------
Set delta t
--------------------------------------------------------------------------------------- */
void setDeltaT( RealOpenMM deltaT );
/**---------------------------------------------------------------------------------------
Get temperature
......
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include <sstream>
#include "../SimTKUtilities/SimTKOpenMMCommon.h"
#include "../SimTKUtilities/SimTKOpenMMLog.h"
#include "../SimTKUtilities/SimTKOpenMMUtilities.h"
#include "ReferenceVariableVerletDynamics.h"
/**---------------------------------------------------------------------------------------
ReferenceVariableVerletDynamics constructor
@param numberOfAtoms number of atoms
@param deltaT initial delta t for dynamics
@param accuracy required accuracy
--------------------------------------------------------------------------------------- */
ReferenceVariableVerletDynamics::ReferenceVariableVerletDynamics( int numberOfAtoms,
RealOpenMM deltaT, RealOpenMM accuracy ) :
ReferenceDynamics( numberOfAtoms, deltaT, 0.0 ), _accuracy(accuracy) {
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceVariableVerletDynamics::ReferenceVariableVerletDynamics";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
// ---------------------------------------------------------------------------------------
allocate2DArrays( numberOfAtoms, 3, Max2DArrays );
allocate1DArrays( numberOfAtoms, Max1DArrays );
}
/**---------------------------------------------------------------------------------------
ReferenceVariableVerletDynamics destructor
--------------------------------------------------------------------------------------- */
ReferenceVariableVerletDynamics::~ReferenceVariableVerletDynamics( ){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nReferenceVariableVerletDynamics::~ReferenceVariableVerletDynamics";
// ---------------------------------------------------------------------------------------
}
/**---------------------------------------------------------------------------------------
Get the required accuracy
@return accuracy
--------------------------------------------------------------------------------------- */
RealOpenMM ReferenceVariableVerletDynamics::getAccuracy( void ) const {
return _accuracy;
}
/**---------------------------------------------------------------------------------------
Set the required accuracy
--------------------------------------------------------------------------------------- */
void ReferenceVariableVerletDynamics::setAccuracy( RealOpenMM accuracy ) {
_accuracy = accuracy;
}
/**---------------------------------------------------------------------------------------
Get the actual size of the last step that was taken
@return step size
--------------------------------------------------------------------------------------- */
RealOpenMM ReferenceVariableVerletDynamics::getLastStepSize( void ) const {
return _lastStepSize;
}
/**---------------------------------------------------------------------------------------
Print parameters
@param message message
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceVariableVerletDynamics::printParameters( std::stringstream& message ) const {
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceVariableVerletDynamics::printParameters";
// ---------------------------------------------------------------------------------------
// print parameters
ReferenceDynamics::printParameters( message );
return ReferenceDynamics::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
Update -- driver routine for performing Verlet dynamics update of coordinates
and velocities
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities velocities
@param forces forces
@param masses atom masses
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceVariableVerletDynamics::update( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities,
RealOpenMM** forces, RealOpenMM* masses ){
// ---------------------------------------------------------------------------------------
static const char* methodName = "\nReferenceVariableVerletDynamics::update";
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static int debug = 0;
// ---------------------------------------------------------------------------------------
// get work arrays
RealOpenMM** xPrime = get2DArrayAtIndex( xPrime2D );
RealOpenMM** vPrime = get2DArrayAtIndex( vPrime2D );
RealOpenMM* inverseMasses = get1DArrayAtIndex( InverseMasses );
// first-time-through initialization
if( getTimeStep() == 0 ){
std::stringstream message;
message << methodName;
int errors = 0;
// invert masses
for( int ii = 0; ii < numberOfAtoms; ii++ ){
if( masses[ii] <= zero ){
message << "mass at atom index=" << ii << " (" << masses[ii] << ") is <= 0" << std::endl;
errors++;
} else {
inverseMasses[ii] = one/masses[ii];
}
}
// exit if errors
if( errors ){
SimTKOpenMMLog::printError( message );
}
}
// Try different step sizes until the accuracy is acceptable.
bool success = false;
RealOpenMM maxStepSize = 5.0f*getDeltaT();
while (!success) {
// Perform the integration and estimate the error.
_lastStepSize = getDeltaT();
RealOpenMM error = zero;
for (int i = 0; i < numberOfAtoms; ++i) {
for (int j = 0; j < 3; ++j) {
RealOpenMM xref = atomCoordinates[i][j] + velocities[i][j]*getDeltaT();
vPrime[i][j] = velocities[i][j] + inverseMasses[i]*forces[i][j]*getDeltaT();
xPrime[i][j] = atomCoordinates[i][j] + vPrime[i][j]*getDeltaT();
RealOpenMM xerror = xPrime[i][j]-xref;
error += xerror*xerror;
}
}
error = SQRT(error/(numberOfAtoms*3));
// Select a new step size.
const RealOpenMM Safety = 0.9f, MinShrink = 0.1f;
const RealOpenMM HysteresisLow = 0.9f, HysteresisHigh = 1.0f, ErrorOrder = 2.0f;
RealOpenMM newStepSize = Safety*getDeltaT()*POW(getAccuracy()/error, 1.0f/ErrorOrder);
if (newStepSize > getDeltaT()) {
if (newStepSize < HysteresisHigh*getDeltaT())
newStepSize = getDeltaT();
}
if (newStepSize < getDeltaT() && error <= getAccuracy())
newStepSize = getDeltaT();
newStepSize = std::min(newStepSize, maxStepSize);
newStepSize = std::max(newStepSize, MinShrink*getDeltaT());
if (newStepSize < getDeltaT())
newStepSize = std::min(newStepSize, HysteresisLow*getDeltaT());
success = (newStepSize >= getDeltaT());
if (success) {
ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
if (referenceConstraintAlgorithm)
success = (referenceConstraintAlgorithm->apply(numberOfAtoms, atomCoordinates, xPrime, inverseMasses) != ErrorReturn);
if (!success) {
newStepSize *= 0.5f;
maxStepSize = newStepSize;
}
}
setDeltaT(newStepSize);
}
// Update the positions and velocities.
RealOpenMM velocityScale = static_cast<RealOpenMM>( 1.0/_lastStepSize );
for (int i = 0; i < numberOfAtoms; ++i) {
for (int j = 0; j < 3; ++j) {
velocities[i][j] = velocityScale*(xPrime[i][j] - atomCoordinates[i][j]);
atomCoordinates[i][j] = xPrime[i][j];
}
}
incrementTimeStep();
return ReferenceDynamics::DefaultReturn;
}
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
* Contributors: Peter Eastman, Pande Group
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __ReferenceVariableVerletDynamics_H__
#define __ReferenceVariableVerletDynamics_H__
#include "ReferenceDynamics.h"
// ---------------------------------------------------------------------------------------
class ReferenceVariableVerletDynamics : public ReferenceDynamics {
private:
enum TwoDArrayIndicies { xPrime2D, vPrime2D, Max2DArrays };
enum OneDArrayIndicies { InverseMasses, Max1DArrays };
RealOpenMM _accuracy, _lastStepSize;
public:
/**---------------------------------------------------------------------------------------
Constructor
@param numberOfAtoms number of atoms
@param deltaT initial delta t for dynamics
@param accuracy required accuracy
--------------------------------------------------------------------------------------- */
ReferenceVariableVerletDynamics( int numberOfAtoms, RealOpenMM deltaT, RealOpenMM accuracy );
/**---------------------------------------------------------------------------------------
Destructor
--------------------------------------------------------------------------------------- */
~ReferenceVariableVerletDynamics( );
/**---------------------------------------------------------------------------------------
Get the required accuracy
@return accuracy
--------------------------------------------------------------------------------------- */
RealOpenMM getAccuracy( void ) const;
/**---------------------------------------------------------------------------------------
Set the required accuracy
--------------------------------------------------------------------------------------- */
void setAccuracy( RealOpenMM accuracy );
/**---------------------------------------------------------------------------------------
Get the actual size of the last step that was taken
@return step size
--------------------------------------------------------------------------------------- */
RealOpenMM getLastStepSize( void ) const;
/**---------------------------------------------------------------------------------------
Print parameters
@param message message
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int printParameters( std::stringstream& message ) const;
/**---------------------------------------------------------------------------------------
Update
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param velocities velocities
@param forces forces
@param masses atom masses
@return ReferenceDynamics::DefaultReturn
--------------------------------------------------------------------------------------- */
int update( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** velocities, RealOpenMM** forces, RealOpenMM* masses );
};
// ---------------------------------------------------------------------------------------
#endif // __ReferenceVariableVerletDynamics_H__
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2009 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of VariableVerletIntegrator.
*/
#include "../../../tests/AssertionUtilities.h"
#include "openmm/OpenMMContext.h"
#include "ReferencePlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VariableVerletIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include "../src/sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleBond() {
ReferencePlatform platform;
System system;
system.addParticle(2.0);
system.addParticle(2.0);
VariableVerletIntegrator integrator(0.01, 1e-6);
HarmonicBondForce* forceField = new HarmonicBondForce();
forceField->addBond(0, 1, 1.5, 1);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// This is simply a harmonic oscillator, so compare it to the analytical solution.
const double freq = 1.0;
State state = context.getState(State::Energy);
const double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy();
for (int i = 0; i < 1000; ++i) {
state = context.getState(State::Positions | State::Velocities | State::Energy);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
double expectedSpeed = -0.5*freq*std::sin(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.02);
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05);
integrator.step(1);
}
ASSERT(state.getTime() > 1.0);
}
void testConstraints() {
const int numParticles = 8;
const double temp = 500.0;
ReferencePlatform platform;
System system;
VariableVerletIntegrator integrator(0.002, 1e-5);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(i%2 == 0 ? 5.0 : 10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
for (int i = 0; i < numParticles-1; ++i)
system.addConstraint(i, i+1, 1.0);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
init_gen_rand(0);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3(i/2, (i+1)/2, 0);
velocities[i] = Vec3(genrand_real2()-0.5, genrand_real2()-0.5, genrand_real2()-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy);
for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
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);
}
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
if (i == 1)
initialEnergy = energy;
else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.1);
integrator.step(1);
}
ASSERT(context.getState(State::Positions).getTime() > 0.1);
}
void testConstrainedClusters() {
const int numParticles = 7;
const double temp = 500.0;
ReferencePlatform platform;
System system;
VariableVerletIntegrator integrator(0.002, 1e-5);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(i > 1 ? 1.0 : 10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
system.addConstraint(0, 1, 1.0);
system.addConstraint(0, 2, 1.0);
system.addConstraint(0, 3, 1.0);
system.addConstraint(0, 4, 1.0);
system.addConstraint(1, 5, 1.0);
system.addConstraint(1, 6, 1.0);
system.addConstraint(2, 3, sqrt(2.0));
system.addConstraint(2, 4, sqrt(2.0));
system.addConstraint(3, 4, sqrt(2.0));
system.addConstraint(5, 6, sqrt(2.0));
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(numParticles);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(1, 0, 0);
positions[2] = Vec3(-1, 0, 0);
positions[3] = Vec3(0, 1, 0);
positions[4] = Vec3(0, 0, 1);
positions[5] = Vec3(2, 0, 0);
positions[6] = Vec3(1, 1, 0);
vector<Vec3> velocities(numParticles);
init_gen_rand(0);
for (int i = 0; i < numParticles; ++i)
velocities[i] = Vec3(genrand_real2()-0.5, genrand_real2()-0.5, genrand_real2()-0.5);
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Energy);
for (int j = 0; j < system.getNumConstraints(); ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
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);
}
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
if (i == 1)
initialEnergy = energy;
else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05);
integrator.step(1);
}
ASSERT(context.getState(State::Positions).getTime() > 0.1);
}
int main() {
try {
testSingleBond();
testConstraints();
testConstrainedClusters();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
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