Commit 5c4a033f authored by Peter Eastman's avatar Peter Eastman
Browse files

Incorporating Cuda code into OpenMM

parent 170e493a
...@@ -107,7 +107,7 @@ public: ...@@ -107,7 +107,7 @@ public:
* the values should be packed into a single array: all the values for the first element, followed by all the values * the values should be packed into a single array: all the values for the first element, followed by all the values
* for the next element, etc. * for the next element, etc.
*/ */
void saveToArray(void* array); void saveToArray(void* array) const;
/** /**
* Set every element of this stream to the same value. * Set every element of this stream to the same value.
* *
......
...@@ -75,7 +75,7 @@ void Stream::loadFromArray(const void* array) { ...@@ -75,7 +75,7 @@ void Stream::loadFromArray(const void* array) {
impl->loadFromArray(array); impl->loadFromArray(array);
} }
void Stream::saveToArray(void* array) { void Stream::saveToArray(void* array) const {
impl->saveToArray(array); impl->saveToArray(array);
} }
......
...@@ -66,11 +66,6 @@ OpenMMContextImpl::OpenMMContextImpl(OpenMMContext& owner, System& system, Integ ...@@ -66,11 +66,6 @@ OpenMMContextImpl::OpenMMContextImpl(OpenMMContext& owner, System& system, Integ
else if (!platform->supportsKernels(kernelNames)) else if (!platform->supportsKernels(kernelNames))
throw OpenMMException("Specified a Platform for an OpenMMContext which does not support all required kernels"); throw OpenMMException("Specified a Platform for an OpenMMContext which does not support all required kernels");
platform->contextCreated(*this); platform->contextCreated(*this);
positions = platform->createStream("atomPositions", system.getNumAtoms(), Stream::Double3, *this);
velocities = platform->createStream("atomVelocities", system.getNumAtoms(), Stream::Double3, *this);
forces = platform->createStream("atomForces", system.getNumAtoms(), Stream::Double3, *this);
double zero[] = {0.0, 0.0, 0.0};
velocities.fillWithValue(&zero);
kineticEnergyKernel = platform->createKernel(CalcKineticEnergyKernel::Name(), *this); kineticEnergyKernel = platform->createKernel(CalcKineticEnergyKernel::Name(), *this);
vector<double> masses(system.getNumAtoms()); vector<double> masses(system.getNumAtoms());
for (size_t i = 0; i < masses.size(); ++i) for (size_t i = 0; i < masses.size(); ++i)
...@@ -79,6 +74,11 @@ OpenMMContextImpl::OpenMMContextImpl(OpenMMContext& owner, System& system, Integ ...@@ -79,6 +74,11 @@ OpenMMContextImpl::OpenMMContextImpl(OpenMMContext& owner, System& system, Integ
for (size_t i = 0; i < forceImpls.size(); ++i) for (size_t i = 0; i < forceImpls.size(); ++i)
forceImpls[i]->initialize(*this); forceImpls[i]->initialize(*this);
integrator.initialize(*this); integrator.initialize(*this);
positions = platform->createStream("atomPositions", system.getNumAtoms(), Stream::Double3, *this);
velocities = platform->createStream("atomVelocities", system.getNumAtoms(), Stream::Double3, *this);
forces = platform->createStream("atomForces", system.getNumAtoms(), Stream::Double3, *this);
double zero[] = {0.0, 0.0, 0.0};
velocities.fillWithValue(&zero);
} }
OpenMMContextImpl::~OpenMMContextImpl() { OpenMMContextImpl::~OpenMMContextImpl() {
......
...@@ -38,19 +38,19 @@ using namespace OpenMM; ...@@ -38,19 +38,19 @@ using namespace OpenMM;
KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform& platform, OpenMMContextImpl& context) const { KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform& platform, OpenMMContextImpl& context) const {
_gpuContext* gpu = static_cast<_gpuContext*>(context.getPlatformData()); _gpuContext* gpu = static_cast<_gpuContext*>(context.getPlatformData());
if (name == CalcStandardMMForceFieldKernel::Name()) if (name == CalcStandardMMForceFieldKernel::Name())
return new CudaCalcStandardMMForceFieldKernel(name, platform, gpu); return new CudaCalcStandardMMForceFieldKernel(name, platform, gpu, context.getSystem());
// if (name == CalcGBSAOBCForceFieldKernel::Name()) // if (name == CalcGBSAOBCForceFieldKernel::Name())
// return new CudaCalcGBSAOBCForceFieldKernel(name, platform); // return new CudaCalcGBSAOBCForceFieldKernel(name, platform);
// if (name == IntegrateVerletStepKernel::Name()) // if (name == IntegrateVerletStepKernel::Name())
// return new CudaIntegrateVerletStepKernel(name, platform); // return new CudaIntegrateVerletStepKernel(name, platform);
// if (name == IntegrateLangevinStepKernel::Name()) if (name == IntegrateLangevinStepKernel::Name())
// return new CudaIntegrateLangevinStepKernel(name, platform); return new CudaIntegrateLangevinStepKernel(name, platform, gpu);
// if (name == IntegrateBrownianStepKernel::Name()) // if (name == IntegrateBrownianStepKernel::Name())
// return new CudaIntegrateBrownianStepKernel(name, platform); // return new CudaIntegrateBrownianStepKernel(name, platform);
// if (name == ApplyAndersenThermostatKernel::Name()) // if (name == ApplyAndersenThermostatKernel::Name())
// return new CudaApplyAndersenThermostatKernel(name, platform); // return new CudaApplyAndersenThermostatKernel(name, platform);
// if (name == CalcKineticEnergyKernel::Name()) if (name == CalcKineticEnergyKernel::Name())
// return new CudaCalcKineticEnergyKernel(name, platform); return new CudaCalcKineticEnergyKernel(name, platform);
// if (name == RemoveCMMotionKernel::Name()) // if (name == RemoveCMMotionKernel::Name())
// return new CudaRemoveCMMotionKernel(name, platform); // return new CudaRemoveCMMotionKernel(name, platform);
} }
...@@ -29,9 +29,14 @@ ...@@ -29,9 +29,14 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include "OpenMMContext.h"
#include "CudaKernels.h" #include "CudaKernels.h"
#include "CudaStreamImpl.h" #include "CudaStreamImpl.h"
#include "LangevinIntegrator.h"
#include "ReferencePlatform.h"
#include "kernels/gputypes.h" #include "kernels/gputypes.h"
#include "kernels/cudaKernels.h"
#include <cmath> #include <cmath>
extern "C" int gpuSetConstants( gpuContext gpu ); extern "C" int gpuSetConstants( gpuContext gpu );
...@@ -55,169 +60,166 @@ void CudaCalcStandardMMForceFieldKernel::initialize(const vector<vector<int> >& ...@@ -55,169 +60,166 @@ void CudaCalcStandardMMForceFieldKernel::initialize(const vector<vector<int> >&
numPeriodicTorsions = periodicTorsionIndices.size(); numPeriodicTorsions = periodicTorsionIndices.size();
numRBTorsions = rbTorsionIndices.size(); numRBTorsions = rbTorsionIndices.size();
num14 = bonded14Indices.size(); num14 = bonded14Indices.size();
const float RadiansToDegrees = 180.0/3.14159265;
// Initialize bonds. // Initialize bonds.
gpu->sim.bonds = numBonds; {
CUDAStream<int4>* psBondID = new CUDAStream<int4>(numBonds, 1); vector<int> atom1(numBonds);
gpu->psBondID = psBondID; vector<int> atom2(numBonds);
gpu->sim.pBondID = psBondID->_pDevStream[0]; vector<float> length(numBonds);
CUDAStream<float2>* psBondParameter = new CUDAStream<float2>(numBonds, 1); vector<float> k(numBonds);
gpu->psBondParameter = psBondParameter; for (int i = 0; i < numBonds; i++) {
gpu->sim.pBondParameter = psBondParameter->_pDevStream[0]; atom1[i] = bondIndices[i][0];
for (int i = 0; i < numBonds; i++ ) { atom2[i] = bondIndices[i][1];
psBondID->_pSysStream[0][i].x = bondIndices[i][0]; length[i] = (float) bondParameters[i][0];
psBondID->_pSysStream[0][i].y = bondIndices[i][1]; k[i] = (float) bondParameters[i][1];
psBondID->_pSysStream[0][i].z = gpu->pOutputBufferCounter[psBondID->_pSysStream[0][i].x]++; }
psBondID->_pSysStream[0][i].w = gpu->pOutputBufferCounter[psBondID->_pSysStream[0][i].y]++; gpuSetBondParameters(gpu, atom1, atom2, length, k);
psBondParameter->_pSysStream[0][i].x = (float) bondParameters[i][0];
psBondParameter->_pSysStream[0][i].y = (float) bondParameters[i][1];
} }
psBondID->Upload();
psBondParameter->Upload();
// Initialize angles. // Initialize angles.
gpu->sim.bond_angles = numAngles; {
CUDAStream<int4>* psBondAngleID1 = new CUDAStream<int4>(numAngles, 1); vector<int> atom1(numAngles);
gpu->psBondAngleID1 = psBondAngleID1; vector<int> atom2(numAngles);
gpu->sim.pBondAngleID1 = psBondAngleID1->_pDevStream[0]; vector<int> atom3(numAngles);
CUDAStream<int2>* psBondAngleID2 = new CUDAStream<int2>(numAngles, 1); vector<float> angle(numAngles);
gpu->psBondAngleID2 = psBondAngleID2; vector<float> k(numAngles);
gpu->sim.pBondAngleID2 = psBondAngleID2->_pDevStream[0]; for (int i = 0; i < numAngles; i++) {
CUDAStream<float2>* psBondAngleParameter = new CUDAStream<float2>(numAngles, 1); atom1[i] = angleIndices[i][0];
gpu->psBondAngleParameter = psBondAngleParameter; atom2[i] = angleIndices[i][1];
gpu->sim.pBondAngleParameter = psBondAngleParameter->_pDevStream[0]; atom3[i] = angleIndices[i][2];
for (int i = 0; i < numAngles; i++) { angle[i] = (float) (angleParameters[i][0]*RadiansToDegrees);
psBondAngleID1->_pSysStream[0][i].x = angleIndices[i][0]; k[i] = (float) angleParameters[i][1];
psBondAngleID1->_pSysStream[0][i].y = angleIndices[i][1]; }
psBondAngleID1->_pSysStream[0][i].z = angleIndices[i][2]; gpuSetBondAngleParameters(gpu, atom1, atom2, atom3, angle, k);
psBondAngleID1->_pSysStream[0][i].w = gpu->pOutputBufferCounter[psBondAngleID1->_pSysStream[0][i].x]++;
psBondAngleID2->_pSysStream[0][i].x = gpu->pOutputBufferCounter[psBondAngleID1->_pSysStream[0][i].y]++;
psBondAngleID2->_pSysStream[0][i].y = gpu->pOutputBufferCounter[psBondAngleID1->_pSysStream[0][i].z]++;
psBondAngleParameter->_pSysStream[0][i].x = (float) (angleParameters[i][0]*180.0/3.14159265);
psBondAngleParameter->_pSysStream[0][i].y = (float) angleParameters[i][1];
} }
psBondAngleID1->Upload();
psBondAngleID2->Upload();
psBondAngleParameter->Upload();
// Initialize periodic torsions. // Initialize periodic torsions.
gpu->sim.dihedrals = numPeriodicTorsions; {
CUDAStream<int4>* psDihedralID1 = new CUDAStream<int4>(numPeriodicTorsions, 1); vector<int> atom1(numPeriodicTorsions);
gpu->psDihedralID1 = psDihedralID1; vector<int> atom2(numPeriodicTorsions);
gpu->sim.pDihedralID1 = psDihedralID1->_pDevStream[0]; vector<int> atom3(numPeriodicTorsions);
CUDAStream<int4>* psDihedralID2 = new CUDAStream<int4>(numPeriodicTorsions, 1); vector<int> atom4(numPeriodicTorsions);
gpu->psDihedralID2 = psDihedralID2; vector<float> k(numPeriodicTorsions);
gpu->sim.pDihedralID2 = psDihedralID2->_pDevStream[0]; vector<float> phase(numPeriodicTorsions);
CUDAStream<float4>* psDihedralParameter = new CUDAStream<float4>(numPeriodicTorsions, 1); vector<int> periodicity(numPeriodicTorsions);
gpu->psDihedralParameter = psDihedralParameter; for (int i = 0; i < numPeriodicTorsions; i++) {
gpu->sim.pDihedralParameter = psDihedralParameter->_pDevStream[0]; atom1[i] = periodicTorsionIndices[i][0];
for (int i = 0; i < numPeriodicTorsions; i++) { atom2[i] = periodicTorsionIndices[i][1];
psDihedralID1->_pSysStream[0][i].x = periodicTorsionIndices[i][0]; atom3[i] = periodicTorsionIndices[i][2];
psDihedralID1->_pSysStream[0][i].y = periodicTorsionIndices[i][1]; atom4[i] = periodicTorsionIndices[i][3];
psDihedralID1->_pSysStream[0][i].z = periodicTorsionIndices[i][2]; k[i] = (float) periodicTorsionParameters[i][0];
psDihedralID1->_pSysStream[0][i].w = periodicTorsionIndices[i][3]; phase[i] = (float) (periodicTorsionParameters[i][1]*RadiansToDegrees);
psDihedralID2->_pSysStream[0][i].x = gpu->pOutputBufferCounter[psDihedralID1->_pSysStream[0][i].x]++; periodicity[i] = (int) periodicTorsionParameters[i][2];
psDihedralID2->_pSysStream[0][i].y = gpu->pOutputBufferCounter[psDihedralID1->_pSysStream[0][i].y]++; }
psDihedralID2->_pSysStream[0][i].z = gpu->pOutputBufferCounter[psDihedralID1->_pSysStream[0][i].z]++; gpuSetDihedralParameters(gpu, atom1, atom2, atom3, atom4, k, phase, periodicity);
psDihedralID2->_pSysStream[0][i].w = gpu->pOutputBufferCounter[psDihedralID1->_pSysStream[0][i].w]++;
psDihedralParameter->_pSysStream[0][i].x = (float) periodicTorsionParameters[i][0];
psDihedralParameter->_pSysStream[0][i].y = (float) periodicTorsionParameters[i][1];
psDihedralParameter->_pSysStream[0][i].z = (float) periodicTorsionParameters[i][2];
psDihedralParameter->_pSysStream[0][i].w = 0.0f;
} }
psDihedralID1->Upload();
psDihedralID2->Upload();
psDihedralParameter->Upload();
// Initialize Ryckaert-Bellemans torsions. // Initialize Ryckaert-Bellemans torsions.
gpu->sim.rb_dihedrals = numRBTorsions; {
CUDAStream<int4>* psRbDihedralID1 = new CUDAStream<int4>(numRBTorsions, 1); vector<int> atom1(numRBTorsions);
gpu->psRbDihedralID1 = psRbDihedralID1; vector<int> atom2(numRBTorsions);
gpu->sim.pRbDihedralID1 = psRbDihedralID1->_pDevStream[0]; vector<int> atom3(numRBTorsions);
CUDAStream<int4>* psRbDihedralID2 = new CUDAStream<int4>(numRBTorsions, 1); vector<int> atom4(numRBTorsions);
gpu->psRbDihedralID2 = psRbDihedralID2; vector<float> c0(numRBTorsions);
gpu->sim.pRbDihedralID2 = psRbDihedralID2->_pDevStream[0]; vector<float> c1(numRBTorsions);
CUDAStream<float4>* psRbDihedralParameter1 = new CUDAStream<float4>(numRBTorsions, 1); vector<float> c2(numRBTorsions);
gpu->psRbDihedralParameter1 = psRbDihedralParameter1; vector<float> c3(numRBTorsions);
gpu->sim.pRbDihedralParameter1 = psRbDihedralParameter1->_pDevStream[0]; vector<float> c4(numRBTorsions);
CUDAStream<float2>* psRbDihedralParameter2 = new CUDAStream<float2>(numRBTorsions, 1); vector<float> c5(numRBTorsions);
gpu->psRbDihedralParameter2 = psRbDihedralParameter2; for (int i = 0; i < numRBTorsions; i++) {
gpu->sim.pRbDihedralParameter2 = psRbDihedralParameter2->_pDevStream[0]; atom1[i] = rbTorsionIndices[i][0];
for (int i = 0; i < numRBTorsions; i++) { atom2[i] = rbTorsionIndices[i][1];
psRbDihedralID1->_pSysStream[0][i].x = rbTorsionIndices[i][0]; atom3[i] = rbTorsionIndices[i][2];
psRbDihedralID1->_pSysStream[0][i].y = rbTorsionIndices[i][1]; atom4[i] = rbTorsionIndices[i][3];
psRbDihedralID1->_pSysStream[0][i].z = rbTorsionIndices[i][2]; c0[i] = (float) rbTorsionParameters[i][0];
psRbDihedralID1->_pSysStream[0][i].w = rbTorsionIndices[i][3]; c1[i] = (float) rbTorsionParameters[i][1];
psRbDihedralID2->_pSysStream[0][i].x = gpu->pOutputBufferCounter[psRbDihedralID1->_pSysStream[0][i].x]++; c2[i] = (float) rbTorsionParameters[i][2];
psRbDihedralID2->_pSysStream[0][i].y = gpu->pOutputBufferCounter[psRbDihedralID1->_pSysStream[0][i].y]++; c3[i] = (float) rbTorsionParameters[i][3];
psRbDihedralID2->_pSysStream[0][i].z = gpu->pOutputBufferCounter[psRbDihedralID1->_pSysStream[0][i].z]++; c4[i] = (float) rbTorsionParameters[i][4];
psRbDihedralID2->_pSysStream[0][i].w = gpu->pOutputBufferCounter[psRbDihedralID1->_pSysStream[0][i].w]++; c5[i] = (float) rbTorsionParameters[i][5];
psRbDihedralParameter1->_pSysStream[0][i].x = (float) rbTorsionParameters[i][0]; }
psRbDihedralParameter1->_pSysStream[0][i].y = (float) rbTorsionParameters[i][1]; gpuSetRbDihedralParameters(gpu, atom1, atom2, atom3, atom4, c0, c1, c2, c3, c4, c5);
psRbDihedralParameter1->_pSysStream[0][i].z = (float) rbTorsionParameters[i][2];
psRbDihedralParameter1->_pSysStream[0][i].w = (float) rbTorsionParameters[i][3];
psRbDihedralParameter2->_pSysStream[0][i].x = (float) rbTorsionParameters[i][4];
psRbDihedralParameter2->_pSysStream[0][i].y = (float) rbTorsionParameters[i][5];
} }
psRbDihedralID1->Upload();
psRbDihedralID2->Upload();
psRbDihedralParameter1->Upload();
psRbDihedralParameter2->Upload();
// Initialize nonbonded interactions. // Initialize nonbonded interactions.
for (int i = 0; i < numAtoms; i++) { {
gpu->psPosq4->_pSysStream[0][i].w = (float) nonbondedParameters[i][0]; vector<int> atom(numAtoms);
gpu->psSigEps2->_pSysStream[0][i].x = (float) nonbondedParameters[i][1]; vector<float> c6(numAtoms);
gpu->psSigEps2->_pSysStream[0][i].y = (float) nonbondedParameters[i][2]; vector<float> c12(numAtoms);
vector<float> q(numAtoms);
vector<char> symbol;
vector<vector<int> > exclusionList(numAtoms);
for (int i = 0; i < numAtoms; i++) {
atom[i] = i;
q[i] = (float) nonbondedParameters[i][0];
c6[i] = (float) (4*nonbondedParameters[i][2]*pow(nonbondedParameters[i][1], 6.0));
c12[i] = (float) (4*nonbondedParameters[i][2]*pow(nonbondedParameters[i][1], 12.0));
exclusionList[i] = vector<int>(exclusions[i].begin(), exclusions[i].end());
exclusionList[i].push_back(i);
}
gpuSetCoulombParameters(gpu, 138.935485f, atom, c6, c12, q, symbol, exclusionList);
} }
gpu->psPosq4->Upload();
gpu->psSigEps2->Upload();
// Initialize 1-4 nonbonded interactions. // Initialize 1-4 nonbonded interactions.
gpu->sim.LJ14s = num14; {
CUDAStream<int4>* psLJ14ID = new CUDAStream<int4>(num14, 1); vector<int> atom1(num14);
gpu->psLJ14ID = psLJ14ID; vector<int> atom2(num14);
gpu->sim.pLJ14ID = psLJ14ID->_pDevStream[0]; vector<float> c6(num14);
CUDAStream<float4>* psLJ14Parameter = new CUDAStream<float4>(num14, 1); vector<float> c12(num14);
gpu->psLJ14Parameter = psLJ14Parameter; vector<float> q1(num14);
gpu->sim.pLJ14Parameter = psLJ14Parameter->_pDevStream[0]; vector<float> q2(num14);
double sqrtEps = std::sqrt(138.935485); for (int i = 0; i < num14; i++) {
for (int i = 0; i < num14; i++) { atom1[i] = bonded14Indices[i][0];
int atom1 = bonded14Indices[i][0]; atom2[i] = bonded14Indices[i][1];
int atom2 = bonded14Indices[i][1]; double sig = 0.5*(nonbondedParameters[atom1[i]][1]+nonbondedParameters[atom2[i]][1]);
double atom1params[] = {0.5*nonbondedParameters[atom1][1], 2.0*sqrt(nonbondedParameters[atom1][2]), nonbondedParameters[atom1][0]*sqrtEps}; double eps = sqrt(nonbondedParameters[atom1[i]][2]*nonbondedParameters[atom2[i]][2]);
double atom2params[] = {0.5*nonbondedParameters[atom2][1], 2.0*sqrt(nonbondedParameters[atom2][2]), nonbondedParameters[atom2][0]*sqrtEps}; c6[i] = (float) (4*eps*pow(sig, 6.0)*lj14Scale);
psLJ14ID->_pSysStream[0][i].x = atom1; c12[i] = (float) (4*eps*pow(sig, 12.0)*lj14Scale);
psLJ14ID->_pSysStream[0][i].y = atom2; q1[i] = (float) nonbondedParameters[atom1[i]][0];
psLJ14ID->_pSysStream[0][i].z = gpu->pOutputBufferCounter[psLJ14ID->_pSysStream[0][i].x]++; q2[i] = (float) nonbondedParameters[atom2[i]][0];
psLJ14ID->_pSysStream[0][i].w = gpu->pOutputBufferCounter[psLJ14ID->_pSysStream[0][i].y]++; }
psLJ14Parameter->_pSysStream[0][i].x = (float) (atom1params[0]+atom2params[0]); gpuSetLJ14Parameters(gpu, 138.935485f, (float) coulomb14Scale, atom1, atom2, c6, c12, q1, q2);
psLJ14Parameter->_pSysStream[0][i].y = (float) (lj14Scale*(atom1params[1]*atom2params[1]));
psLJ14Parameter->_pSysStream[0][i].z = (float) (coulomb14Scale*(atom1params[2]*atom2params[2]));
} }
psLJ14ID->Upload();
psLJ14Parameter->Upload();
// Initialize exclusions.
// TODO
// Finish initialization. // Finish initialization.
gpuBuildThreadBlockWorkList(gpu);
gpuBuildExclusionList(gpu);
gpuBuildOutputBuffers(gpu);
gpuSetConstants(gpu); gpuSetConstants(gpu);
kClearBornForces(gpu);
kClearForces(gpu);
} }
void CudaCalcStandardMMForceFieldKernel::executeForces(const Stream& positions, Stream& forces) { void CudaCalcStandardMMForceFieldKernel::executeForces(const Stream& positions, Stream& forces) {
kClearForces(gpu);
kCalculateCDLJForces(gpu);
kCalculateLocalForces(gpu);
kReduceBornSumAndForces(gpu);
} }
double CudaCalcStandardMMForceFieldKernel::executeEnergy(const Stream& positions) { double CudaCalcStandardMMForceFieldKernel::executeEnergy(const Stream& positions) {
return 0.0; // We don't currently have GPU kernels to calculate energy, so instead we have the reference
// platform do it. This is VERY slow.
LangevinIntegrator integrator(0.0, 1.0, 0.0);
ReferencePlatform platform;
OpenMMContext context(system, integrator, platform);
double* posData = new double[positions.getSize()*3];
positions.saveToArray(posData);
vector<Vec3> pos(positions.getSize());
for (int i = 0; i < pos.size(); i++)
pos[i] = Vec3(posData[3*i], posData[3*i+1], posData[3*i+2]);
delete[] posData;
context.setPositions(pos);
return context.getState(State::Energy).getPotentialEnergy();
} }
//CudaCalcGBSAOBCForceFieldKernel::~CudaCalcGBSAOBCForceFieldKernel() { //CudaCalcGBSAOBCForceFieldKernel::~CudaCalcGBSAOBCForceFieldKernel() {
...@@ -240,16 +242,57 @@ double CudaCalcStandardMMForceFieldKernel::executeEnergy(const Stream& positions ...@@ -240,16 +242,57 @@ double CudaCalcStandardMMForceFieldKernel::executeEnergy(const Stream& positions
// //
//void CudaIntegrateVerletStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double stepSize) { //void CudaIntegrateVerletStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double stepSize) {
//} //}
//
//CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() { CudaIntegrateLangevinStepKernel::~CudaIntegrateLangevinStepKernel() {
//} }
//
//void CudaIntegrateLangevinStepKernel::initialize(const vector<double>& masses, const vector<vector<int> >& constraintIndices, void CudaIntegrateLangevinStepKernel::initialize(const vector<double>& masses, const vector<vector<int> >& constraintIndices,
// const vector<double>& constraintLengths) { const vector<double>& constraintLengths) {
//}
// // Set masses.
//void CudaIntegrateLangevinStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize) {
//} vector<float> mass(masses.size());
for (int i = 0; i < (int) mass.size(); i++)
mass[i] = (float) masses[i];
gpuSetMass(gpu, mass);
// Set constraints.
int numConstraints = constraintLengths.size();
vector<int> atom1(numConstraints);
vector<int> atom2(numConstraints);
vector<float> distance(numConstraints);
vector<float> invMass1(numConstraints);
vector<float> invMass2(numConstraints);
for (int i = 0; i < numConstraints; i++) {
atom1[i] = constraintIndices[i][0];
atom2[i] = constraintIndices[i][1];
distance[i] = (float) constraintLengths[i];
invMass1[i] = 1.0f/mass[atom1[i]];
invMass2[i] = 1.0f/mass[atom2[i]];
}
gpuSetShakeParameters(gpu, atom1, atom2, distance, invMass1, invMass2);
gpuSetConstants(gpu);
prevStepSize = -1.0;
}
void CudaIntegrateLangevinStepKernel::execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize) {
if (temperature != prevTemp || friction != prevFriction || stepSize != prevStepSize) {
// Initialize the GPU parameters.
double tau = (friction == 0.0 ? 0.0 : 1.0/friction);
gpuSetIntegrationParameters(gpu, tau, stepSize, temperature);
gpuSetConstants(gpu);
kGenerateRandoms(gpu);
prevTemp = temperature;
prevFriction = friction;
prevStepSize = stepSize;
}
kUpdatePart1(gpu);
kApplyFirstShake(gpu);
kUpdatePart2(gpu);
kApplySecondShake(gpu);
}
// //
//CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() { //CudaIntegrateBrownianStepKernel::~CudaIntegrateBrownianStepKernel() {
//} //}
...@@ -269,12 +312,23 @@ double CudaCalcStandardMMForceFieldKernel::executeEnergy(const Stream& positions ...@@ -269,12 +312,23 @@ double CudaCalcStandardMMForceFieldKernel::executeEnergy(const Stream& positions
// //
//void CudaApplyAndersenThermostatKernel::execute(Stream& velocities, double temperature, double collisionFrequency, double stepSize) { //void CudaApplyAndersenThermostatKernel::execute(Stream& velocities, double temperature, double collisionFrequency, double stepSize) {
//} //}
//
//void CudaCalcKineticEnergyKernel::initialize(const vector<double>& masses) { void CudaCalcKineticEnergyKernel::initialize(const vector<double>& masses) {
//} this->masses = masses;
// }
//double CudaCalcKineticEnergyKernel::execute(const Stream& velocities) {
//} double CudaCalcKineticEnergyKernel::execute(const Stream& velocities) {
// We don't currently have a GPU kernel to do this, so we retrieve the velocities and calculate the energy
// on the CPU.
double* v = new double[velocities.getSize()*3];
velocities.saveToArray(v);
double energy = 0.0;
for (size_t i = 0; i < masses.size(); ++i)
energy += masses[i]*(v[i*3]*v[i*3]+v[i*3+1]*v[i*3+1]+v[i*3+2]*v[i*3+2]);
delete v;
return 0.5*energy;
}
// //
//void CudaRemoveCMMotionKernel::initialize(const vector<double>& masses) { //void CudaRemoveCMMotionKernel::initialize(const vector<double>& masses) {
//} //}
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "kernels.h" #include "kernels.h"
#include "kernels/gpuTypes.h" #include "kernels/gpuTypes.h"
#include "System.h"
class CudaAndersenThermostat; class CudaAndersenThermostat;
class CudaBrownianDynamics; class CudaBrownianDynamics;
...@@ -48,7 +49,7 @@ namespace OpenMM { ...@@ -48,7 +49,7 @@ namespace OpenMM {
*/ */
class CudaCalcStandardMMForceFieldKernel : public CalcStandardMMForceFieldKernel { class CudaCalcStandardMMForceFieldKernel : public CalcStandardMMForceFieldKernel {
public: public:
CudaCalcStandardMMForceFieldKernel(std::string name, const Platform& platform, _gpuContext* gpu) : CalcStandardMMForceFieldKernel(name, platform), gpu(gpu) { CudaCalcStandardMMForceFieldKernel(std::string name, const Platform& platform, _gpuContext* gpu, System& system) : CalcStandardMMForceFieldKernel(name, platform), gpu(gpu), system(system) {
} }
~CudaCalcStandardMMForceFieldKernel(); ~CudaCalcStandardMMForceFieldKernel();
/** /**
...@@ -96,8 +97,7 @@ public: ...@@ -96,8 +97,7 @@ public:
private: private:
_gpuContext* gpu; _gpuContext* gpu;
int numAtoms, numBonds, numAngles, numPeriodicTorsions, numRBTorsions, num14; int numAtoms, numBonds, numAngles, numPeriodicTorsions, numRBTorsions, num14;
// int **bondIndexArray, **angleIndexArray, **periodicTorsionIndexArray, **rbTorsionIndexArray, **exclusionArray, **bonded14IndexArray; System& system;
// RealOpenMM **bondParamArray, **angleParamArray, **periodicTorsionParamArray, **rbTorsionParamArray, **atomParamArray, **bonded14ParamArray;
}; };
///** ///**
...@@ -172,45 +172,39 @@ private: ...@@ -172,45 +172,39 @@ private:
// int numConstraints; // int numConstraints;
// double prevStepSize; // double prevStepSize;
//}; //};
//
///** /**
// * This kernel is invoked by LangevinIntegrator to take one time step. * This kernel is invoked by LangevinIntegrator to take one time step.
// */ */
//class CudaIntegrateLangevinStepKernel : public IntegrateLangevinStepKernel { class CudaIntegrateLangevinStepKernel : public IntegrateLangevinStepKernel {
//public: public:
// CudaIntegrateLangevinStepKernel(std::string name, const Platform& platform) : IntegrateLangevinStepKernel(name, platform), CudaIntegrateLangevinStepKernel(std::string name, const Platform& platform, _gpuContext* gpu) : IntegrateLangevinStepKernel(name, platform), gpu(gpu) {
// dynamics(0), shake(0), masses(0), shakeParameters(0), constraintIndices(0) { }
// } ~CudaIntegrateLangevinStepKernel();
// ~CudaIntegrateLangevinStepKernel(); /**
// /** * Initialize the kernel, setting up all parameters related to integrator.
// * Initialize the kernel, setting up all parameters related to integrator. *
// * * @param masses the mass of each atom
// * @param masses the mass of each atom * @param constraintIndices each element contains the indices of two atoms whose distance should be constrained
// * @param constraintIndices each element contains the indices of two atoms whose distance should be constrained * @param constraintLengths the required distance between each pair of constrained atoms
// * @param constraintLengths the required distance between each pair of constrained atoms */
// */ void initialize(const std::vector<double>& masses, const std::vector<std::vector<int> >& constraintIndices,
// void initialize(const std::vector<double>& masses, const std::vector<std::vector<int> >& constraintIndices, const std::vector<double>& constraintLengths);
// const std::vector<double>& constraintLengths); /**
// /** * Execute the kernel.
// * Execute the kernel. *
// * * @param positions a Stream of type Double3 containing the position (x, y, z) of each atom
// * @param positions a Stream of type Double3 containing the position (x, y, z) of each atom * @param velocities a Stream of type Double3 containing the velocity (x, y, z) of each atom
// * @param velocities a Stream of type Double3 containing the velocity (x, y, z) of each atom * @param forces a Stream of type Double3 containing the force (x, y, z) on each atom
// * @param forces a Stream of type Double3 containing the force (x, y, z) on each atom * @param temperature the temperature of the heat bath
// * @param temperature the temperature of the heat bath * @param friction the friction coefficient coupling the system to the heat bath
// * @param friction the friction coefficient coupling the system to the heat bath * @param stepSize the integration step size
// * @param stepSize the integration step size */
// */ void execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize);
// void execute(Stream& positions, Stream& velocities, const Stream& forces, double temperature, double friction, double stepSize); private:
//private: _gpuContext* gpu;
// CudaStochasticDynamics* dynamics; double prevTemp, prevFriction, prevStepSize;
// CudaShakeAlgorithm* shake; };
// RealOpenMM* masses;
// RealOpenMM** shakeParameters;
// int** constraintIndices;
// int numConstraints;
// double prevTemp, prevFriction, prevStepSize;
//};
// //
///** ///**
// * This kernel is invoked by BrownianIntegrator to take one time step. // * This kernel is invoked by BrownianIntegrator to take one time step.
...@@ -278,30 +272,30 @@ private: ...@@ -278,30 +272,30 @@ private:
// CudaAndersenThermostat* thermostat; // CudaAndersenThermostat* thermostat;
// RealOpenMM* masses; // RealOpenMM* masses;
//}; //};
//
///** /**
// * This kernel is invoked to calculate the kinetic energy of the system. * This kernel is invoked to calculate the kinetic energy of the system.
// */ */
//class CudaCalcKineticEnergyKernel : public CalcKineticEnergyKernel { class CudaCalcKineticEnergyKernel : public CalcKineticEnergyKernel {
//public: public:
// CudaCalcKineticEnergyKernel(std::string name, const Platform& platform) : CalcKineticEnergyKernel(name, platform) { CudaCalcKineticEnergyKernel(std::string name, const Platform& platform) : CalcKineticEnergyKernel(name, platform) {
// } }
// /** /**
// * Initialize the kernel, setting up the atomic masses. * Initialize the kernel, setting up the atomic masses.
// * *
// * @param masses the mass of each atom * @param masses the mass of each atom
// */ */
// void initialize(const std::vector<double>& masses); void initialize(const std::vector<double>& masses);
// /** /**
// * Execute the kernel. * Execute the kernel.
// * *
// * @param velocities a Stream of type Double3 containing the velocity (x, y, z) of each atom * @param velocities a Stream of type Double3 containing the velocity (x, y, z) of each atom
// * @return the kinetic energy of the system * @return the kinetic energy of the system
// */ */
// double execute(const Stream& velocities); double execute(const Stream& velocities);
//private: private:
// std::vector<double> masses; std::vector<double> masses;
//}; };
// //
///** ///**
// * This kernel is invoked to remove center of mass motion from the system. // * This kernel is invoked to remove center of mass motion from the system.
......
...@@ -43,10 +43,10 @@ CudaPlatform::CudaPlatform() { ...@@ -43,10 +43,10 @@ CudaPlatform::CudaPlatform() {
registerKernelFactory(CalcStandardMMForceFieldKernel::Name(), factory); registerKernelFactory(CalcStandardMMForceFieldKernel::Name(), factory);
// registerKernelFactory(CalcGBSAOBCForceFieldKernel::Name(), factory); // registerKernelFactory(CalcGBSAOBCForceFieldKernel::Name(), factory);
// registerKernelFactory(IntegrateVerletStepKernel::Name(), factory); // registerKernelFactory(IntegrateVerletStepKernel::Name(), factory);
// registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory); registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory);
// registerKernelFactory(IntegrateBrownianStepKernel::Name(), factory); // registerKernelFactory(IntegrateBrownianStepKernel::Name(), factory);
// registerKernelFactory(ApplyAndersenThermostatKernel::Name(), factory); // registerKernelFactory(ApplyAndersenThermostatKernel::Name(), factory);
// registerKernelFactory(CalcKineticEnergyKernel::Name(), factory); registerKernelFactory(CalcKineticEnergyKernel::Name(), factory);
// registerKernelFactory(RemoveCMMotionKernel::Name(), factory); // registerKernelFactory(RemoveCMMotionKernel::Name(), factory);
} }
......
...@@ -157,6 +157,7 @@ void CudaStreamImpl<T>::loadFromArray(const void* array) { ...@@ -157,6 +157,7 @@ void CudaStreamImpl<T>::loadFromArray(const void* array) {
template <class T> template <class T>
void CudaStreamImpl<T>::saveToArray(void* array) { void CudaStreamImpl<T>::saveToArray(void* array) {
stream->Download();
float* data = reinterpret_cast<float*>(stream->_pSysData); float* data = reinterpret_cast<float*>(stream->_pSysData);
if (baseType == Stream::Float) { if (baseType == Stream::Float) {
float* arrayData = (float*) array; float* arrayData = (float*) array;
...@@ -176,7 +177,6 @@ void CudaStreamImpl<T>::saveToArray(void* array) { ...@@ -176,7 +177,6 @@ void CudaStreamImpl<T>::saveToArray(void* array) {
for (int j = 0; j < width; ++j) for (int j = 0; j < width; ++j)
arrayData[i*width+j] = (int) data[i*rowOffset+j]; arrayData[i*width+j] = (int) data[i*rowOffset+j];
} }
stream->Download();
} }
template <class T> template <class T>
......
/* -------------------------------------------------------------------------- *
* 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 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 LangevinIntegrator.
*/
#include "../../../tests/AssertionUtilities.h"
#include "OpenMMContext.h"
#include "CudaPlatform.h"
#include "StandardMMForceField.h"
#include "System.h"
#include "LangevinIntegrator.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() {
CudaPlatform platform;
System system(2, 0);
system.setAtomMass(0, 2.0);
system.setAtomMass(1, 2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(2, 1, 0, 0, 0);
forceField->setBondParameters(0, 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 damped harmonic oscillator, so compare it to the analytical solution.
double freq = std::sqrt(1-0.05*0.05);
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Velocities);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::exp(-0.05*time)*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*std::exp(-0.05*time)*(0.05*std::cos(freq*time)+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);
integrator.step(1);
}
// Not set the friction to a tiny value and see if it conserves energy.
integrator.setFriction(5e-5);
context.setPositions(positions);
State state = context.getState(State::Energy);
double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy();
for (int i = 0; i < 1000; ++i) {
state = context.getState(State::Energy);
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1);
}
}
void testTemperature() {
const int numAtoms = 8;
const double temp = 100.0;
CudaPlatform platform;
System system(numAtoms, 0);
LangevinIntegrator integrator(temp, 2.0, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(numAtoms, 0, 0, 0, 0);
for (int i = 0; i < numAtoms; ++i) {
system.setAtomMass(i, 2.0);
forceField->setAtomParameters(i, (i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(numAtoms);
for (int i = 0; i < numAtoms; ++i)
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the temperature is correct.
double ke = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Energy);
ke += state.getKineticEnergy();
integrator.step(1);
}
ke /= 1000;
double expected = 0.5*numAtoms*3*BOLTZ*temp;
ASSERT_EQUAL_TOL(expected, ke, 3*expected/std::sqrt(1000.0));
}
void testConstraints() {
const int numAtoms = 8;
const int numConstraints = numAtoms-1;
const double temp = 100.0;
CudaPlatform platform;
System system(numAtoms, numConstraints);
LangevinIntegrator integrator(temp, 2.0, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(numAtoms, 0, 0, 0, 0);
for (int i = 0; i < numAtoms; ++i) {
system.setAtomMass(i, 10.0);
forceField->setAtomParameters(i, (i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
for (int i = 0; i < numConstraints; ++i)
system.setConstraintParameters(i, i, i+1, 1.0);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(numAtoms);
vector<Vec3> velocities(numAtoms);
init_gen_rand(0);
for (int i = 0; i < numAtoms; ++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.
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions);
for (int j = 0; j < numConstraints; ++j) {
Vec3 p1 = state.getPositions()[j];
Vec3 p2 = state.getPositions()[j+1];
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(1.0, dist, 2e-4);
}
integrator.step(1);
}
}
int main() {
try {
testSingleBond();
testTemperature();
testConstraints();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* 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 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 all the different force terms in the reference implementation of StandardMMForceField.
*/
#include "../../../tests/AssertionUtilities.h"
#include "OpenMMContext.h"
#include "CudaPlatform.h"
#include "StandardMMForceField.h"
#include "System.h"
#include "LangevinIntegrator.h"
#include "../src/SimTKUtilities/SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testBonds() {
CudaPlatform platform;
System system(3, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(3, 2, 0, 0, 0);
forceField->setBondParameters(0, 0, 1, 1.5, 0.8);
forceField->setBondParameters(1, 1, 2, 1.2, 0.7);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 2, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(0, -0.8*0.5, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0.7*0.2, 0, 0), forces[2], TOL);
ASSERT_EQUAL_VEC(Vec3(-forces[0][0]-forces[2][0], -forces[0][1]-forces[2][1], -forces[0][2]-forces[2][2]), forces[1], TOL);
ASSERT_EQUAL_TOL(0.5*0.8*0.5*0.5 + 0.5*0.7*0.2*0.2, state.getPotentialEnergy(), TOL);
}
void testAngles() {
CudaPlatform platform;
System system(4, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(4, 0, 2, 0, 0);
forceField->setAngleParameters(0, 0, 1, 2, PI_M/3, 1.1);
forceField->setAngleParameters(1, 1, 2, 3, PI_M/2, 1.2);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(4);
positions[0] = Vec3(0, 1, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
positions[3] = Vec3(2, 1, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double torque1 = 1.1*PI_M/6;
double torque2 = 1.2*PI_M/4;
ASSERT_EQUAL_VEC(Vec3(torque1, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(-0.5*torque2, 0.5*torque2, 0), forces[3], TOL); // reduced by sqrt(2) due to the bond length, another sqrt(2) due to the angle
ASSERT_EQUAL_VEC(Vec3(forces[0][0]+forces[1][0]+forces[2][0]+forces[3][0], forces[0][1]+forces[1][1]+forces[2][1]+forces[3][1], forces[0][2]+forces[1][2]+forces[2][2]+forces[3][2]), Vec3(0, 0, 0), TOL);
ASSERT_EQUAL_TOL(0.5*1.1*(PI_M/6)*(PI_M/6) + 0.5*1.2*(PI_M/4)*(PI_M/4), state.getPotentialEnergy(), TOL);
}
void testPeriodicTorsions() {
CudaPlatform platform;
System system(4, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(4, 0, 0, 1, 0);
forceField->setPeriodicTorsionParameters(0, 0, 1, 2, 3, 2, PI_M/3, 1.1);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(4);
positions[0] = Vec3(0, 1, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
positions[3] = Vec3(1, 0, 2);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double torque = -2*1.1*std::sin(2*PI_M/3);
ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, 0), forces[3], TOL);
ASSERT_EQUAL_VEC(Vec3(forces[0][0]+forces[1][0]+forces[2][0]+forces[3][0], forces[0][1]+forces[1][1]+forces[2][1]+forces[3][1], forces[0][2]+forces[1][2]+forces[2][2]+forces[3][2]), Vec3(0, 0, 0), TOL);
ASSERT_EQUAL_TOL(1.1*(1+std::cos(2*PI_M/3)), state.getPotentialEnergy(), TOL);
}
void testRBTorsions() {
CudaPlatform platform;
System system(4, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(4, 0, 0, 0, 1);
forceField->setRBTorsionParameters(0, 0, 1, 2, 3, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(4);
positions[0] = Vec3(0, 1, 0);
positions[1] = Vec3(0, 0, 0);
positions[2] = Vec3(1, 0, 0);
positions[3] = Vec3(1, 1, 1);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double psi = 0.25*PI_M - PI_M;
double torque = 0.0;
for (int i = 1; i < 6; ++i) {
double c = 0.1*(i+1);
torque += -c*i*std::pow(std::cos(psi), i-1)*std::sin(psi);
}
ASSERT_EQUAL_VEC(Vec3(0, 0, torque), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0.5*torque, -0.5*torque), forces[3], TOL);
ASSERT_EQUAL_VEC(Vec3(forces[0][0]+forces[1][0]+forces[2][0]+forces[3][0], forces[0][1]+forces[1][1]+forces[2][1]+forces[3][1], forces[0][2]+forces[1][2]+forces[2][2]+forces[3][2]), Vec3(0, 0, 0), TOL);
double energy = 0.0;
for (int i = 0; i < 6; ++i) {
double c = 0.1*(i+1);
energy += c*std::pow(std::cos(psi), i);
}
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
}
void testCoulomb() {
CudaPlatform platform;
System system(2, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(2, 0, 0, 0, 0);
forceField->setAtomParameters(0, 0.5, 1, 0);
forceField->setAtomParameters(1, -1.5, 1, 0);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double force = 138.935485*(-0.75)/4.0;
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(138.935485*(-0.75)/2.0, state.getPotentialEnergy(), TOL);
}
void testLJ() {
CudaPlatform platform;
System system(2, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(2, 0, 0, 0, 0);
forceField->setAtomParameters(0, 0, 1.2, 1);
forceField->setAtomParameters(1, 0, 1.4, 2);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double x = 1.3/2.0;
double eps = SQRT_TWO;
double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0;
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL);
}
void testExclusionsAnd14() {
CudaPlatform platform;
System system(5, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(5, 4, 0, 0, 0);
forceField->setBondParameters(0, 0, 1, 1, 0);
forceField->setBondParameters(1, 1, 2, 1, 0);
forceField->setBondParameters(2, 2, 3, 1, 0);
forceField->setBondParameters(3, 3, 4, 1, 0);
system.addForce(forceField);
for (int i = 1; i < 5; ++i) {
// Test LJ forces
vector<Vec3> positions(5);
const double r = 1.0;
for (int j = 0; j < 5; ++j) {
forceField->setAtomParameters(j, 0, 1.5, 0);
positions[j] = Vec3(0, j, 0);
}
forceField->setAtomParameters(0, 0, 1.5, 1);
forceField->setAtomParameters(i, 0, 1.5, 1);
positions[i] = Vec3(r, 0, 0);
OpenMMContext context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double x = 1.5/r;
double eps = 1.0;
double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r;
double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0));
if (i == 3) {
force *= 0.5;
energy *= 0.5;
}
if (i < 3) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
// Test Coulomb forces
forceField->setAtomParameters(0, 2, 1.5, 0);
forceField->setAtomParameters(i, 2, 1.5, 0);
OpenMMContext context2(system, integrator, platform);
context2.setPositions(positions);
state = context2.getState(State::Forces | State::Energy);
const vector<Vec3>& forces2 = state.getForces();
force = 138.935485*4/(r*r);
energy = 138.935485*4/r;
if (i == 3) {
force /= 1.2;
energy /= 1.2;
}
if (i < 3) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
}
}
void testCutoff() {
CudaPlatform platform;
System system(3, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(3, 0, 0, 0, 0);
forceField->setAtomParameters(0, 1.0, 1, 0);
forceField->setAtomParameters(1, 1.0, 1, 0);
forceField->setAtomParameters(2, 1.0, 1, 0);
forceField->setNonbondedMethod(StandardMMForceField::CutoffNonPeriodic);
const double cutoff = 2.9;
forceField->setCutoffDistance(cutoff);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 2, 0);
positions[2] = Vec3(0, 3, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
const double eps = 78.3;
const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
const double force1 = 138.935485*(1.0)*(0.25-2.0*krf*2.0);
const double force2 = 138.935485*(1.0)*(1.0-2.0*krf*1.0);
ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL);
const double energy1 = 138.935485*(1.0)*(0.5+krf*4.0-crf);
const double energy2 = 138.935485*(1.0)*(1.0+krf*1.0-crf);
ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL);
}
void testCutoff14() {
CudaPlatform platform;
System system(5, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(5, 4, 0, 0, 0);
forceField->setBondParameters(0, 0, 1, 1, 0);
forceField->setBondParameters(1, 1, 2, 1, 0);
forceField->setBondParameters(2, 2, 3, 1, 0);
forceField->setBondParameters(3, 3, 4, 1, 0);
forceField->setNonbondedMethod(StandardMMForceField::CutoffNonPeriodic);
const double cutoff = 3.5;
forceField->setCutoffDistance(cutoff);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(5);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(1, 0, 0);
positions[2] = Vec3(2, 0, 0);
positions[3] = Vec3(3, 0, 0);
positions[4] = Vec3(4, 0, 0);
for (int i = 1; i < 5; ++i) {
// Test LJ forces
forceField->setAtomParameters(0, 0, 1.5, 1);
for (int j = 1; j < 5; ++j)
forceField->setAtomParameters(j, 0, 1.5, 0);
forceField->setAtomParameters(i, 0, 1.5, 1);
context.reinitialize();
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double r = positions[i][0];
double x = 1.5/r;
double e = 1.0;
double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r;
double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0));
if (i == 3) {
force *= 0.5;
energy *= 0.5;
}
if (i < 3 || r > cutoff) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
// Test Coulomb forces
const double q = 0.7;
forceField->setAtomParameters(0, q, 1.5, 0);
forceField->setAtomParameters(i, q, 1.5, 0);
context.reinitialize();
context.setPositions(positions);
state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces2 = state.getForces();
const double eps = 78.3;
const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
force = 138.935485*q*q*(1.0/(r*r)-2.0*krf*r);
energy = 138.935485*q*q*(1.0/r+krf*r*r-crf);
if (i == 3) {
force /= 1.2;
energy /= 1.2;
}
if (i < 3 || r > cutoff) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
}
}
void testPeriodic() {
CudaPlatform platform;
System system(3, 0);
LangevinIntegrator integrator(0.0, 0.1, 0.01);
StandardMMForceField* forceField = new StandardMMForceField(3, 1, 0, 0, 0);
forceField->setAtomParameters(0, 1.0, 1, 0);
forceField->setAtomParameters(1, 1.0, 1, 0);
forceField->setAtomParameters(2, 1.0, 1, 0);
forceField->setBondParameters(0, 0, 1, 1.0, 0.0);
forceField->setNonbondedMethod(StandardMMForceField::CutoffPeriodic);
const double cutoff = 2.0;
forceField->setCutoffDistance(cutoff);
forceField->setPeriodicBoxSize(4.0, 4.0, 4.0);
system.addForce(forceField);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
positions[2] = Vec3(3, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
const double eps = 78.3;
const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
const double force = 138.935485*(1.0)*(1.0-2.0*krf*1.0);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL);
ASSERT_EQUAL_TOL(2*138.935485*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL);
}
int main() {
try {
testBonds();
testAngles();
testPeriodicTorsions();
testRBTorsions();
testCoulomb();
testLJ();
testExclusionsAnd14();
// testCutoff();
// testCutoff14();
// testPeriodic();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -206,21 +206,19 @@ void testExclusionsAnd14() { ...@@ -206,21 +206,19 @@ void testExclusionsAnd14() {
forceField->setBondParameters(3, 3, 4, 1, 0); forceField->setBondParameters(3, 3, 4, 1, 0);
system.addForce(forceField); system.addForce(forceField);
OpenMMContext context(system, integrator, platform); OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(5);
const double r = 1.0;
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(r, 0, 0);
positions[2] = Vec3(r, 0, 0);
positions[3] = Vec3(r, 0, 0);
positions[4] = Vec3(r, 0, 0);
for (int i = 1; i < 5; ++i) { for (int i = 1; i < 5; ++i) {
// Test LJ forces // Test LJ forces
forceField->setAtomParameters(0, 0, 1.5, 1); vector<Vec3> positions(5);
for (int j = 1; j < 5; ++j) const double r = 1.0;
for (int j = 0; j < 5; ++j) {
forceField->setAtomParameters(j, 0, 1.5, 0); forceField->setAtomParameters(j, 0, 1.5, 0);
positions[j] = Vec3(0, j, 0);
}
forceField->setAtomParameters(0, 0, 1.5, 1);
forceField->setAtomParameters(i, 0, 1.5, 1); forceField->setAtomParameters(i, 0, 1.5, 1);
positions[i] = Vec3(r, 0, 0);
context.reinitialize(); context.reinitialize();
context.setPositions(positions); context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy); State state = context.getState(State::Forces | State::Energy);
......
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