Commit 53f770f4 authored by peastman's avatar peastman Committed by GitHub
Browse files

Merge pull request #1557 from andysim/dpme

Dispersion PME
parents f36f36bf c0850062
...@@ -602,7 +602,7 @@ void ReferenceCalcAmoebaMultipoleForceKernel::initialize(const System& system, c ...@@ -602,7 +602,7 @@ void ReferenceCalcAmoebaMultipoleForceKernel::initialize(const System& system, c
nb.setEwaldErrorTolerance(force.getEwaldErrorTolerance()); nb.setEwaldErrorTolerance(force.getEwaldErrorTolerance());
nb.setCutoffDistance(force.getCutoffDistance()); nb.setCutoffDistance(force.getCutoffDistance());
int gridSizeX, gridSizeY, gridSizeZ; int gridSizeX, gridSizeY, gridSizeZ;
NonbondedForceImpl::calcPMEParameters(system, nb, alphaEwald, gridSizeX, gridSizeY, gridSizeZ); NonbondedForceImpl::calcPMEParameters(system, nb, alphaEwald, gridSizeX, gridSizeY, gridSizeZ, false);
pmeGridDimension[0] = gridSizeX; pmeGridDimension[0] = gridSizeX;
pmeGridDimension[1] = gridSizeY; pmeGridDimension[1] = gridSizeY;
pmeGridDimension[2] = gridSizeZ; pmeGridDimension[2] = gridSizeZ;
......
...@@ -55,5 +55,7 @@ extern "C" OPENMM_EXPORT_PME void registerPlatforms() { ...@@ -55,5 +55,7 @@ extern "C" OPENMM_EXPORT_PME void registerPlatforms() {
KernelImpl* CpuPmeKernelFactory::createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const { KernelImpl* CpuPmeKernelFactory::createKernelImpl(std::string name, const Platform& platform, ContextImpl& context) const {
if (name == CalcPmeReciprocalForceKernel::Name()) if (name == CalcPmeReciprocalForceKernel::Name())
return new CpuCalcPmeReciprocalForceKernel(name, platform); return new CpuCalcPmeReciprocalForceKernel(name, platform);
if (name == CalcDispersionPmeReciprocalForceKernel::Name())
return new CpuCalcDispersionPmeReciprocalForceKernel(name, platform);
throw OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str()); throw OpenMMException((std::string("Tried to create kernel with illegal kernel name '")+name+"'").c_str());
} }
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "SimTKOpenMMRealType.h" #include "SimTKOpenMMRealType.h"
#include "openmm/internal/hardware.h" #include "openmm/internal/hardware.h"
#include "openmm/internal/vectorize.h" #include "openmm/internal/vectorize.h"
#include "openmm/OpenMMException.h"
#include <cmath> #include <cmath>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
...@@ -47,10 +48,10 @@ using namespace std; ...@@ -47,10 +48,10 @@ using namespace std;
static const int PME_ORDER = 5; static const int PME_ORDER = 5;
bool CpuCalcPmeReciprocalForceKernel::hasInitializedThreads = false; bool CpuCalcDispersionPmeReciprocalForceKernel::hasInitializedThreads = false;
int CpuCalcPmeReciprocalForceKernel::numThreads = 0; int CpuCalcDispersionPmeReciprocalForceKernel::numThreads = 0;
static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors, gmx_atomic_t& atomicCounter) { static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors, gmx_atomic_t& atomicCounter, const float epsilonFactor) {
float temp[4]; float temp[4];
fvec4 boxSize((float) periodicBoxVectors[0][0], (float) periodicBoxVectors[1][1], (float) periodicBoxVectors[2][2], 0); fvec4 boxSize((float) periodicBoxVectors[0][0], (float) periodicBoxVectors[1][1], (float) periodicBoxVectors[2][2], 0);
fvec4 invBoxSize((float) recipBoxVectors[0][0], (float) recipBoxVectors[1][1], (float) recipBoxVectors[2][2], 0); fvec4 invBoxSize((float) recipBoxVectors[0][0], (float) recipBoxVectors[1][1], (float) recipBoxVectors[2][2], 0);
...@@ -62,7 +63,6 @@ static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gri ...@@ -62,7 +63,6 @@ static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gri
fvec4 one(1); fvec4 one(1);
fvec4 scale(1.0f/(PME_ORDER-1)); fvec4 scale(1.0f/(PME_ORDER-1));
float posInBox[4] = {0,0,0,0}; float posInBox[4] = {0,0,0,0};
const float epsilonFactor = sqrt(ONE_4PI_EPS0);
memset(grid, 0, sizeof(float)*gridx*gridy*gridz); memset(grid, 0, sizeof(float)*gridx*gridy*gridz);
while (true) { while (true) {
...@@ -154,42 +154,60 @@ static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gri ...@@ -154,42 +154,60 @@ static void spreadCharge(float* posq, float* grid, int gridx, int gridy, int gri
} }
} }
static void computeReciprocalEterm(int start, int end, int gridx, int gridy, int gridz, vector<float>& recipEterm, double alpha, vector<float>* bsplineModuli, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) { #define FAST_ERFC 1
static void computeReciprocalDispersionEterm(int start, int end, int gridx, int gridy, int gridz, vector<float>& recipEterm, double alpha, vector<float>* bsplineModuli, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) {
const unsigned int zsize = gridz/2+1; const unsigned int zsize = gridz/2+1;
const unsigned int yzsize = gridy*zsize; const unsigned int yzsize = gridy*zsize;
const float scaleFactor = (float) (M_PI*periodicBoxVectors[0][0]*periodicBoxVectors[1][1]*periodicBoxVectors[2][2]); const float scaleFactor = (float) -2.0f*M_PI*sqrtf(M_PI) / (6.0*periodicBoxVectors[0][0]*periodicBoxVectors[1][1]*periodicBoxVectors[2][2]);
const float recipExpFactor = (float) (M_PI*M_PI/(alpha*alpha));
float bfac = M_PI / alpha;
float fac1 = 2.0f*M_PI*M_PI*M_PI*sqrtf(M_PI);
float fac2 = alpha*alpha*alpha;
float fac3 = -2.0f*alpha*M_PI*M_PI;
float b, m, m3, expterm, erfcterm, t;
int firstz = (start == 0 ? 1 : 0);
for (int kx = start; kx < end; kx++) { for (int kx = start; kx < end; kx++) {
int mx = (kx < (gridx+1)/2) ? kx : kx-gridx; int mx = (kx < (gridx+1)/2) ? kx : kx-gridx;
float mhx = mx*(float)recipBoxVectors[0][0]; float mhx = mx*(float)recipBoxVectors[0][0];
float bx = scaleFactor*bsplineModuli[0][kx]; float bx = bsplineModuli[0][kx];
for (int ky = 0; ky < gridy; ky++) { for (int ky = 0; ky < gridy; ky++) {
int my = (ky < (gridy+1)/2) ? ky : ky-gridy; int my = (ky < (gridy+1)/2) ? ky : ky-gridy;
float mhy = mx*(float)recipBoxVectors[1][0] + my*(float)recipBoxVectors[1][1]; float mhy = mx*(float)recipBoxVectors[1][0] + my*(float)recipBoxVectors[1][1];
float mhx2y2 = mhx*mhx + mhy*mhy; float mhx2y2 = mhx*mhx + mhy*mhy;
float bxby = bx*bsplineModuli[1][ky]; float bxby = bx*bsplineModuli[1][ky];
for (int kz = firstz; kz < zsize; kz++) { for (int kz = 0; kz < zsize; kz++) {
int index = kx*yzsize + ky*zsize + kz; int index = kx*yzsize + ky*zsize + kz;
int mz = (kz < (gridz+1)/2) ? kz : kz-gridz; int mz = (kz < (gridz+1)/2) ? kz : kz-gridz;
float mhz = mx*(float)recipBoxVectors[2][0] + my*(float)recipBoxVectors[2][1] + mz*(float)recipBoxVectors[2][2]; float mhz = mx*(float)recipBoxVectors[2][0] + my*(float)recipBoxVectors[2][1] + mz*(float)recipBoxVectors[2][2];
float bz = bsplineModuli[2][kz]; float bz = bsplineModuli[2][kz];
float m2 = mhx2y2 + mhz*mhz; float m2 = mhx2y2 + mhz*mhz;
float denom = m2*bxby*bz; float denom = scaleFactor/(bxby*bz);
recipEterm[index] = exp(-recipExpFactor*m2)/denom;
m = sqrtf(m2);
m3 = m*m2;
b = bfac*m;
expterm = exp(-b*b);
#if FAST_ERFC
// This approximation for erfc is from Abramowitz and Stegun (1964) p. 299. They cite the following as
// the original source: C. Hastings, Jr., Approximations for Digital Computers (1955). It has a maximum
// error of 1.5e-7. Stolen by ACS from the CUDA platform's AMOEBA plugin.
t = 1.0f/(1.0f+0.3275911f*b);
erfcterm = (0.254829592f+(-0.284496736f+(1.421413741f+(-1.453152027f+1.061405429f*t)*t)*t)*t)*t*expterm;
#else
erfcterm = erfc(b);
#endif
recipEterm[index] = (fac1*erfcterm*m3 + expterm*(fac2 + fac3*m2)) * denom;
} }
firstz = 0;
} }
} }
} }
static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int gridx, int gridy, int gridz, double alpha, vector<float>* bsplineModuli, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) { static void computeReciprocalEterm(int start, int end, int gridx, int gridy, int gridz, vector<float>& recipEterm, double alpha, vector<float>* bsplineModuli, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) {
const unsigned int zsizeHalf = gridz/2+1; const unsigned int zsize = gridz/2+1;
const unsigned int yzsizeHalf = gridy*zsizeHalf; const unsigned int yzsize = gridy*zsize;
const float scaleFactor = (float) (M_PI*periodicBoxVectors[0][0]*periodicBoxVectors[1][1]*periodicBoxVectors[2][2]); const float scaleFactor = (float) (M_PI*periodicBoxVectors[0][0]*periodicBoxVectors[1][1]*periodicBoxVectors[2][2]);
const float recipExpFactor = (float) (M_PI*M_PI/(alpha*alpha)); const float recipExpFactor = (float) (M_PI*M_PI/(alpha*alpha));
double energy = 0.0;
int firstz = (start == 0 ? 1 : 0); int firstz = (start == 0 ? 1 : 0);
for (int kx = start; kx < end; kx++) { for (int kx = start; kx < end; kx++) {
...@@ -201,13 +219,30 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid ...@@ -201,13 +219,30 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid
float mhy = mx*(float)recipBoxVectors[1][0] + my*(float)recipBoxVectors[1][1]; float mhy = mx*(float)recipBoxVectors[1][0] + my*(float)recipBoxVectors[1][1];
float mhx2y2 = mhx*mhx + mhy*mhy; float mhx2y2 = mhx*mhx + mhy*mhy;
float bxby = bx*bsplineModuli[1][ky]; float bxby = bx*bsplineModuli[1][ky];
for (int kz = firstz; kz < gridz; kz++) { for (int kz = firstz; kz < zsize; kz++) {
int index = kx*yzsize + ky*zsize + kz;
int mz = (kz < (gridz+1)/2) ? kz : kz-gridz; int mz = (kz < (gridz+1)/2) ? kz : kz-gridz;
float mhz = mx*(float)recipBoxVectors[2][0] + my*(float)recipBoxVectors[2][1] + mz*(float)recipBoxVectors[2][2]; float mhz = mx*(float)recipBoxVectors[2][0] + my*(float)recipBoxVectors[2][1] + mz*(float)recipBoxVectors[2][2];
float bz = bsplineModuli[2][kz]; float bz = bsplineModuli[2][kz];
float m2 = mhx2y2 + mhz*mhz; float m2 = mhx2y2 + mhz*mhz;
float denom = m2*bxby*bz; float denom = m2*bxby*bz;
float eterm = exp(-recipExpFactor*m2)/denom; recipEterm[index] = exp(-recipExpFactor*m2)/denom;
}
firstz = 0;
}
}
}
static double reciprocalEnergy(int start, int end, fftwf_complex* grid, vector<float>& recipEterm, int gridx, int gridy, int gridz, double alpha, vector<float>* bsplineModuli, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) {
const unsigned int zsizeHalf = gridz/2+1;
const unsigned int yzsizeHalf = gridy*zsizeHalf;
double energy = 0.0;
int firstz = (start == 0 ? 1 : 0);
for (int kx = start; kx < end; kx++) {
for (int ky = 0; ky < gridy; ky++) {
for (int kz = firstz; kz < gridz; kz++) {
int kx1, ky1, kz1; int kx1, ky1, kz1;
if (kz >= gridz/2+1) { if (kz >= gridz/2+1) {
kx1 = (kx == 0 ? kx : gridx-kx); kx1 = (kx == 0 ? kx : gridx-kx);
...@@ -222,7 +257,7 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid ...@@ -222,7 +257,7 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid
int index = kx1*yzsizeHalf + ky1*zsizeHalf + kz1; int index = kx1*yzsizeHalf + ky1*zsizeHalf + kz1;
float gridReal = grid[index][0]; float gridReal = grid[index][0];
float gridImag = grid[index][1]; float gridImag = grid[index][1];
energy += eterm*(gridReal*gridReal+gridImag*gridImag); energy += recipEterm[index]*(gridReal*gridReal+gridImag*gridImag);
} }
firstz = 0; firstz = 0;
} }
...@@ -230,6 +265,38 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid ...@@ -230,6 +265,38 @@ static double reciprocalEnergy(int start, int end, fftwf_complex* grid, int grid
return 0.5*energy; return 0.5*energy;
} }
static double reciprocalDispersionEnergy(int start, int end, fftwf_complex* grid, const vector<float>& recipEterm, int gridx, int gridy, int gridz, double alpha, vector<float>* bsplineModuli, Vec3* periodicBoxVectors, Vec3* recipBoxVectors) {
const unsigned int zsizeHalf = gridz/2+1;
const unsigned int yzsizeHalf = gridy*zsizeHalf;
double energy = 0.0;
for (int kx = start; kx < end; kx++) {
for (int ky = 0; ky < gridy; ky++) {
for (int kz = 0; kz < gridz; kz++) {
int kx1, ky1, kz1;
if (kz >= gridz/2+1) {
kx1 = (kx == 0 ? kx : gridx-kx);
ky1 = (ky == 0 ? ky : gridy-ky);
kz1 = gridz-kz;
}
else {
kx1 = kx;
ky1 = ky;
kz1 = kz;
}
int index = kx1*yzsizeHalf + ky1*zsizeHalf + kz1;
float gridReal = grid[index][0];
float gridImag = grid[index][1];
energy += recipEterm[index]*(gridReal*gridReal+gridImag*gridImag);
}
}
}
return 0.5f*energy;
}
static void reciprocalConvolution(int start, int end, fftwf_complex* grid, vector<float>& recipEterm) { static void reciprocalConvolution(int start, int end, fftwf_complex* grid, vector<float>& recipEterm) {
for (int index = start; index < end; index++) { for (int index = start; index < end; index++) {
float eterm = recipEterm[index]; float eterm = recipEterm[index];
...@@ -238,7 +305,7 @@ static void reciprocalConvolution(int start, int end, fftwf_complex* grid, vecto ...@@ -238,7 +305,7 @@ static void reciprocalConvolution(int start, int end, fftwf_complex* grid, vecto
} }
} }
static void interpolateForces(float* posq, float* force, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors, gmx_atomic_t& atomicCounter) { static void interpolateForces(float* posq, float* force, float* grid, int gridx, int gridy, int gridz, int numParticles, Vec3* periodicBoxVectors, Vec3* recipBoxVectors, gmx_atomic_t& atomicCounter, const float epsilonFactor) {
fvec4 boxSize((float) periodicBoxVectors[0][0], (float) periodicBoxVectors[1][1], (float) periodicBoxVectors[2][2], 0); fvec4 boxSize((float) periodicBoxVectors[0][0], (float) periodicBoxVectors[1][1], (float) periodicBoxVectors[2][2], 0);
fvec4 invBoxSize((float) recipBoxVectors[0][0], (float) recipBoxVectors[1][1], (float) recipBoxVectors[2][2], 0); fvec4 invBoxSize((float) recipBoxVectors[0][0], (float) recipBoxVectors[1][1], (float) recipBoxVectors[2][2], 0);
fvec4 recipBoxVec0((float) recipBoxVectors[0][0], (float) recipBoxVectors[0][1], (float) recipBoxVectors[0][2], 0); fvec4 recipBoxVec0((float) recipBoxVectors[0][0], (float) recipBoxVectors[0][1], (float) recipBoxVectors[0][2], 0);
...@@ -248,7 +315,6 @@ static void interpolateForces(float* posq, float* force, float* grid, int gridx, ...@@ -248,7 +315,6 @@ static void interpolateForces(float* posq, float* force, float* grid, int gridx,
ivec4 gridSizeInt(gridx, gridy, gridz, 0); ivec4 gridSizeInt(gridx, gridy, gridz, 0);
fvec4 one(1); fvec4 one(1);
fvec4 scale(1.0f/(PME_ORDER-1)); fvec4 scale(1.0f/(PME_ORDER-1));
const float epsilonFactor = sqrt(ONE_4PI_EPS0);
while (true) { while (true) {
int i = gmx_atomic_fetch_add(&atomicCounter, 1); int i = gmx_atomic_fetch_add(&atomicCounter, 1);
if (i >= numParticles) if (i >= numParticles)
...@@ -513,7 +579,8 @@ void CpuCalcPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int i ...@@ -513,7 +579,8 @@ void CpuCalcPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int i
int complexSize = gridx*gridy*(gridz/2+1); int complexSize = gridx*gridy*(gridz/2+1);
int complexStart = std::max(1, ((index*complexSize)/numThreads)); int complexStart = std::max(1, ((index*complexSize)/numThreads));
int complexEnd = (((index+1)*complexSize)/numThreads); int complexEnd = (((index+1)*complexSize)/numThreads);
spreadCharge(posq, tempGrid[index], gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter); const float epsilonFactor = sqrt(ONE_4PI_EPS0);
spreadCharge(posq, tempGrid[index], gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter, epsilonFactor);
threads.syncThreads(); threads.syncThreads();
int numGrids = tempGrid.size(); int numGrids = tempGrid.size();
for (int i = gridStart; i < gridEnd; i += 4) { for (int i = gridStart; i < gridEnd; i += 4) {
...@@ -528,12 +595,12 @@ void CpuCalcPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int i ...@@ -528,12 +595,12 @@ void CpuCalcPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int i
threads.syncThreads(); threads.syncThreads();
} }
if (includeEnergy) { if (includeEnergy) {
threadEnergy[index] = reciprocalEnergy(gridxStart, gridxEnd, complexGrid, gridx, gridy, gridz, alpha, bsplineModuli, periodicBoxVectors, recipBoxVectors); threadEnergy[index] = reciprocalEnergy(gridxStart, gridxEnd, complexGrid, recipEterm, gridx, gridy, gridz, alpha, bsplineModuli, periodicBoxVectors, recipBoxVectors);
threads.syncThreads(); threads.syncThreads();
} }
reciprocalConvolution(complexStart, complexEnd, complexGrid, recipEterm); reciprocalConvolution(complexStart, complexEnd, complexGrid, recipEterm);
threads.syncThreads(); threads.syncThreads();
interpolateForces(posq, &force[0], realGrid, gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter); interpolateForces(posq, &force[0], realGrid, gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter, epsilonFactor);
} }
void CpuCalcPmeReciprocalForceKernel::beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy) { void CpuCalcPmeReciprocalForceKernel::beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy) {
...@@ -603,3 +670,296 @@ int CpuCalcPmeReciprocalForceKernel::findFFTDimension(int minimum, bool isZ) { ...@@ -603,3 +670,296 @@ int CpuCalcPmeReciprocalForceKernel::findFFTDimension(int minimum, bool isZ) {
minimum++; minimum++;
} }
} }
/*
* Everything below here is just a clone of the above, but to handle the dispersion term
* instead of electrostatics.
*/
bool CpuCalcPmeReciprocalForceKernel::hasInitializedThreads = false;
int CpuCalcPmeReciprocalForceKernel::numThreads = 0;
class CpuCalcDispersionPmeReciprocalForceKernel::ComputeTask : public ThreadPool::Task {
public:
ComputeTask(CpuCalcDispersionPmeReciprocalForceKernel& owner) : owner(owner) {
}
void execute(ThreadPool& threads, int threadIndex) {
owner.runWorkerThread(threads, threadIndex);
}
CpuCalcDispersionPmeReciprocalForceKernel& owner;
};
static void* dispersionThreadBody(void* args) {
CpuCalcDispersionPmeReciprocalForceKernel& owner = *reinterpret_cast<CpuCalcDispersionPmeReciprocalForceKernel*>(args);
owner.runMainThread();
return 0;
}
void CpuCalcDispersionPmeReciprocalForceKernel::initialize(int xsize, int ysize, int zsize, int numParticles, double alpha) {
if (!hasInitializedThreads) {
numThreads = getNumProcessors();
char* threadsEnv = getenv("OPENMM_CPU_THREADS");
if (threadsEnv != NULL)
stringstream(threadsEnv) >> numThreads;
fftwf_init_threads();
hasInitializedThreads = true;
}
threadEnergy.resize(numThreads);
gridx = findFFTDimension(xsize, false);
gridy = findFFTDimension(ysize, false);
gridz = findFFTDimension(zsize, true);
this->numParticles = numParticles;
this->alpha = alpha;
force.resize(4*numParticles);
recipEterm.resize(gridx*gridy*gridz);
// Initialize threads.
isFinished = false;
pthread_cond_init(&startCondition, NULL);
pthread_cond_init(&endCondition, NULL);
pthread_mutex_init(&lock, NULL);
pthread_create(&mainThread, NULL, dispersionThreadBody, this);
// Wait until the main thread is up and running.
pthread_mutex_lock(&lock);
while (!isFinished)
pthread_cond_wait(&endCondition, &lock);
pthread_mutex_unlock(&lock);
// Initialize FFTW.
for (int i = 0; i < numThreads; i++)
tempGrid.push_back((float*) fftwf_malloc(sizeof(float)*(gridx*gridy*gridz+3)));
realGrid = tempGrid[0];
complexGrid = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex)*gridx*gridy*(gridz/2+1));
fftwf_plan_with_nthreads(numThreads);
forwardFFT = fftwf_plan_dft_r2c_3d(gridx, gridy, gridz, realGrid, complexGrid, FFTW_MEASURE);
backwardFFT = fftwf_plan_dft_c2r_3d(gridx, gridy, gridz, complexGrid, realGrid, FFTW_MEASURE);
hasCreatedPlan = true;
// Initialize the b-spline moduli.
int maxSize = std::max(std::max(gridx, gridy), gridz);
vector<double> data(PME_ORDER);
vector<double> ddata(PME_ORDER);
vector<double> bsplinesData(maxSize);
data[PME_ORDER-1] = 0.0;
data[1] = 0.0;
data[0] = 1.0;
for (int i = 3; i < PME_ORDER; i++) {
double div = 1.0/(i-1.0);
data[i-1] = 0.0;
for (int j = 1; j < (i-1); j++)
data[i-j-1] = div*(j*data[i-j-2]+(i-j)*data[i-j-1]);
data[0] = div*data[0];
}
// Differentiate.
ddata[0] = -data[0];
for (int i = 1; i < PME_ORDER; i++)
ddata[i] = data[i-1]-data[i];
double div = 1.0/(PME_ORDER-1);
data[PME_ORDER-1] = 0.0;
for (int i = 1; i < (PME_ORDER-1); i++)
data[PME_ORDER-i-1] = div*(i*data[PME_ORDER-i-2]+(PME_ORDER-i)*data[PME_ORDER-i-1]);
data[0] = div*data[0];
for (int i = 0; i < maxSize; i++)
bsplinesData[i] = 0.0;
for (int i = 1; i <= PME_ORDER; i++)
bsplinesData[i] = data[i-1];
// Evaluate the actual bspline moduli for X/Y/Z.
bsplineModuli[0].resize(gridx);
bsplineModuli[1].resize(gridy);
bsplineModuli[2].resize(gridz);
for (int dim = 0; dim < 3; dim++) {
int ndata = bsplineModuli[dim].size();
vector<float>& moduli = bsplineModuli[dim];
for (int i = 0; i < ndata; i++) {
double sc = 0.0;
double ss = 0.0;
for (int j = 0; j < ndata; j++) {
double arg = (2.0*M_PI*i*j)/ndata;
sc += bsplinesData[j]*cos(arg);
ss += bsplinesData[j]*sin(arg);
}
moduli[i] = (float) (sc*sc+ss*ss);
}
for (int i = 0; i < ndata; i++)
if (moduli[i] < 1.0e-7f)
moduli[i] = (moduli[i-1]+moduli[i+1])*0.5f;
}
}
CpuCalcDispersionPmeReciprocalForceKernel::~CpuCalcDispersionPmeReciprocalForceKernel() {
isDeleted = true;
pthread_mutex_lock(&lock);
pthread_cond_broadcast(&startCondition);
pthread_mutex_unlock(&lock);
pthread_join(mainThread, NULL);
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&startCondition);
pthread_cond_destroy(&endCondition);
for (int i = 0; i < (int) tempGrid.size(); i++)
fftwf_free(tempGrid[i]);
if (complexGrid != NULL)
fftwf_free(complexGrid);
if (hasCreatedPlan) {
fftwf_destroy_plan(forwardFFT);
fftwf_destroy_plan(backwardFFT);
}
}
void CpuCalcDispersionPmeReciprocalForceKernel::runMainThread() {
// This is the main thread that coordinates all the other ones.
pthread_mutex_lock(&lock);
isFinished = true;
pthread_cond_signal(&endCondition);
ThreadPool threads(numThreads);
while (true) {
// Wait for the signal to start.
pthread_cond_wait(&startCondition, &lock);
if (isDeleted)
break;
posq = io->getPosq();
ComputeTask task(*this);
gmx_atomic_set(&atomicCounter, 0);
threads.execute(task); // Signal threads to perform charge spreading.
threads.waitForThreads();
threads.resumeThreads(); // Signal threads to sum the charge grids.
threads.waitForThreads();
fftwf_execute_dft_r2c(forwardFFT, realGrid, complexGrid);
if (lastBoxVectors[0] != periodicBoxVectors[0] || lastBoxVectors[1] != periodicBoxVectors[1] || lastBoxVectors[2] != periodicBoxVectors[2]) {
threads.resumeThreads(); // Signal threads to compute the reciprocal scale factors.
threads.waitForThreads();
}
if (includeEnergy) {
threads.resumeThreads(); // Signal threads to compute energy.
threads.waitForThreads();
for (int i = 0; i < (int) threadEnergy.size(); i++)
energy += threadEnergy[i];
}
threads.resumeThreads(); // Signal threads to perform reciprocal convolution.
threads.waitForThreads();
fftwf_execute_dft_c2r(backwardFFT, complexGrid, realGrid);
gmx_atomic_set(&atomicCounter, 0);
threads.resumeThreads(); // Signal threads to interpolate forces.
threads.waitForThreads();
isFinished = true;
lastBoxVectors[0] = periodicBoxVectors[0];
lastBoxVectors[1] = periodicBoxVectors[1];
lastBoxVectors[2] = periodicBoxVectors[2];
pthread_cond_signal(&endCondition);
}
pthread_mutex_unlock(&lock);
}
void CpuCalcDispersionPmeReciprocalForceKernel::runWorkerThread(ThreadPool& threads, int index) {
int gridxStart = (index*gridx)/numThreads;
int gridxEnd = ((index+1)*gridx)/numThreads;
int gridSize = (gridx*gridy*gridz+3)/4;
int gridStart = 4*((index*gridSize)/numThreads);
int gridEnd = 4*(((index+1)*gridSize)/numThreads);
int complexSize = gridx*gridy*(gridz/2+1);
int complexStart = std::max(1, ((index*complexSize)/numThreads));
int complexEnd = (((index+1)*complexSize)/numThreads);
const float epsilonFactor = 1.0f;
spreadCharge(posq, tempGrid[index], gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter, epsilonFactor);
threads.syncThreads();
int numGrids = tempGrid.size();
for (int i = gridStart; i < gridEnd; i += 4) {
fvec4 sum(&realGrid[i]);
for (int j = 1; j < numGrids; j++)
sum += fvec4(&tempGrid[j][i]);
sum.store(&realGrid[i]);
}
threads.syncThreads();
if (lastBoxVectors[0] != periodicBoxVectors[0] || lastBoxVectors[1] != periodicBoxVectors[1] || lastBoxVectors[2] != periodicBoxVectors[2]) {
computeReciprocalDispersionEterm(gridxStart, gridxEnd, gridx, gridy, gridz, recipEterm, alpha, bsplineModuli, periodicBoxVectors, recipBoxVectors);
threads.syncThreads();
}
if (includeEnergy) {
threadEnergy[index] = reciprocalDispersionEnergy(gridxStart, gridxEnd, complexGrid, recipEterm, gridx, gridy, gridz, alpha, bsplineModuli, periodicBoxVectors, recipBoxVectors);
threads.syncThreads();
}
// For dispersion, we include the {0,0,0} term, so the start point needs to be redefined
complexStart = (index*complexSize)/numThreads;
reciprocalConvolution(complexStart, complexEnd, complexGrid, recipEterm);
threads.syncThreads();
interpolateForces(posq, &force[0], realGrid, gridx, gridy, gridz, numParticles, periodicBoxVectors, recipBoxVectors, atomicCounter, epsilonFactor);
}
void CpuCalcDispersionPmeReciprocalForceKernel::beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy) {
this->io = &io;
this->periodicBoxVectors[0] = periodicBoxVectors[0];
this->periodicBoxVectors[1] = periodicBoxVectors[1];
this->periodicBoxVectors[2] = periodicBoxVectors[2];
this->includeEnergy = includeEnergy;
energy = 0.0;
// Invert the box vectors.
double determinant = periodicBoxVectors[0][0]*periodicBoxVectors[1][1]*periodicBoxVectors[2][2];
double scale = 1.0/determinant;
recipBoxVectors[0] = Vec3(periodicBoxVectors[1][1]*periodicBoxVectors[2][2], 0, 0)*scale;
recipBoxVectors[1] = Vec3(-periodicBoxVectors[1][0]*periodicBoxVectors[2][2], periodicBoxVectors[0][0]*periodicBoxVectors[2][2], 0)*scale;
recipBoxVectors[2] = Vec3(periodicBoxVectors[1][0]*periodicBoxVectors[2][1]-periodicBoxVectors[1][1]*periodicBoxVectors[2][0], -periodicBoxVectors[0][0]*periodicBoxVectors[2][1], periodicBoxVectors[0][0]*periodicBoxVectors[1][1])*scale;
// Do the calculation.
pthread_mutex_lock(&lock);
isFinished = false;
pthread_cond_signal(&startCondition);
pthread_mutex_unlock(&lock);
}
double CpuCalcDispersionPmeReciprocalForceKernel::finishComputation(IO& io) {
pthread_mutex_lock(&lock);
while (!isFinished) {
pthread_cond_wait(&endCondition, &lock);
}
pthread_mutex_unlock(&lock);
io.setForce(&force[0]);
return energy;
}
bool CpuCalcDispersionPmeReciprocalForceKernel::isProcessorSupported() {
return isVec4Supported();
}
void CpuCalcDispersionPmeReciprocalForceKernel::getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const {
alpha = this->alpha;
nx = gridx;
ny = gridy;
nz = gridz;
}
int CpuCalcDispersionPmeReciprocalForceKernel::findFFTDimension(int minimum, bool isZ) {
if (minimum < 1)
return 1;
while (true) {
// Attempt to factor the current value.
if (isZ && minimum%2 == 1) {
// Force the last dimension to be even, since this produces better performance in FFTW.
minimum++;
continue;
}
int unfactored = minimum;
for (int factor = 2; factor < 8; factor++) {
while (unfactored > 1 && unfactored%factor == 0)
unfactored /= factor;
}
if (unfactored == 1 || unfactored == 11 || unfactored == 13)
return minimum;
minimum++;
}
}
...@@ -133,6 +133,98 @@ private: ...@@ -133,6 +133,98 @@ private:
gmx_atomic_t atomicCounter; gmx_atomic_t atomicCounter;
}; };
/**
* This is an optimized CPU implementation of CalcDispersionPmeReciprocalForceKernel. It is both
* vectorized (requiring SSE 4.1) and multithreaded. It uses FFTW to perform the FFTs.
*/
class OPENMM_EXPORT_PME CpuCalcDispersionPmeReciprocalForceKernel : public CalcPmeReciprocalForceKernel {
public:
CpuCalcDispersionPmeReciprocalForceKernel(std::string name, const Platform& platform) : CalcPmeReciprocalForceKernel(name, platform),
hasCreatedPlan(false), isDeleted(false), realGrid(NULL), complexGrid(NULL) {
}
/**
* Initialize the kernel.
*
* @param gridx the x size of the PME grid
* @param gridy the y size of the PME grid
* @param gridz the z size of the PME grid
* @param numParticles the number of particles in the system
* @param alpha the Ewald blending parameter
*/
void initialize(int xsize, int ysize, int zsize, int numParticles, double alpha);
~CpuCalcDispersionPmeReciprocalForceKernel();
/**
* Begin computing the force and energy.
*
* @param io an object that coordinates data transfer
* @param periodicBoxVectors the vectors defining the periodic box (measured in nm)
* @param includeEnergy true if potential energy should be computed
*/
void beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy);
/**
* Finish computing the force and energy.
*
* @param io an object that coordinates data transfer
* @return the potential energy due to the PME reciprocal space interactions
*/
double finishComputation(IO& io);
/**
* This routine contains the code executed by the main thread.
*/
void runMainThread();
/**
* This routine contains the code executed by each worker thread.
*/
void runWorkerThread(ThreadPool& threads, int index);
/**
* Get whether the current CPU supports all features needed by this kernel.
*/
static bool isProcessorSupported();
/**
* Get the parameters being used for PME.
*
* @param alpha the separation parameter
* @param nx the number of grid points along the X axis
* @param ny the number of grid points along the Y axis
* @param nz the number of grid points along the Z axis
*/
void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const;
private:
class ComputeTask;
/**
* Select a size for one grid dimension that FFTW can handle efficiently.
*/
int findFFTDimension(int minimum, bool isZ);
static bool hasInitializedThreads;
static int numThreads;
int gridx, gridy, gridz, numParticles;
double alpha;
bool hasCreatedPlan, isFinished, isDeleted;
std::vector<float> force;
std::vector<float> bsplineModuli[3];
std::vector<float> recipEterm;
Vec3 lastBoxVectors[3];
std::vector<float> threadEnergy;
std::vector<float*> tempGrid;
float* realGrid;
fftwf_complex* complexGrid;
fftwf_plan forwardFFT, backwardFFT;
int waitCount;
pthread_cond_t startCondition, endCondition;
pthread_mutex_t lock;
pthread_t mainThread;
// The following variables are used to store information about the calculation currently being performed.
IO* io;
float energy;
float* posq;
Vec3 periodicBoxVectors[3], recipBoxVectors[3];
bool includeEnergy;
gmx_atomic_t atomicCounter;
};
} // namespace OpenMM } // namespace OpenMM
#endif /*OPENMM_CPU_PME_KERNELS_H_*/ #endif /*OPENMM_CPU_PME_KERNELS_H_*/
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "openmm/System.h" #include "openmm/System.h"
#include "openmm/VerletIntegrator.h" #include "openmm/VerletIntegrator.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/Units.h"
#include "../src/CpuPmeKernels.h" #include "../src/CpuPmeKernels.h"
#include "SimTKOpenMMRealType.h" #include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h" #include "sfmt/SFMT.h"
...@@ -61,6 +62,509 @@ public: ...@@ -61,6 +62,509 @@ public:
} }
}; };
void make_waterbox(int natoms, double boxEdgeLength, NonbondedForce *forceField, vector<Vec3> &positions, vector<double>& eps, vector<double>& sig,
vector<pair<int, int> >& bonds, System &system, bool do_electrostatics) {
const int RESSIZE = 3;
const double masses[RESSIZE] = { 8.0, 1.0, 1.0 };
const double charges[RESSIZE] = { -0.834, 0.417, 0.417 };
// Values from the CHARMM force field, in AKMA units
const double epsilons[RESSIZE] = { -0.1521, -0.046, -0.046 };
const double halfrmins[RESSIZE] = { 1.7682, 0.2245, 0.2245 };
positions.clear();
if(natoms == 6){
const double coords[6][3] = {
{ 2.000000, 2.000000, 2.000000},
{ 2.500000, 2.000000, 3.000000},
{ 1.500000, 2.000000, 3.000000},
{ 0.000000, 0.000000, 0.000000},
{ 0.500000, 0.000000, 1.000000},
{ -0.500000, 0.000000, 1.000000}
};
for(int atom = 0; atom < natoms; ++atom)
positions.push_back(Vec3(coords[atom][0], coords[atom][1], coords[atom][2])*OpenMM::NmPerAngstrom);
}else if(natoms == 375){
const double coords[375][3] = {
{ -6.22, -6.25, -6.24 },
{ -5.32, -6.03, -6.00 },
{ -6.75, -5.56, -5.84 },
{ -3.04, -6.23, -6.19 },
{ -3.52, -5.55, -5.71 },
{ -3.59, -6.43, -6.94 },
{ 0.02, -6.23, -6.14 },
{ -0.87, -5.97, -6.37 },
{ 0.53, -6.03, -6.93 },
{ 3.10, -6.20, -6.27 },
{ 3.87, -6.35, -5.72 },
{ 2.37, -6.11, -5.64 },
{ 6.18, -6.14, -6.20 },
{ 6.46, -6.66, -5.44 },
{ 6.26, -6.74, -6.94 },
{ -6.21, -3.15, -6.24 },
{ -6.23, -3.07, -5.28 },
{ -6.02, -2.26, -6.55 },
{ -3.14, -3.07, -6.16 },
{ -3.38, -3.63, -6.90 },
{ -2.18, -3.05, -6.17 },
{ -0.00, -3.16, -6.23 },
{ -0.03, -2.30, -6.67 },
{ 0.05, -2.95, -5.29 },
{ 3.08, -3.11, -6.14 },
{ 2.65, -2.55, -6.79 },
{ 3.80, -3.53, -6.62 },
{ 6.16, -3.14, -6.16 },
{ 7.04, -3.32, -6.51 },
{ 5.95, -2.27, -6.51 },
{ -6.20, -0.04, -6.15 },
{ -5.43, 0.32, -6.59 },
{ -6.95, 0.33, -6.62 },
{ -3.10, -0.06, -6.19 },
{ -3.75, 0.42, -6.69 },
{ -2.46, 0.60, -5.93 },
{ 0.05, -0.01, -6.17 },
{ -0.10, 0.02, -7.12 },
{ -0.79, 0.16, -5.77 },
{ 3.03, 0.00, -6.19 },
{ 3.54, 0.08, -7.01 },
{ 3.69, -0.22, -5.53 },
{ 6.17, 0.05, -6.19 },
{ 5.78, -0.73, -6.57 },
{ 7.09, -0.17, -6.04 },
{ -6.20, 3.15, -6.25 },
{ -6.59, 3.18, -5.37 },
{ -5.87, 2.25, -6.33 },
{ -3.09, 3.04, -6.17 },
{ -3.88, 3.58, -6.26 },
{ -2.41, 3.54, -6.63 },
{ 0.00, 3.06, -6.26 },
{ -0.71, 3.64, -6.00 },
{ 0.65, 3.15, -5.55 },
{ 3.14, 3.06, -6.23 },
{ 3.11, 3.31, -5.30 },
{ 2.38, 3.49, -6.63 },
{ 6.19, 3.14, -6.25 },
{ 6.82, 3.25, -5.54 },
{ 5.76, 2.30, -6.07 },
{ -6.22, 6.26, -6.19 },
{ -6.22, 5.74, -7.00 },
{ -5.89, 5.67, -5.52 },
{ -3.04, 6.24, -6.20 },
{ -3.08, 5.28, -6.17 },
{ -3.96, 6.52, -6.25 },
{ -0.05, 6.21, -6.16 },
{ 0.82, 6.58, -6.06 },
{ 0.01, 5.64, -6.93 },
{ 3.10, 6.25, -6.15 },
{ 3.64, 5.47, -6.31 },
{ 2.46, 6.24, -6.87 },
{ 6.22, 6.20, -6.27 },
{ 5.37, 6.42, -5.88 },
{ 6.80, 6.07, -5.51 },
{ -6.19, -6.15, -3.13 },
{ -6.37, -7.01, -3.51 },
{ -6.25, -6.29, -2.18 },
{ -3.10, -6.27, -3.11 },
{ -2.29, -5.77, -2.99 },
{ -3.80, -5.62, -2.98 },
{ -0.03, -6.18, -3.15 },
{ -0.07, -7.05, -2.75 },
{ 0.68, -5.74, -2.70 },
{ 3.10, -6.14, -3.07 },
{ 2.35, -6.72, -3.23 },
{ 3.86, -6.65, -3.37 },
{ 6.22, -6.20, -3.16 },
{ 6.82, -6.36, -2.43 },
{ 5.35, -6.13, -2.75 },
{ -6.26, -3.13, -3.12 },
{ -6.16, -2.27, -2.70 },
{ -5.36, -3.47, -3.18 },
{ -3.11, -3.05, -3.14 },
{ -3.31, -3.96, -3.34 },
{ -2.77, -3.06, -2.24 },
{ 0.00, -3.13, -3.16 },
{ 0.48, -2.37, -2.81 },
{ -0.57, -3.40, -2.44 },
{ 3.09, -3.09, -3.16 },
{ 2.41, -3.19, -2.49 },
{ 3.91, -3.07, -2.67 },
{ 6.19, -3.04, -3.08 },
{ 5.64, -3.61, -3.61 },
{ 6.93, -3.58, -2.82 },
{ -6.18, -0.00, -3.04 },
{ -6.00, -0.59, -3.78 },
{ -6.79, 0.64, -3.39 },
{ -3.05, -0.03, -3.07 },
{ -2.95, 0.80, -3.52 },
{ -4.00, -0.20, -3.07 },
{ -0.03, 0.03, -3.06 },
{ -0.33, -0.37, -3.87 },
{ 0.89, -0.21, -2.99 },
{ 3.13, -0.05, -3.10 },
{ 3.44, 0.81, -3.34 },
{ 2.21, 0.07, -2.86 },
{ 6.20, -0.05, -3.13 },
{ 6.89, 0.60, -3.20 },
{ 5.58, 0.30, -2.49 },
{ -6.23, 3.09, -3.16 },
{ -5.62, 3.79, -2.94 },
{ -6.33, 2.60, -2.33 },
{ -3.10, 3.08, -3.04 },
{ -3.84, 3.47, -3.51 },
{ -2.40, 3.01, -3.69 },
{ 0.01, 3.04, -3.11 },
{ -0.56, 3.59, -3.64 },
{ 0.28, 3.60, -2.38 },
{ 3.04, 3.11, -3.09 },
{ 3.49, 2.30, -2.87 },
{ 3.70, 3.66, -3.51 },
{ 6.15, 3.14, -3.11 },
{ 6.52, 2.52, -3.74 },
{ 6.72, 3.06, -2.34 },
{ -6.22, 6.15, -3.13 },
{ -5.49, 6.21, -2.51 },
{ -6.56, 7.04, -3.18 },
{ -3.11, 6.24, -3.05 },
{ -3.76, 5.83, -3.62 },
{ -2.26, 5.92, -3.37 },
{ 0.03, 6.25, -3.07 },
{ 0.34, 5.63, -3.73 },
{ -0.87, 6.00, -2.91 },
{ 3.07, 6.15, -3.08 },
{ 3.29, 6.92, -2.56 },
{ 3.39, 6.35, -3.96 },
{ 6.22, 6.14, -3.12 },
{ 5.79, 6.38, -2.29 },
{ 6.25, 6.96, -3.62 },
{ -6.21, -6.20, -0.06 },
{ -5.79, -6.87, 0.48 },
{ -6.43, -5.50, 0.54 },
{ -3.16, -6.21, -0.02 },
{ -2.50, -6.87, 0.20 },
{ -2.77, -5.37, 0.23 },
{ -0.00, -6.14, -0.00 },
{ 0.68, -6.72, -0.33 },
{ -0.64, -6.73, 0.38 },
{ 3.03, -6.20, -0.01 },
{ 3.77, -6.56, -0.51 },
{ 3.43, -5.85, 0.78 },
{ 6.25, -6.16, -0.00 },
{ 5.36, -6.09, -0.36 },
{ 6.24, -6.97, 0.49 },
{ -6.24, -3.05, -0.01 },
{ -6.35, -3.64, 0.73 },
{ -5.42, -3.33, -0.42 },
{ -3.09, -3.06, 0.05 },
{ -2.44, -3.62, -0.38 },
{ -3.90, -3.21, -0.43 },
{ 0.05, -3.10, 0.02 },
{ -0.31, -2.35, -0.43 },
{ -0.63, -3.77, 0.01 },
{ 3.05, -3.09, -0.04 },
{ 3.28, -3.90, 0.41 },
{ 3.65, -2.43, 0.30 },
{ 6.20, -3.04, -0.03 },
{ 5.66, -3.31, 0.71 },
{ 6.78, -3.79, -0.19 },
{ -6.18, 0.04, -0.04 },
{ -6.73, -0.73, -0.15 },
{ -5.98, 0.06, 0.89 },
{ -3.11, -0.04, -0.04 },
{ -3.36, -0.08, 0.87 },
{ -2.70, 0.81, -0.14 },
{ -0.02, -0.02, -0.05 },
{ -0.45, 0.28, 0.75 },
{ 0.90, 0.15, 0.07 },
{ 3.04, 0.02, -0.01 },
{ 3.26, -0.82, 0.38 },
{ 3.89, 0.45, -0.13 },
{ 6.19, 0.05, -0.03 },
{ 5.52, -0.56, 0.25 },
{ 7.01, -0.29, 0.32 },
{ -6.14, 3.08, 0.00 },
{ -6.83, 2.82, 0.61 },
{ -6.59, 3.64, -0.64 },
{ -3.05, 3.09, -0.04 },
{ -3.79, 2.50, 0.09 },
{ -3.18, 3.80, 0.59 },
{ 0.02, 3.14, 0.04 },
{ -0.89, 3.04, -0.19 },
{ 0.49, 2.57, -0.57 },
{ 3.14, 3.15, 0.00 },
{ 3.28, 2.28, 0.37 },
{ 2.30, 3.08, -0.45 },
{ 6.27, 3.08, -0.00 },
{ 5.55, 2.54, -0.33 },
{ 5.83, 3.87, 0.34 },
{ -6.18, 6.15, -0.03 },
{ -6.45, 6.21, 0.88 },
{ -6.26, 7.05, -0.36 },
{ -3.06, 6.19, -0.05 },
{ -2.84, 6.64, 0.76 },
{ -3.99, 5.96, 0.03 },
{ -0.00, 6.20, 0.06 },
{ -0.67, 5.99, -0.59 },
{ 0.76, 6.46, -0.44 },
{ 3.10, 6.26, -0.03 },
{ 3.57, 6.09, 0.78 },
{ 2.57, 5.47, -0.18 },
{ 6.26, 6.18, 0.02 },
{ 5.53, 5.64, -0.29 },
{ 5.95, 7.08, -0.06 },
{ -6.26, -6.21, 3.07 },
{ -5.98, -6.38, 3.97 },
{ -5.46, -5.94, 2.62 },
{ -3.10, -6.24, 3.04 },
{ -2.69, -6.51, 3.87 },
{ -3.43, -5.35, 3.21 },
{ -0.03, -6.16, 3.06 },
{ 0.83, -6.00, 3.42 },
{ -0.30, -6.99, 3.45 },
{ 3.15, -6.25, 3.11 },
{ 2.77, -5.60, 3.72 },
{ 2.68, -6.10, 2.28 },
{ 6.20, -6.21, 3.16 },
{ 5.75, -6.73, 2.50 },
{ 6.69, -5.56, 2.66 },
{ -6.17, -3.10, 3.04 },
{ -6.82, -2.44, 3.28 },
{ -6.12, -3.69, 3.80 },
{ -3.08, -3.04, 3.11 },
{ -3.59, -3.56, 3.72 },
{ -2.97, -3.61, 2.34 },
{ 0.01, -3.04, 3.11 },
{ -0.86, -3.41, 3.20 },
{ 0.56, -3.78, 2.86 },
{ 3.07, -3.07, 3.15 },
{ 3.81, -3.68, 3.13 },
{ 2.80, -2.98, 2.23 },
{ 6.20, -3.04, 3.13 },
{ 5.48, -3.64, 2.92 },
{ 6.98, -3.49, 2.81 },
{ -6.18, -0.05, 3.12 },
{ -6.41, 0.66, 3.69 },
{ -6.33, 0.28, 2.23 },
{ -3.05, 0.03, 3.10 },
{ -3.46, -0.42, 3.83 },
{ -3.57, -0.19, 2.33 },
{ 0.03, -0.02, 3.15 },
{ 0.23, -0.08, 2.21 },
{ -0.81, 0.41, 3.18 },
{ 3.09, 0.00, 3.03 },
{ 2.48, -0.29, 3.71 },
{ 3.91, 0.16, 3.51 },
{ 6.19, -0.06, 3.11 },
{ 6.05, 0.47, 2.33 },
{ 6.59, 0.52, 3.74 },
{ -6.20, 3.05, 3.05 },
{ -6.87, 3.73, 3.17 },
{ -5.55, 3.24, 3.73 },
{ -3.11, 3.06, 3.15 },
{ -3.64, 3.74, 2.71 },
{ -2.32, 3.00, 2.62 },
{ 0.02, 3.05, 3.06 },
{ -0.87, 3.14, 3.38 },
{ 0.48, 3.82, 3.42 },
{ 3.07, 3.10, 3.16 },
{ 3.95, 3.44, 2.97 },
{ 2.76, 2.73, 2.32 },
{ 6.19, 3.07, 3.16 },
{ 7.02, 3.30, 2.72 },
{ 5.52, 3.27, 2.51 },
{ -6.19, 6.24, 3.15 },
{ -5.56, 5.88, 2.52 },
{ -7.05, 5.96, 2.83 },
{ -3.10, 6.14, 3.08 },
{ -2.34, 6.69, 3.27 },
{ -3.86, 6.69, 3.29 },
{ -0.04, 6.24, 3.13 },
{ 0.63, 6.54, 2.53 },
{ 0.08, 5.29, 3.18 },
{ 3.12, 6.24, 3.14 },
{ 3.57, 5.82, 2.40 },
{ 2.23, 5.90, 3.12 },
{ 6.25, 6.19, 3.06 },
{ 5.55, 5.59, 3.32 },
{ 6.08, 6.99, 3.55 },
{ -6.20, -6.16, 6.15 },
{ -6.29, -5.99, 7.09 },
{ -6.09, -7.11, 6.09 },
{ -3.09, -6.19, 6.27 },
{ -2.56, -5.90, 5.52 },
{ -3.80, -6.69, 5.87 },
{ 0.02, -6.25, 6.24 },
{ -0.70, -5.70, 6.51 },
{ 0.25, -5.93, 5.36 },
{ 3.11, -6.18, 6.14 },
{ 3.76, -6.54, 6.74 },
{ 2.29, -6.20, 6.64 },
{ 6.22, -6.17, 6.15 },
{ 6.61, -6.98, 6.47 },
{ 5.56, -5.94, 6.81 },
{ -6.21, -3.10, 6.14 },
{ -6.76, -2.66, 6.78 },
{ -5.51, -3.50, 6.65 },
{ -3.13, -3.05, 6.18 },
{ -2.19, -3.14, 6.34 },
{ -3.50, -3.89, 6.43 },
{ 0.01, -3.06, 6.15 },
{ -0.06, -2.81, 7.07 },
{ -0.25, -3.98, 6.13 },
{ 3.04, -3.09, 6.17 },
{ 3.84, -3.51, 5.84 },
{ 3.25, -2.85, 7.08 },
{ 6.26, -3.13, 6.19 },
{ 6.01, -2.20, 6.09 },
{ 5.47, -3.55, 6.54 },
{ -6.20, 0.01, 6.27 },
{ -5.79, -0.70, 5.78 },
{ -6.67, 0.51, 5.60 },
{ -3.13, 0.01, 6.14 },
{ -3.53, -0.35, 6.94 },
{ -2.21, 0.17, 6.39 },
{ -0.04, -0.04, 6.20 },
{ 0.26, 0.47, 5.46 },
{ 0.51, 0.22, 6.93 },
{ 3.10, -0.05, 6.23 },
{ 2.33, 0.44, 5.95 },
{ 3.85, 0.45, 5.92 },
{ 6.19, -0.01, 6.26 },
{ 7.05, 0.16, 5.88 },
{ 5.58, 0.02, 5.52 },
{ -6.22, 3.04, 6.17 },
{ -5.45, 3.57, 5.95 },
{ -6.62, 3.50, 6.92 },
{ -3.09, 3.16, 6.21 },
{ -3.71, 2.75, 5.61 },
{ -2.60, 2.43, 6.59 },
{ -0.02, 3.10, 6.26 },
{ 0.89, 3.27, 6.05 },
{ -0.44, 2.94, 5.41 },
{ 3.12, 3.04, 6.23 },
{ 2.31, 3.53, 6.43 },
{ 3.59, 3.60, 5.60 },
{ 6.23, 3.05, 6.24 },
{ 5.92, 3.91, 6.54 },
{ 6.02, 3.03, 5.30 },
{ -6.15, 6.21, 6.24 },
{ -6.27, 6.46, 5.32 },
{ -7.00, 5.85, 6.51 },
{ -3.07, 6.15, 6.22 },
{ -3.98, 6.27, 5.94 },
{ -2.66, 7.01, 6.10 },
{ 0.04, 6.20, 6.25 },
{ -0.38, 5.50, 5.75 },
{ -0.36, 7.00, 5.93 },
{ 3.12, 6.15, 6.24 },
{ 3.66, 6.88, 5.93 },
{ 2.25, 6.33, 5.86 },
{ 6.20, 6.27, 6.19 },
{ 5.46, 5.65, 6.19 },
{ 6.97, 5.73, 6.39 }
};
for(int atom = 0; atom < natoms; ++atom)
positions.push_back(Vec3(coords[atom][0], coords[atom][1], coords[atom][2])*OpenMM::NmPerAngstrom);
}else{
throw exception();
}
system.setDefaultPeriodicBoxVectors(Vec3(boxEdgeLength, 0, 0),
Vec3(0, boxEdgeLength, 0),
Vec3(0, 0, boxEdgeLength));
sig.clear();
eps.clear();
bonds.clear();
for(int atom = 0; atom < natoms; ++atom){
system.addParticle(masses[atom%RESSIZE]);
double sigma = 2.0*pow(2.0, -1.0/6.0)*halfrmins[atom%RESSIZE]*OpenMM::NmPerAngstrom;
double epsilon = fabs(epsilons[atom%RESSIZE])*OpenMM::KJPerKcal;
sig.push_back(0.5*sigma);
eps.push_back(2.0*sqrt(epsilon));
if(atom%RESSIZE == 0){
bonds.push_back(pair<int, int>(atom, atom+1));
bonds.push_back(pair<int, int>(atom, atom+2));
}
double charge = do_electrostatics ? charges[atom] : 0;
forceField->addParticle(charge, sigma, epsilon);
}
}
void test_water2_dpme_energies_forces_no_exclusions() {
const double cutoff = 7.0*OpenMM::NmPerAngstrom;
const double dalpha = 4.0124063605;
const int grid = 32;
NonbondedForce* forceField = new NonbondedForce();
vector<Vec3> positions;
vector<double> epsvals;
vector<double> sigvals;
vector<pair<int, int> > bonds;
System system;
const int NATOMS = 6;
double boxEdgeLength = 25*OpenMM::NmPerAngstrom;
make_waterbox(NATOMS, boxEdgeLength, forceField, positions, epsvals, sigvals, bonds, system, false);
forceField->setNonbondedMethod(OpenMM::NonbondedForce::LJPME);
forceField->setPMEParameters(0.0f, grid, grid, grid);
forceField->setReciprocalSpaceForceGroup(1);
forceField->setLJPMEParameters(dalpha, grid, grid, grid);
forceField->setCutoffDistance(cutoff);
forceField->setReactionFieldDielectric(1.0);
system.addForce(forceField);
// Reference calculation
VerletIntegrator integrator(0.01);
Platform& platform = Platform::getPlatformByName("Reference");
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy, false, 1<<1);
double refenergy = state.getPotentialEnergy();
const vector<Vec3>& refforces = state.getForces();
// Optimized CPU calculation
CpuCalcDispersionPmeReciprocalForceKernel pme(CalcPmeReciprocalForceKernel::Name(), platform);
IO io;
double selfEwaldEnergy = 0;
double dalpha6 = pow(dalpha, 6.0);
for (int i = 0; i < NATOMS; i++) {
io.posq.push_back((float)positions[i][0]);
io.posq.push_back((float)positions[i][1]);
io.posq.push_back((float)positions[i][2]);
double c6 = 8.0f * pow(sigvals[i], 3) * epsvals[i];
io.posq.push_back(c6);
selfEwaldEnergy += dalpha6 * c6 * c6 / 12.0;
}
pme.initialize(grid, grid, grid, NATOMS, dalpha);
Vec3 boxVectors[3];
system.getDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
pme.beginComputation(io, boxVectors, true);
double recenergy = pme.finishComputation(io);
ASSERT_EQUAL_TOL(recenergy, -2.179629087, 5e-3);
ASSERT_EQUAL_TOL(selfEwaldEnergy, 1.731404285, 1e-5);
std::vector<Vec3> knownforces(6);
knownforces[0] = Vec3( -1.890360546, -1.890723915, -1.879662698);
knownforces[1] = Vec3( -0.003161352455, -0.000922244929, -0.005391616425);
knownforces[2] = Vec3( 0.0009199035545, -0.001453894176, -0.006188087146);
knownforces[3] = Vec3( 1.887108856, 1.887241446, 1.89644647);
knownforces[4] = Vec3( 0.0008242336483, 0.003778910089, -0.002116131106);
knownforces[5] = Vec3( 0.004912763044, 0.002324059399, -0.002844482646);
for (int i = 0; i < NATOMS; i++)
ASSERT_EQUAL_VEC(refforces[i], knownforces[i], 5e-3);
recenergy += selfEwaldEnergy;
// See if they match.
ASSERT_EQUAL_TOL(refenergy, recenergy, 1e-3);
for (int i = 0; i < NATOMS; i++)
ASSERT_EQUAL_VEC(refforces[i], Vec3(io.force[4*i], io.force[4*i+1], io.force[4*i+2]), 5e-3);
}
void testPME(bool triclinic) { void testPME(bool triclinic) {
// Create a cloud of random point charges. // Create a cloud of random point charges.
...@@ -108,7 +612,7 @@ void testPME(bool triclinic) { ...@@ -108,7 +612,7 @@ void testPME(bool triclinic) {
double alpha; double alpha;
int gridx, gridy, gridz; int gridx, gridy, gridz;
NonbondedForceImpl::calcPMEParameters(system, *force, alpha, gridx, gridy, gridz); NonbondedForceImpl::calcPMEParameters(system, *force, alpha, gridx, gridy, gridz, false);
CpuCalcPmeReciprocalForceKernel pme(CalcPmeReciprocalForceKernel::Name(), platform); CpuCalcPmeReciprocalForceKernel pme(CalcPmeReciprocalForceKernel::Name(), platform);
IO io; IO io;
double sumSquaredCharges = 0; double sumSquaredCharges = 0;
...@@ -125,7 +629,7 @@ void testPME(bool triclinic) { ...@@ -125,7 +629,7 @@ void testPME(bool triclinic) {
pme.initialize(gridx, gridy, gridz, numParticles, alpha); pme.initialize(gridx, gridy, gridz, numParticles, alpha);
pme.beginComputation(io, boxVectors, true); pme.beginComputation(io, boxVectors, true);
double energy = pme.finishComputation(io); double energy = pme.finishComputation(io);
// See if they match. // See if they match.
ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), energy+ewaldSelfEnergy, 1e-3); ASSERT_EQUAL_TOL(refState.getPotentialEnergy(), energy+ewaldSelfEnergy, 1e-3);
...@@ -141,6 +645,7 @@ int main(int argc, char* argv[]) { ...@@ -141,6 +645,7 @@ int main(int argc, char* argv[]) {
} }
testPME(false); testPME(false);
testPME(true); testPME(true);
test_water2_dpme_energies_forces_no_exclusions();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -42,7 +42,7 @@ NonbondedForceProxy::NonbondedForceProxy() : SerializationProxy("NonbondedForce" ...@@ -42,7 +42,7 @@ NonbondedForceProxy::NonbondedForceProxy() : SerializationProxy("NonbondedForce"
} }
void NonbondedForceProxy::serialize(const void* object, SerializationNode& node) const { void NonbondedForceProxy::serialize(const void* object, SerializationNode& node) const {
node.setIntProperty("version", 1); node.setIntProperty("version", 2);
const NonbondedForce& force = *reinterpret_cast<const NonbondedForce*>(object); const NonbondedForce& force = *reinterpret_cast<const NonbondedForce*>(object);
node.setIntProperty("forceGroup", force.getForceGroup()); node.setIntProperty("forceGroup", force.getForceGroup());
node.setIntProperty("method", (int) force.getNonbondedMethod()); node.setIntProperty("method", (int) force.getNonbondedMethod());
...@@ -59,6 +59,11 @@ void NonbondedForceProxy::serialize(const void* object, SerializationNode& node) ...@@ -59,6 +59,11 @@ void NonbondedForceProxy::serialize(const void* object, SerializationNode& node)
node.setIntProperty("nx", nx); node.setIntProperty("nx", nx);
node.setIntProperty("ny", ny); node.setIntProperty("ny", ny);
node.setIntProperty("nz", nz); node.setIntProperty("nz", nz);
force.getLJPMEParameters(alpha, nx, ny, nz);
node.setDoubleProperty("ljAlpha", alpha);
node.setIntProperty("ljnx", nx);
node.setIntProperty("ljny", ny);
node.setIntProperty("ljnz", nz);
node.setIntProperty("recipForceGroup", force.getReciprocalSpaceForceGroup()); node.setIntProperty("recipForceGroup", force.getReciprocalSpaceForceGroup());
SerializationNode& particles = node.createChildNode("Particles"); SerializationNode& particles = node.createChildNode("Particles");
for (int i = 0; i < force.getNumParticles(); i++) { for (int i = 0; i < force.getNumParticles(); i++) {
...@@ -76,7 +81,8 @@ void NonbondedForceProxy::serialize(const void* object, SerializationNode& node) ...@@ -76,7 +81,8 @@ void NonbondedForceProxy::serialize(const void* object, SerializationNode& node)
} }
void* NonbondedForceProxy::deserialize(const SerializationNode& node) const { void* NonbondedForceProxy::deserialize(const SerializationNode& node) const {
if (node.getIntProperty("version") != 1) int version = node.getIntProperty("version");
if (version < 1 || version > 2)
throw OpenMMException("Unsupported version number"); throw OpenMMException("Unsupported version number");
NonbondedForce* force = new NonbondedForce(); NonbondedForce* force = new NonbondedForce();
try { try {
...@@ -93,6 +99,13 @@ void* NonbondedForceProxy::deserialize(const SerializationNode& node) const { ...@@ -93,6 +99,13 @@ void* NonbondedForceProxy::deserialize(const SerializationNode& node) const {
int ny = node.getIntProperty("ny", 0); int ny = node.getIntProperty("ny", 0);
int nz = node.getIntProperty("nz", 0); int nz = node.getIntProperty("nz", 0);
force->setPMEParameters(alpha, nx, ny, nz); force->setPMEParameters(alpha, nx, ny, nz);
if (version >= 2) {
alpha = node.getDoubleProperty("ljAlpha", 0.0);
nx = node.getIntProperty("ljnx", 0);
ny = node.getIntProperty("ljny", 0);
nz = node.getIntProperty("ljnz", 0);
force->setLJPMEParameters(alpha, nx, ny, nz);
}
force->setReciprocalSpaceForceGroup(node.getIntProperty("recipForceGroup", -1)); force->setReciprocalSpaceForceGroup(node.getIntProperty("recipForceGroup", -1));
const SerializationNode& particles = node.getChildNode("Particles"); const SerializationNode& particles = node.getChildNode("Particles");
for (int i = 0; i < (int) particles.getChildren().size(); i++) { for (int i = 0; i < (int) particles.getChildren().size(); i++) {
......
...@@ -53,6 +53,9 @@ void testSerialization() { ...@@ -53,6 +53,9 @@ void testSerialization() {
double alpha = 0.5; double alpha = 0.5;
int nx = 3, ny = 5, nz = 7; int nx = 3, ny = 5, nz = 7;
force.setPMEParameters(alpha, nx, ny, nz); force.setPMEParameters(alpha, nx, ny, nz);
double dalpha = 0.8;
int dnx = 4, dny = 6, dnz = 7;
force.setLJPMEParameters(dalpha, dnx, dny, dnz);
force.addParticle(1, 0.1, 0.01); force.addParticle(1, 0.1, 0.01);
force.addParticle(0.5, 0.2, 0.02); force.addParticle(0.5, 0.2, 0.02);
force.addParticle(-0.5, 0.3, 0.03); force.addParticle(-0.5, 0.3, 0.03);
...@@ -84,6 +87,13 @@ void testSerialization() { ...@@ -84,6 +87,13 @@ void testSerialization() {
ASSERT_EQUAL(nx, nx2); ASSERT_EQUAL(nx, nx2);
ASSERT_EQUAL(ny, ny2); ASSERT_EQUAL(ny, ny2);
ASSERT_EQUAL(nz, nz2); ASSERT_EQUAL(nz, nz2);
double dalpha2;
int dnx2, dny2, dnz2;
force2.getLJPMEParameters(dalpha2, dnx2, dny2, dnz2);
ASSERT_EQUAL(dalpha, dalpha2);
ASSERT_EQUAL(dnx, dnx2);
ASSERT_EQUAL(dny, dny2);
ASSERT_EQUAL(dnz, dnz2);
for (int i = 0; i < force.getNumParticles(); i++) { for (int i = 0; i < force.getNumParticles(); i++) {
double charge1, sigma1, epsilon1; double charge1, sigma1, epsilon1;
double charge2, sigma2, epsilon2; double charge2, sigma2, epsilon2;
......
/* -------------------------------------------------------------------------- *
* 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-2017 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. *
* -------------------------------------------------------------------------- */
#ifdef _MSC_VER
// Prevent Windows from defining macros that interfere with other code.
#define NOMINMAX
#endif
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/Units.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/internal/NonbondedForceImpl.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
#include <algorithm>
using namespace OpenMM;
using namespace std;
void testConvergence() {
// Create a cloud of random particles.
const int numParticles = 1000;
const double boxWidth = 6.0;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
force->addParticle(0.0, 0.1+0.3*genrand_real2(sfmt), genrand_real2(sfmt));
while (true) {
Vec3 pos = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
double minDist = boxWidth;
for (int j = 0; j < i; j++) {
Vec3 delta = pos-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
}
if (minDist > 0.15) {
positions[i] = pos;
break;
}
}
}
// Compute the energy with short and long cutoffs, and compare them to LJPME.
// The long cutoff should match the LJPME result better than the short cutoff.
force->setNonbondedMethod(NonbondedForce::LJPME);
force->setCutoffDistance(1.0);
force->setEwaldErrorTolerance(1e-5);
force->setUseDispersionCorrection(false);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
double pmeEnergy = context.getState(State::Energy, false, 1).getPotentialEnergy();
force->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
context.reinitialize();
context.setPositions(positions);
double shortEnergy = context.getState(State::Energy, false, 1).getPotentialEnergy();
force->setCutoffDistance(3.0);
context.reinitialize();
context.setPositions(positions);
double longEnergy = context.getState(State::Energy, false, 1).getPotentialEnergy();
ASSERT(fabs(longEnergy-pmeEnergy) < fabs(shortEnergy-pmeEnergy))
}
void testErrorTolerance() {
// Create a cloud of random particles.
const int numParticles = 200;
const double boxWidth = 5.0;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
force->addParticle(0.0, 0.1+0.2*genrand_real2(sfmt), genrand_real2(sfmt));
while (true) {
Vec3 pos = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
double minDist = boxWidth;
for (int j = 0; j < i; j++) {
Vec3 delta = pos-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
}
if (minDist > 0.1) {
positions[i] = pos;
break;
}
}
}
force->setNonbondedMethod(NonbondedForce::LJPME);
// For various values of the cutoff and error tolerance, see if the actual error is reasonable.
for (double cutoff = 0.8; cutoff < boxWidth/2; cutoff *= 1.3) {
force->setCutoffDistance(cutoff);
vector<Vec3> refForces;
double norm = 0.0;
for (double tol = 5e-5; tol < 1e-3; tol *= 2.0) {
force->setEwaldErrorTolerance(tol);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces);
if (refForces.size() == 0) {
refForces = state.getForces();
for (int i = 0; i < numParticles; i++)
norm += refForces[i].dot(refForces[i]);
norm = sqrt(norm);
}
else {
double diff = 0.0;
for (int i = 0; i < numParticles; i++) {
Vec3 delta = refForces[i]-state.getForces()[i];
diff += delta.dot(delta);
}
diff = sqrt(diff)/norm;
ASSERT(diff < 2*tol);
}
// See if the PME parameters were calculated correctly.
double expectedAlpha, actualAlpha;
int expectedSize[3], actualSize[3];
NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2], true);
force->getLJPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]);
ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5);
for (int i = 0; i < 3; i++) {
ASSERT(actualSize[i] >= expectedSize[i]);
ASSERT(actualSize[i] < expectedSize[i]+10);
}
}
}
}
void testPMEParameters() {
// Create a cloud of random particles.
const int numParticles = 51;
const double boxWidth = 4.7;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
force->addParticle(0.0, 0.1+0.2*genrand_real2(sfmt), genrand_real2(sfmt));
positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
}
force->setNonbondedMethod(NonbondedForce::LJPME);
force->setCutoffDistance(0.5);
// Compute the energy with an error tolerance of 0.1.
force->setEwaldErrorTolerance(0.1);
VerletIntegrator integrator1(0.01);
Context context1(system, integrator1, platform);
context1.setPositions(positions);
double energy1 = context1.getState(State::Energy).getPotentialEnergy();
double alpha;
int gridx, gridy, gridz;
force->getLJPMEParametersInContext(context1, alpha, gridx, gridy, gridz);
// Try again with an error tolerance of 1e-4.
force->setEwaldErrorTolerance(1e-4);
VerletIntegrator integrator2(0.01);
Context context2(system, integrator2, platform);
context2.setPositions(positions);
double energy2 = context2.getState(State::Energy).getPotentialEnergy();
// Now explicitly set the parameters. These should match the values that were
// used for tolerance 0.1.
force->setLJPMEParameters(alpha, gridx, gridy, gridz);
VerletIntegrator integrator3(0.01);
Context context3(system, integrator3, platform);
context3.setPositions(positions);
double energy3 = context3.getState(State::Energy).getPotentialEnergy();
ASSERT_EQUAL_TOL(energy1, energy3, 1e-5);
ASSERT(fabs((energy1-energy2)/energy1) > 1e-5);
force->getLJPMEParametersInContext(context2, alpha, gridx, gridy, gridz);
}
void testCoulombAndLJ() {
// Create a cloud of random particles.
const int numParticles = 200;
const double boxWidth = 5.0;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<double> charge(numParticles), sigma(numParticles), epsilon(numParticles);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
charge[i] = -1.0+i*2.0/(numParticles-1);
sigma[i] = 0.1+0.2*genrand_real2(sfmt);
epsilon[i] = genrand_real2(sfmt);
force->addParticle(charge[i], 1.0, 0.0);
while (true) {
Vec3 pos = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
double minDist = boxWidth;
for (int j = 0; j < i; j++) {
Vec3 delta = pos-positions[j];
minDist = std::min(minDist, sqrt(delta.dot(delta)));
}
if (minDist > 0.1) {
positions[i] = pos;
break;
}
}
}
force->setNonbondedMethod(NonbondedForce::LJPME);
// Compute forces and energy with only Coulomb interactions.
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State state1 = context.getState(State::Forces | State::Energy);
// Now repeat with only LJ interactions.
for (int i = 0; i < numParticles; i++)
force->setParticleParameters(i, 0.0, sigma[i], epsilon[i]);
context.reinitialize();
context.setPositions(positions);
State state2 = context.getState(State::Forces | State::Energy);
// Finally compute with both Coulomb and LJ.
for (int i = 0; i < numParticles; i++)
force->setParticleParameters(i, charge[i], sigma[i], epsilon[i]);
context.reinitialize();
context.setPositions(positions);
State state3 = context.getState(State::Forces | State::Energy);
// Make sure the results agree.
ASSERT_EQUAL_TOL(state1.getPotentialEnergy()+state2.getPotentialEnergy(), state3.getPotentialEnergy(), 1e-5);
for (int i = 0; i < numParticles; i++)
ASSERT_EQUAL_VEC(state1.getForces()[i]+state2.getForces()[i], state3.getForces()[i], 1e-5);
}
void make_dmfbox(int natoms, double boxEdgeLength, NonbondedForce *forceField, vector<Vec3> &positions, vector<double>& eps, vector<double>& sig,
vector<pair<int, int> >& bonds, System &system, bool do_electrostatics) {
const int RESSIZE = 12;
const double charges[RESSIZE] = {
0.08, 0.43, -0.54, -0.33, -0.09, 0.09,
0.09, 0.09, -0.09, 0.09, 0.09, 0.09
};
const double masses[RESSIZE] = {
1.008, 12.011, 15.9994, 14.007, 12.011, 1.008,
1.008, 1.008, 12.011, 1.008, 1.008, 1.008
};
const double sigmas[RESSIZE] = {
0.160361769265, 0.356359487256, 0.302905564168, 0.329632525712, 0.365268474438, 0.238760856462,
0.238760856462, 0.238760856462, 0.365268474438, 0.238760856462, 0.238760856462, 0.238760856462
};
const double epsilons[RESSIZE] = {
0.19246, 0.46024, 0.50208, 0.83680, 0.32635, 0.10042,
0.10042, 0.10042, 0.32635, 0.10042, 0.10042, 0.10042
};
positions.clear();
if (natoms == 12) {
const double coords[12][3] = {
{ 0.620, 0.945, 0.128 },
{ 0.560, 0.905, 0.045 },
{ 0.502, 0.987, -0.026 },
{ 0.556, 0.770, 0.028 },
{ 0.643, 0.685, 0.106 },
{ 0.680, 0.741, 0.193 },
{ 0.729, 0.653, 0.045 },
{ 0.587, 0.597, 0.140 },
{ 0.477, 0.708, -0.072 },
{ 0.377, 0.688, -0.032 },
{ 0.524, 0.614, -0.102 },
{ 0.468, 0.775, -0.158 }
};
for (int atom = 0; atom < natoms; ++atom)
positions.push_back(Vec3(coords[atom][0], coords[atom][1], coords[atom][2]));
}
else
throw exception();
system.setDefaultPeriodicBoxVectors(Vec3(boxEdgeLength, 0, 0),
Vec3(0, boxEdgeLength, 0),
Vec3(0, 0, boxEdgeLength));
sig.clear();
eps.clear();
bonds.clear();
for (int atom = 0; atom < natoms; ++atom) {
system.addParticle(masses[atom%RESSIZE]);
double sigma = sigmas[atom%RESSIZE];
double epsilon = epsilons[atom%RESSIZE];
sig.push_back(sigma);
eps.push_back(epsilon);
if (atom%RESSIZE == 0) {
int offset = atom-1;
bonds.push_back(pair<int, int>(offset+1, offset+ 2));
bonds.push_back(pair<int, int>(offset+2, offset+ 3));
bonds.push_back(pair<int, int>(offset+2, offset+ 4));
bonds.push_back(pair<int, int>(offset+4, offset+ 5));
bonds.push_back(pair<int, int>(offset+4, offset+ 9));
bonds.push_back(pair<int, int>(offset+5, offset+ 6));
bonds.push_back(pair<int, int>(offset+5, offset+ 7));
bonds.push_back(pair<int, int>(offset+5, offset+ 8));
bonds.push_back(pair<int, int>(offset+9, offset+10));
bonds.push_back(pair<int, int>(offset+9, offset+11));
bonds.push_back(pair<int, int>(offset+9, offset+12));
}
double charge = do_electrostatics ? charges[atom] : 0;
forceField->addParticle(charge, sigma, epsilon);
}
// Make exceptions and replacement 1-4 parameters
forceField->createExceptionsFromBonds(bonds, 1.0, 1.0);
int nres = natoms / RESSIZE;
double newqq = do_electrostatics ? charges[8]*charges[8] : 0.0;
double newsig = 0.293996576986;
double neweps = 0.144938011577;
for(int i = 0; i < forceField->getNumExceptions(); ++i){
for(int res = 0; res < nres; ++res){
int particle1, particle2;
double chargeProd, sigma, epsilon;
forceField->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon);
if((particle1 == res+2 && particle2 == res+8) ||
(particle1 == res+8 && particle2 == res+2) ||
(particle1 == res+2 && particle2 == res+4) ||
(particle1 == res+4 && particle2 == res+2))
forceField->setExceptionParameters(i, particle1, particle2, newqq, newsig, neweps);
}
}
}
void make_waterbox(int natoms, double boxEdgeLength, NonbondedForce *forceField, vector<Vec3> &positions, vector<double>& eps, vector<double>& sig,
vector<pair<int, int> >& bonds, System &system, bool do_electrostatics) {
const int RESSIZE = 3;
const double masses[RESSIZE] = { 8.0, 1.0, 1.0 };
const double charges[RESSIZE] = { -0.834, 0.417, 0.417 };
// Values from the CHARMM force field, in AKMA units
const double epsilons[RESSIZE] = { -0.1521, -0.046, -0.046 };
const double halfrmins[RESSIZE] = { 1.7682, 0.2245, 0.2245 };
positions.clear();
if (natoms == 6) {
const double coords[6][3] = {
{ 2.000000, 2.000000, 2.000000},
{ 2.500000, 2.000000, 3.000000},
{ 1.500000, 2.000000, 3.000000},
{ 0.000000, 0.000000, 0.000000},
{ 0.500000, 0.000000, 1.000000},
{ -0.500000, 0.000000, 1.000000}
};
for (int atom = 0; atom < natoms; ++atom)
positions.push_back(Vec3(coords[atom][0], coords[atom][1], coords[atom][2])*OpenMM::NmPerAngstrom);
}
else if (natoms == 375) {
const double coords[375][3] = {
{ -6.22, -6.25, -6.24 },
{ -5.32, -6.03, -6.00 },
{ -6.75, -5.56, -5.84 },
{ -3.04, -6.23, -6.19 },
{ -3.52, -5.55, -5.71 },
{ -3.59, -6.43, -6.94 },
{ 0.02, -6.23, -6.14 },
{ -0.87, -5.97, -6.37 },
{ 0.53, -6.03, -6.93 },
{ 3.10, -6.20, -6.27 },
{ 3.87, -6.35, -5.72 },
{ 2.37, -6.11, -5.64 },
{ 6.18, -6.14, -6.20 },
{ 6.46, -6.66, -5.44 },
{ 6.26, -6.74, -6.94 },
{ -6.21, -3.15, -6.24 },
{ -6.23, -3.07, -5.28 },
{ -6.02, -2.26, -6.55 },
{ -3.14, -3.07, -6.16 },
{ -3.38, -3.63, -6.90 },
{ -2.18, -3.05, -6.17 },
{ -0.00, -3.16, -6.23 },
{ -0.03, -2.30, -6.67 },
{ 0.05, -2.95, -5.29 },
{ 3.08, -3.11, -6.14 },
{ 2.65, -2.55, -6.79 },
{ 3.80, -3.53, -6.62 },
{ 6.16, -3.14, -6.16 },
{ 7.04, -3.32, -6.51 },
{ 5.95, -2.27, -6.51 },
{ -6.20, -0.04, -6.15 },
{ -5.43, 0.32, -6.59 },
{ -6.95, 0.33, -6.62 },
{ -3.10, -0.06, -6.19 },
{ -3.75, 0.42, -6.69 },
{ -2.46, 0.60, -5.93 },
{ 0.05, -0.01, -6.17 },
{ -0.10, 0.02, -7.12 },
{ -0.79, 0.16, -5.77 },
{ 3.03, 0.00, -6.19 },
{ 3.54, 0.08, -7.01 },
{ 3.69, -0.22, -5.53 },
{ 6.17, 0.05, -6.19 },
{ 5.78, -0.73, -6.57 },
{ 7.09, -0.17, -6.04 },
{ -6.20, 3.15, -6.25 },
{ -6.59, 3.18, -5.37 },
{ -5.87, 2.25, -6.33 },
{ -3.09, 3.04, -6.17 },
{ -3.88, 3.58, -6.26 },
{ -2.41, 3.54, -6.63 },
{ 0.00, 3.06, -6.26 },
{ -0.71, 3.64, -6.00 },
{ 0.65, 3.15, -5.55 },
{ 3.14, 3.06, -6.23 },
{ 3.11, 3.31, -5.30 },
{ 2.38, 3.49, -6.63 },
{ 6.19, 3.14, -6.25 },
{ 6.82, 3.25, -5.54 },
{ 5.76, 2.30, -6.07 },
{ -6.22, 6.26, -6.19 },
{ -6.22, 5.74, -7.00 },
{ -5.89, 5.67, -5.52 },
{ -3.04, 6.24, -6.20 },
{ -3.08, 5.28, -6.17 },
{ -3.96, 6.52, -6.25 },
{ -0.05, 6.21, -6.16 },
{ 0.82, 6.58, -6.06 },
{ 0.01, 5.64, -6.93 },
{ 3.10, 6.25, -6.15 },
{ 3.64, 5.47, -6.31 },
{ 2.46, 6.24, -6.87 },
{ 6.22, 6.20, -6.27 },
{ 5.37, 6.42, -5.88 },
{ 6.80, 6.07, -5.51 },
{ -6.19, -6.15, -3.13 },
{ -6.37, -7.01, -3.51 },
{ -6.25, -6.29, -2.18 },
{ -3.10, -6.27, -3.11 },
{ -2.29, -5.77, -2.99 },
{ -3.80, -5.62, -2.98 },
{ -0.03, -6.18, -3.15 },
{ -0.07, -7.05, -2.75 },
{ 0.68, -5.74, -2.70 },
{ 3.10, -6.14, -3.07 },
{ 2.35, -6.72, -3.23 },
{ 3.86, -6.65, -3.37 },
{ 6.22, -6.20, -3.16 },
{ 6.82, -6.36, -2.43 },
{ 5.35, -6.13, -2.75 },
{ -6.26, -3.13, -3.12 },
{ -6.16, -2.27, -2.70 },
{ -5.36, -3.47, -3.18 },
{ -3.11, -3.05, -3.14 },
{ -3.31, -3.96, -3.34 },
{ -2.77, -3.06, -2.24 },
{ 0.00, -3.13, -3.16 },
{ 0.48, -2.37, -2.81 },
{ -0.57, -3.40, -2.44 },
{ 3.09, -3.09, -3.16 },
{ 2.41, -3.19, -2.49 },
{ 3.91, -3.07, -2.67 },
{ 6.19, -3.04, -3.08 },
{ 5.64, -3.61, -3.61 },
{ 6.93, -3.58, -2.82 },
{ -6.18, -0.00, -3.04 },
{ -6.00, -0.59, -3.78 },
{ -6.79, 0.64, -3.39 },
{ -3.05, -0.03, -3.07 },
{ -2.95, 0.80, -3.52 },
{ -4.00, -0.20, -3.07 },
{ -0.03, 0.03, -3.06 },
{ -0.33, -0.37, -3.87 },
{ 0.89, -0.21, -2.99 },
{ 3.13, -0.05, -3.10 },
{ 3.44, 0.81, -3.34 },
{ 2.21, 0.07, -2.86 },
{ 6.20, -0.05, -3.13 },
{ 6.89, 0.60, -3.20 },
{ 5.58, 0.30, -2.49 },
{ -6.23, 3.09, -3.16 },
{ -5.62, 3.79, -2.94 },
{ -6.33, 2.60, -2.33 },
{ -3.10, 3.08, -3.04 },
{ -3.84, 3.47, -3.51 },
{ -2.40, 3.01, -3.69 },
{ 0.01, 3.04, -3.11 },
{ -0.56, 3.59, -3.64 },
{ 0.28, 3.60, -2.38 },
{ 3.04, 3.11, -3.09 },
{ 3.49, 2.30, -2.87 },
{ 3.70, 3.66, -3.51 },
{ 6.15, 3.14, -3.11 },
{ 6.52, 2.52, -3.74 },
{ 6.72, 3.06, -2.34 },
{ -6.22, 6.15, -3.13 },
{ -5.49, 6.21, -2.51 },
{ -6.56, 7.04, -3.18 },
{ -3.11, 6.24, -3.05 },
{ -3.76, 5.83, -3.62 },
{ -2.26, 5.92, -3.37 },
{ 0.03, 6.25, -3.07 },
{ 0.34, 5.63, -3.73 },
{ -0.87, 6.00, -2.91 },
{ 3.07, 6.15, -3.08 },
{ 3.29, 6.92, -2.56 },
{ 3.39, 6.35, -3.96 },
{ 6.22, 6.14, -3.12 },
{ 5.79, 6.38, -2.29 },
{ 6.25, 6.96, -3.62 },
{ -6.21, -6.20, -0.06 },
{ -5.79, -6.87, 0.48 },
{ -6.43, -5.50, 0.54 },
{ -3.16, -6.21, -0.02 },
{ -2.50, -6.87, 0.20 },
{ -2.77, -5.37, 0.23 },
{ -0.00, -6.14, -0.00 },
{ 0.68, -6.72, -0.33 },
{ -0.64, -6.73, 0.38 },
{ 3.03, -6.20, -0.01 },
{ 3.77, -6.56, -0.51 },
{ 3.43, -5.85, 0.78 },
{ 6.25, -6.16, -0.00 },
{ 5.36, -6.09, -0.36 },
{ 6.24, -6.97, 0.49 },
{ -6.24, -3.05, -0.01 },
{ -6.35, -3.64, 0.73 },
{ -5.42, -3.33, -0.42 },
{ -3.09, -3.06, 0.05 },
{ -2.44, -3.62, -0.38 },
{ -3.90, -3.21, -0.43 },
{ 0.05, -3.10, 0.02 },
{ -0.31, -2.35, -0.43 },
{ -0.63, -3.77, 0.01 },
{ 3.05, -3.09, -0.04 },
{ 3.28, -3.90, 0.41 },
{ 3.65, -2.43, 0.30 },
{ 6.20, -3.04, -0.03 },
{ 5.66, -3.31, 0.71 },
{ 6.78, -3.79, -0.19 },
{ -6.18, 0.04, -0.04 },
{ -6.73, -0.73, -0.15 },
{ -5.98, 0.06, 0.89 },
{ -3.11, -0.04, -0.04 },
{ -3.36, -0.08, 0.87 },
{ -2.70, 0.81, -0.14 },
{ -0.02, -0.02, -0.05 },
{ -0.45, 0.28, 0.75 },
{ 0.90, 0.15, 0.07 },
{ 3.04, 0.02, -0.01 },
{ 3.26, -0.82, 0.38 },
{ 3.89, 0.45, -0.13 },
{ 6.19, 0.05, -0.03 },
{ 5.52, -0.56, 0.25 },
{ 7.01, -0.29, 0.32 },
{ -6.14, 3.08, 0.00 },
{ -6.83, 2.82, 0.61 },
{ -6.59, 3.64, -0.64 },
{ -3.05, 3.09, -0.04 },
{ -3.79, 2.50, 0.09 },
{ -3.18, 3.80, 0.59 },
{ 0.02, 3.14, 0.04 },
{ -0.89, 3.04, -0.19 },
{ 0.49, 2.57, -0.57 },
{ 3.14, 3.15, 0.00 },
{ 3.28, 2.28, 0.37 },
{ 2.30, 3.08, -0.45 },
{ 6.27, 3.08, -0.00 },
{ 5.55, 2.54, -0.33 },
{ 5.83, 3.87, 0.34 },
{ -6.18, 6.15, -0.03 },
{ -6.45, 6.21, 0.88 },
{ -6.26, 7.05, -0.36 },
{ -3.06, 6.19, -0.05 },
{ -2.84, 6.64, 0.76 },
{ -3.99, 5.96, 0.03 },
{ -0.00, 6.20, 0.06 },
{ -0.67, 5.99, -0.59 },
{ 0.76, 6.46, -0.44 },
{ 3.10, 6.26, -0.03 },
{ 3.57, 6.09, 0.78 },
{ 2.57, 5.47, -0.18 },
{ 6.26, 6.18, 0.02 },
{ 5.53, 5.64, -0.29 },
{ 5.95, 7.08, -0.06 },
{ -6.26, -6.21, 3.07 },
{ -5.98, -6.38, 3.97 },
{ -5.46, -5.94, 2.62 },
{ -3.10, -6.24, 3.04 },
{ -2.69, -6.51, 3.87 },
{ -3.43, -5.35, 3.21 },
{ -0.03, -6.16, 3.06 },
{ 0.83, -6.00, 3.42 },
{ -0.30, -6.99, 3.45 },
{ 3.15, -6.25, 3.11 },
{ 2.77, -5.60, 3.72 },
{ 2.68, -6.10, 2.28 },
{ 6.20, -6.21, 3.16 },
{ 5.75, -6.73, 2.50 },
{ 6.69, -5.56, 2.66 },
{ -6.17, -3.10, 3.04 },
{ -6.82, -2.44, 3.28 },
{ -6.12, -3.69, 3.80 },
{ -3.08, -3.04, 3.11 },
{ -3.59, -3.56, 3.72 },
{ -2.97, -3.61, 2.34 },
{ 0.01, -3.04, 3.11 },
{ -0.86, -3.41, 3.20 },
{ 0.56, -3.78, 2.86 },
{ 3.07, -3.07, 3.15 },
{ 3.81, -3.68, 3.13 },
{ 2.80, -2.98, 2.23 },
{ 6.20, -3.04, 3.13 },
{ 5.48, -3.64, 2.92 },
{ 6.98, -3.49, 2.81 },
{ -6.18, -0.05, 3.12 },
{ -6.41, 0.66, 3.69 },
{ -6.33, 0.28, 2.23 },
{ -3.05, 0.03, 3.10 },
{ -3.46, -0.42, 3.83 },
{ -3.57, -0.19, 2.33 },
{ 0.03, -0.02, 3.15 },
{ 0.23, -0.08, 2.21 },
{ -0.81, 0.41, 3.18 },
{ 3.09, 0.00, 3.03 },
{ 2.48, -0.29, 3.71 },
{ 3.91, 0.16, 3.51 },
{ 6.19, -0.06, 3.11 },
{ 6.05, 0.47, 2.33 },
{ 6.59, 0.52, 3.74 },
{ -6.20, 3.05, 3.05 },
{ -6.87, 3.73, 3.17 },
{ -5.55, 3.24, 3.73 },
{ -3.11, 3.06, 3.15 },
{ -3.64, 3.74, 2.71 },
{ -2.32, 3.00, 2.62 },
{ 0.02, 3.05, 3.06 },
{ -0.87, 3.14, 3.38 },
{ 0.48, 3.82, 3.42 },
{ 3.07, 3.10, 3.16 },
{ 3.95, 3.44, 2.97 },
{ 2.76, 2.73, 2.32 },
{ 6.19, 3.07, 3.16 },
{ 7.02, 3.30, 2.72 },
{ 5.52, 3.27, 2.51 },
{ -6.19, 6.24, 3.15 },
{ -5.56, 5.88, 2.52 },
{ -7.05, 5.96, 2.83 },
{ -3.10, 6.14, 3.08 },
{ -2.34, 6.69, 3.27 },
{ -3.86, 6.69, 3.29 },
{ -0.04, 6.24, 3.13 },
{ 0.63, 6.54, 2.53 },
{ 0.08, 5.29, 3.18 },
{ 3.12, 6.24, 3.14 },
{ 3.57, 5.82, 2.40 },
{ 2.23, 5.90, 3.12 },
{ 6.25, 6.19, 3.06 },
{ 5.55, 5.59, 3.32 },
{ 6.08, 6.99, 3.55 },
{ -6.20, -6.16, 6.15 },
{ -6.29, -5.99, 7.09 },
{ -6.09, -7.11, 6.09 },
{ -3.09, -6.19, 6.27 },
{ -2.56, -5.90, 5.52 },
{ -3.80, -6.69, 5.87 },
{ 0.02, -6.25, 6.24 },
{ -0.70, -5.70, 6.51 },
{ 0.25, -5.93, 5.36 },
{ 3.11, -6.18, 6.14 },
{ 3.76, -6.54, 6.74 },
{ 2.29, -6.20, 6.64 },
{ 6.22, -6.17, 6.15 },
{ 6.61, -6.98, 6.47 },
{ 5.56, -5.94, 6.81 },
{ -6.21, -3.10, 6.14 },
{ -6.76, -2.66, 6.78 },
{ -5.51, -3.50, 6.65 },
{ -3.13, -3.05, 6.18 },
{ -2.19, -3.14, 6.34 },
{ -3.50, -3.89, 6.43 },
{ 0.01, -3.06, 6.15 },
{ -0.06, -2.81, 7.07 },
{ -0.25, -3.98, 6.13 },
{ 3.04, -3.09, 6.17 },
{ 3.84, -3.51, 5.84 },
{ 3.25, -2.85, 7.08 },
{ 6.26, -3.13, 6.19 },
{ 6.01, -2.20, 6.09 },
{ 5.47, -3.55, 6.54 },
{ -6.20, 0.01, 6.27 },
{ -5.79, -0.70, 5.78 },
{ -6.67, 0.51, 5.60 },
{ -3.13, 0.01, 6.14 },
{ -3.53, -0.35, 6.94 },
{ -2.21, 0.17, 6.39 },
{ -0.04, -0.04, 6.20 },
{ 0.26, 0.47, 5.46 },
{ 0.51, 0.22, 6.93 },
{ 3.10, -0.05, 6.23 },
{ 2.33, 0.44, 5.95 },
{ 3.85, 0.45, 5.92 },
{ 6.19, -0.01, 6.26 },
{ 7.05, 0.16, 5.88 },
{ 5.58, 0.02, 5.52 },
{ -6.22, 3.04, 6.17 },
{ -5.45, 3.57, 5.95 },
{ -6.62, 3.50, 6.92 },
{ -3.09, 3.16, 6.21 },
{ -3.71, 2.75, 5.61 },
{ -2.60, 2.43, 6.59 },
{ -0.02, 3.10, 6.26 },
{ 0.89, 3.27, 6.05 },
{ -0.44, 2.94, 5.41 },
{ 3.12, 3.04, 6.23 },
{ 2.31, 3.53, 6.43 },
{ 3.59, 3.60, 5.60 },
{ 6.23, 3.05, 6.24 },
{ 5.92, 3.91, 6.54 },
{ 6.02, 3.03, 5.30 },
{ -6.15, 6.21, 6.24 },
{ -6.27, 6.46, 5.32 },
{ -7.00, 5.85, 6.51 },
{ -3.07, 6.15, 6.22 },
{ -3.98, 6.27, 5.94 },
{ -2.66, 7.01, 6.10 },
{ 0.04, 6.20, 6.25 },
{ -0.38, 5.50, 5.75 },
{ -0.36, 7.00, 5.93 },
{ 3.12, 6.15, 6.24 },
{ 3.66, 6.88, 5.93 },
{ 2.25, 6.33, 5.86 },
{ 6.20, 6.27, 6.19 },
{ 5.46, 5.65, 6.19 },
{ 6.97, 5.73, 6.39 }
};
for (int atom = 0; atom < natoms; ++atom)
positions.push_back(Vec3(coords[atom][0], coords[atom][1], coords[atom][2])*OpenMM::NmPerAngstrom);
}
else
throw exception();
system.setDefaultPeriodicBoxVectors(Vec3(boxEdgeLength, 0, 0),
Vec3(0, boxEdgeLength, 0),
Vec3(0, 0, boxEdgeLength));
sig.clear();
eps.clear();
bonds.clear();
for (int atom = 0; atom < natoms; ++atom) {
system.addParticle(masses[atom%RESSIZE]);
double sigma = 2.0*pow(2.0, -1.0/6.0)*halfrmins[atom%RESSIZE]*OpenMM::NmPerAngstrom;
double epsilon = fabs(epsilons[atom%RESSIZE])*OpenMM::KJPerKcal;
sig.push_back(0.5*sigma);
eps.push_back(2.0*sqrt(epsilon));
if (atom%RESSIZE == 0) {
bonds.push_back(pair<int, int>(atom, atom+1));
bonds.push_back(pair<int, int>(atom, atom+2));
}
double charge = do_electrostatics ? charges[atom] : 0;
forceField->addParticle(charge, sigma, epsilon);
}
}
void testWater2DpmeEnergiesForcesNoExclusions() {
const double cutoff = 7.0*OpenMM::NmPerAngstrom;
const double alpha = 4.0124063605;
const double dalpha = 4.0124063605;
const int grid = 32;
NonbondedForce* forceField = new NonbondedForce();
vector<Vec3> positions;
vector<double> epsvals;
vector<double> sigvals;
vector<pair<int, int> > bonds;
System system;
const int numAtoms = 6;
double boxEdgeLength = 25*OpenMM::NmPerAngstrom;
make_waterbox(numAtoms, boxEdgeLength, forceField, positions, epsvals, sigvals, bonds, system, false);
forceField->setNonbondedMethod(OpenMM::NonbondedForce::LJPME);
forceField->setPMEParameters(alpha, grid, grid, grid);
forceField->setLJPMEParameters(dalpha, grid, grid, grid);
forceField->setCutoffDistance(cutoff);
forceField->setReactionFieldDielectric(1.0);
system.addForce(forceField);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
//Gromacs reference values from the following inputs
//
//------------------------------------------------
// water2.gro
//------------------------------------------------
//MD of 2 waters, t= 0.0
// 6
// 1SOL OW1 1 0.200 0.200 0.200
// 1SOL HW1 2 0.250 0.200 0.300
// 1SOL HW2 3 0.150 0.200 0.300
// 2SOL OW1 4 0.000 0.000 0.000
// 2SOL HW1 5 0.050 0.000 0.100
// 2SOL HW2 6 -0.050 0.000 0.100
// 2.50000 2.50000 2.50000
//------------------------------------------------
//
//------------------------------------------------
// water2.gro
//------------------------------------------------
//[ defaults ]
//; nbfunc comb-rule gen-pairs fudgeLJ fudgeQQ
// 1 2 no 1.0 1.0
//
//[ atomtypes ]
//; full atom descriptions are available in ffoplsaa.atp
//; name bond_type mass charge ptype sigma epsilon
//OW OW 8 15.99940 -0.834 A 3.15057e-01 6.36386e-01
//HW HW 1 1.00800 0.417 A 4.00014e-02 1.92464e-01
//
//
//#ifdef NOEXCLUDE
//
//[ moleculetype ]
//; molname nrexcl
//SOL 0
//
//#else
//
//[ moleculetype ]
//; molname nrexcl
//SOL 3
//
//#endif
//
//#ifdef NOCHARGE
//[ atoms ]
//; id at type res nr residu name at name cg nr charge
//1 OW 1 SOL OW1 1 0.000
//2 HW 1 SOL HW1 1 0.000
//3 HW 1 SOL HW2 1 0.000
//#else
//[ atoms ]
//; id at type res nr residu name at name cg nr charge
//1 OW 1 SOL OW1 1 -0.834
//2 HW 1 SOL HW1 1 0.417
//3 HW 1 SOL HW2 1 0.417
//#endif
//
//[ settles ]
//; i j funct length
//1 1 0.09572 0.15139
//
//#ifndef NOEXCLUDE
//[ exclusions ]
//1 2 3
//2 1 3
//3 1 2
//#endif
//------------------------------------------------
//
//------------------------------------------------
// water2.top
//------------------------------------------------
//#include "tip3p.tpi"
//
//[ system ]
//Water dimer
//
//[ molecules ]
//SOL 2
//------------------------------------------------
//
//------------------------------------------------
// water2.mdp
//------------------------------------------------
//define = -DNOCHARGE -DNOEXCLUDE
//;define = -DNOCHARGE
//rvdw = 0.7
//vdw-modifier = Potential-Shift
//;vdw-modifier = None
//rlist = 0.9
//rcoulomb = 0.7
//nstfout = 1
//fourierspacing = 0.08
//pme-order = 5
//ewald-rtol = 1.5E-2
//ewald-rtol-lj = 1.5E-2
//vdwtype = PME
//lj-pme-comb-rule = geometric
//continuation = yes
//------------------------------------------------
//
//run commands:-
// gmx grompp -c water2.gro -p water2.top -f water2.mdp -o run.tpr
// gmx mdrun -s run.tpr -o traj.trr -pforce 1E-16
// gmx dump -f traj.trr
double refenergy = 1.34804e+03;
vector<Vec3> refforces(6);
refforces[0] = Vec3( 3.15301e-01, -3.91114e-03, -6.68965e+04);
refforces[1] = Vec3( 1.67241e+04, -3.79846e-02, 3.34487e+04);
refforces[2] = Vec3(-1.67243e+04, -9.55931e-02, 3.34486e+04);
refforces[3] = Vec3(-1.71643e+00, -1.76696e+00, -6.68993e+04);
refforces[4] = Vec3( 1.67254e+04, 1.59080e+00, 3.34495e+04);
refforces[5] = Vec3(-1.67239e+04, 3.13897e-01, 3.34491e+04);
State state = context.getState(State::Forces | State::Energy);
double energy = state.getPotentialEnergy();
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_TOL(refenergy, energy, 1E-4);
for (int n = 0; n < numAtoms; ++n)
ASSERT_EQUAL_VEC(refforces[n], forces[n], 1E-4);
}
void testDMFDpmeEnergiesForcesWithExclusions() {
const double cutoff = 7.0*OpenMM::NmPerAngstrom;
const double alpha = 4.0124063605;
const double dalpha = 4.0124063605;
const int grid = 32;
NonbondedForce* forceField = new NonbondedForce();
vector<Vec3> positions;
vector<double> epsvals;
vector<double> sigvals;
vector<pair<int, int> > bonds;
System system;
const int numAtoms = 12;
double boxEdgeLength = 20*OpenMM::NmPerAngstrom;
make_dmfbox(numAtoms, boxEdgeLength, forceField, positions, epsvals, sigvals, bonds, system, false);
forceField->setNonbondedMethod(OpenMM::NonbondedForce::LJPME);
forceField->setPMEParameters(alpha, grid, grid, grid);
forceField->setLJPMEParameters(dalpha, grid, grid, grid);
forceField->setCutoffDistance(cutoff);
forceField->setUseSwitchingFunction(false);
forceField->setUseDispersionCorrection(false);
forceField->setReactionFieldDielectric(1.0);
system.addForce(forceField);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
double refenergy = 1.29545e+01;
vector<Vec3> refforces(12);
//Gromacs reference values from the following inputs
//------------------------------------------------
// dmf.mdp
//------------------------------------------------
//rvdw = 0.7
//vdw-modifier = Potential-Shift
//rlist = 0.9
//rcoulomb = 0.7
//nstfout = 1
//fourierspacing = 0.0625
//pme-order = 5
//ewald-rtol = 1.5E-2
//ewald-rtol-lj = 1.5E-2
//vdwtype = PME
//lj-pme-comb-rule = geometric
//continuation = yes
//------------------------------------------------
// dmf.gro
//------------------------------------------------
//Guyana Rwanda Oman Macau Angola Cameroon Senegal
// 12
// 101DMF HA 1 0.620 0.945 0.128
// 101DMF C 2 0.560 0.905 0.045
// 101DMF O 3 0.502 0.987 -0.026
// 101DMF N 4 0.556 0.770 0.028
// 101DMF CC 5 0.643 0.685 0.106
// 101DMF HC1 6 0.680 0.741 0.193
// 101DMF HC2 7 0.729 0.653 0.045
// 101DMF HC3 8 0.587 0.597 0.140
// 101DMF CT 9 0.477 0.708 -0.072
// 101DMF HT1 10 0.377 0.688 -0.032
// 101DMF HT2 11 0.524 0.614 -0.102
// 101DMF HT3 12 0.468 0.775 -0.158
// 2.00000 2.00000 2.00000
//------------------------------------------------
// dmf.top
//------------------------------------------------
//[ defaults ]
//; nbfunc comb-rule gen-pairs fudgeLJ fudgeQQ
//1 2 yes 1.0 1.0
//
//[ atomtypes ]
//HGR52 1 1.008000 0.000 A 0.160361769265 0.19246
//CG2O1 6 12.011000 0.000 A 0.356359487256 0.46024
//OG2D1 8 15.999400 0.000 A 0.302905564168 0.50208
//NG2S0 7 14.007000 0.000 A 0.329632525712 0.83680
//CG331 6 12.011000 0.000 A 0.365268474438 0.32635
// HGA3 1 1.008000 0.000 A 0.238760856462 0.10042
//
//[ pairtypes ]
//OG2D1 CG331 1 0.293996576986 0.144938011577
//
//[ bondtypes ]
//; i j func b0 kb
// CG2O1 HGR52 1 0.11000000 0.0000000000
// CG2O1 OG2D1 1 0.12300000 0.0000000000
// CG2O1 NG2S0 1 0.13500000 0.0000000000
// CG331 NG2S0 1 0.14340000 0.0000000000
// CG331 HGA3 1 0.11110000 0.0000000000
//
//[ angletypes ]
//; i j k func theta0 ktheta ub0 kub
// HGA3 CG331 HGA3 5 108.400000 0.0000000000000 0.18020000 0.0000000
// NG2S0 CG331 HGA3 5 105.000000 0.0000000000000 0.00000000 0.0000000
// CG331 NG2S0 CG331 5 121.000000 0.0000000000000 0.00000000 0.0000000
// CG2O1 NG2S0 CG331 5 119.500000 0.0000000000000 0.00000000 0.0000000
// NG2S0 CG2O1 OG2D1 5 124.000000 0.0000000000000 0.00000000 0.0000000
// NG2S0 CG2O1 HGR52 5 115.000000 0.0000000000000 0.00000000 0.0000000
// OG2D1 CG2O1 HGR52 5 122.000000 0.0000000000000 0.00000000 0.0000000
//
//[ dihedraltypes ]
//; i j k l func phi0 kphi mult
// OG2D1 CG2O1 NG2S0 CG331 9 180.000000 0.00000000 2
// HGR52 CG2O1 NG2S0 CG331 9 180.000000 0.00000000 2
// HGA3 CG331 NG2S0 CG331 9 0.000000 0.00000000 3
// HGA3 CG331 NG2S0 CG2O1 9 0.000000 0.00000000 3
//
//[ dihedraltypes ]
//; 'improper' dihedrals
//; i j k l func phi0 kphi
// CG2O1 NG2S0 OG2D1 HGR52 2 0.000000 0.0000000
//
//[ moleculetype ]
//; Name nrexcl
//DMF 3
//
//[ atoms ]
//; nr type resnr residue atom cgnr charge mass typeB chargeB massB
//; residue 101 DMF rtp DMF q 0.0
// 1 HGR52 101 DMF HA 1 0.00 1.008 ; qtot 0.00
// 2 CG2O1 101 DMF C 2 0.00 12.011 ; qtot 0.00
// 3 OG2D1 101 DMF O 3 0.00 15.9994 ; qtot 0.00
// 4 NG2S0 101 DMF N 4 0.00 14.007 ; qtot 0.00
// 5 CG331 101 DMF CC 5 0.00 12.011 ; qtot 0.00
// 6 HGA3 101 DMF HC1 6 0.00 1.008 ; qtot 0.00
// 7 HGA3 101 DMF HC2 7 0.00 1.008 ; qtot 0.00
// 8 HGA3 101 DMF HC3 8 0.00 1.008 ; qtot 0.00
// 9 CG331 101 DMF CT 9 0.00 12.011 ; qtot 0.00
// 10 HGA3 101 DMF HT1 10 0.00 1.008 ; qtot 0.00
// 11 HGA3 101 DMF HT2 11 0.00 1.008 ; qtot 0.00
// 12 HGA3 101 DMF HT3 12 0.00 1.008 ; qtot 0
//
//[ bonds ]
//; ai aj funct c0 c1 c2 c3
// 1 2 1
// 2 3 1
// 2 4 1
// 4 5 1
// 4 9 1
// 5 6 1
// 5 7 1
// 5 8 1
// 9 10 1
// 9 11 1
// 9 12 1
//
//[ pairs ]
//; ai aj funct c0 c1 c2 c3
// 1 5 1
// 1 9 1
// 2 6 1
// 2 7 1
// 2 8 1
// 2 10 1
// 2 11 1
// 2 12 1
// 3 5 1
// 3 9 1
// 5 10 1
// 5 11 1
// 5 12 1
// 6 9 1
// 7 9 1
// 8 9 1
//
//[ angles ]
//; ai aj ak funct c0 c1 c2 c3
// 1 2 3 5
// 1 2 4 5
// 3 2 4 5
// 2 4 5 5
// 2 4 9 5
// 5 4 9 5
// 4 5 6 5
// 4 5 7 5
// 4 5 8 5
// 6 5 7 5
// 6 5 8 5
// 7 5 8 5
// 4 9 10 5
// 4 9 11 5
// 4 9 12 5
// 10 9 11 5
// 10 9 12 5
// 11 9 12 5
//
//[ dihedrals ]
//; ai aj ak al funct c0 c1 c2 c3 c4 c5
// 1 2 4 5 9
// 1 2 4 9 9
// 3 2 4 5 9
// 3 2 4 9 9
// 2 4 5 6 9
// 2 4 5 7 9
// 2 4 5 8 9
// 9 4 5 6 9
// 9 4 5 7 9
// 9 4 5 8 9
// 2 4 9 10 9
// 2 4 9 11 9
// 2 4 9 12 9
// 5 4 9 10 9
// 5 4 9 11 9
// 5 4 9 12 9
//
//[ dihedrals ]
//; ai aj ak al funct c0 c1 c2 c3
// 1 3 4 2 2
//
//[ system ]
//; Name
//DMF Monomer
//
//[ molecules ]
//; Compound #mols
//DMF 1
//
//
//run commands:-
//gmx_d grompp -c dmf.gro -p dmf.top -f dmf.mdp -o run.tpr
//gmx_d mdrun -s run.tpr -o traj.trr -pforce 1E-16 -debug
//gmx_d dump -f traj.trr
// Gromacs reference values. See inputs above.
refforces[ 0] = Vec3(-3.19942e+00, 2.19766e+01, 2.72861e-01);
refforces[ 1] = Vec3(-5.22879e+01, 2.82006e+02, -6.86534e+00);
refforces[ 2] = Vec3( 1.23583e+01, 7.31235e+01, 4.08375e+01);
refforces[ 3] = Vec3(-1.28656e-03, 1.14097e-03, 4.07527e-04);
refforces[ 4] = Vec3( 1.51942e+02, 5.65684e+01, 2.41818e+02);
refforces[ 5] = Vec3( 1.20290e+02, -1.65176e+02, 1.48309e+02);
refforces[ 6] = Vec3( 4.57022e+01, -1.65198e+01, 1.88824e+01);
refforces[ 7] = Vec3( 5.57228e+01, -5.68770e+01, 1.09979e+02);
refforces[ 8] = Vec3(-9.58422e+01, 4.41982e+01, -1.27887e+02);
refforces[ 9] = Vec3(-2.59754e+01, -1.42402e+01, -1.23475e+01);
refforces[10] = Vec3(-1.37259e+02, -7.97690e+01, -2.39814e+02);
refforces[11] = Vec3(-7.14520e+01, -1.45287e+02, -1.73189e+02);
State state = context.getState(State::Forces | State::Energy);
double energy = state.getPotentialEnergy();
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_TOL(refenergy, energy, 1E-4);
for (int n = 0; n < numAtoms; ++n)
// The forces on atom 3 are much smaller in magnitude to the others,
// which causes problems for testing in single precision
if(n != 3)
ASSERT_EQUAL_VEC(refforces[n], forces[n], 5E-4);
}
void testWater2DpmeEnergiesForcesWithExclusions() {
const double cutoff = 7.0*OpenMM::NmPerAngstrom;
const double alpha = 4.0124063605;
const double dalpha = 4.0124063605;
const int grid = 32;
NonbondedForce* forceField = new NonbondedForce();
vector<Vec3> positions;
vector<double> epsvals;
vector<double> sigvals;
vector<pair<int, int> > bonds;
System system;
const int numAtoms = 6;
double boxEdgeLength = 25*OpenMM::NmPerAngstrom;
make_waterbox(numAtoms, boxEdgeLength, forceField, positions, epsvals, sigvals, bonds, system, false);
forceField->setNonbondedMethod(OpenMM::NonbondedForce::LJPME);
forceField->createExceptionsFromBonds(bonds, 1.0, 1.0);
forceField->setPMEParameters(alpha, grid, grid, grid);
forceField->setLJPMEParameters(dalpha, grid, grid, grid);
forceField->setCutoffDistance(cutoff);
forceField->setUseSwitchingFunction(false);
forceField->setUseDispersionCorrection(false);
forceField->setReactionFieldDielectric(1.0);
system.addForce(forceField);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
double refenergy = -7.78060e-01;
vector<Vec3> refforces(6);
// Gromacs reference values. See comments in testWater2DpmeEnergiesForcesNoExclusions() for details.
refforces[0] = Vec3( 3.15301e-01, -3.91114e-03, 9.48373e-01);
refforces[1] = Vec3(-4.74745e-02, -3.79846e-02, -5.69616e-02);
refforces[2] = Vec3(-7.16866e-02, -9.55931e-02, -1.43348e-01);
refforces[3] = Vec3(-1.78136e+00, -1.76696e+00, -1.70022e+00);
refforces[4] = Vec3( 1.19309e+00, 1.59080e+00, 7.95443e-01);
refforces[5] = Vec3( 3.92366e-01, 3.13897e-01, 1.56962e-01);
State state = context.getState(State::Forces | State::Energy);
double energy = state.getPotentialEnergy();
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_TOL(refenergy, energy, 1E-4);
for (int n = 0; n < numAtoms; ++n)
ASSERT_EQUAL_VEC(refforces[n], forces[n], 5E-4);
}
void testWater125DpmeVsLongCutoffNoExclusions() {
const double cutoff = 8.5*OpenMM::NmPerAngstrom;
const double alpha = 0.45*OpenMM::AngstromsPerNm;
const double dalpha = 0.45*OpenMM::AngstromsPerNm;
const int grid = 32;
NonbondedForce* forceField = new NonbondedForce();
vector<Vec3> positions;
vector<double> epsvals;
vector<double> sigvals;
vector<pair<int, int> > bonds;
System system;
const int numAtoms = 375;
double boxEdgeLength = 17.01*OpenMM::NmPerAngstrom;
make_waterbox(numAtoms, boxEdgeLength, forceField, positions, epsvals, sigvals, bonds, system, false);
forceField->setNonbondedMethod(OpenMM::NonbondedForce::LJPME);
forceField->setPMEParameters(alpha, grid, grid, grid);
forceField->setLJPMEParameters(dalpha, grid, grid, grid);
forceField->setCutoffDistance(cutoff);
forceField->setReactionFieldDielectric(1.0);
system.addForce(forceField);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
double energy = state.getPotentialEnergy();
//Gromacs reference values. See comments in testWater2DpmeEnergiesForcesNoExclusions() for details.
//Coordinates are from make_waterbox, and the .gro file looks like
//
//;define = -DNOCHARGE -DNOEXCLUDE
//define = -DNOCHARGE
//vdw-modifier = Potential-Shift
//rvdw = 1.15
//rlist = 1.15
//rcoulomb = 1.15
//fourierspacing = 0.04
//nstfout = 1
//pme-order = 5
//ewald-rtol = 1E-8
//ewald-rtol-lj = 1E-8
//vdwtype = PME
//lj-pme-comb-rule = geometric
//continuation = yes
double gromacs_energy = 5.63157e+05;
const vector<Vec3>& forces = state.getForces();
vector<Vec3> refforces(numAtoms);
refforces[ 0] = Vec3(-1.12446e+05, -2.71952e+05, -1.91471e+05);
refforces[ 1] = Vec3( 2.70479e+05, 6.61172e+04, 7.21277e+04);
refforces[ 2] = Vec3(-1.58058e+05, 2.05779e+05, 1.19292e+05);
refforces[ 3] = Vec3( 3.16438e+05, -1.27994e+05, 1.08811e+05);
refforces[ 4] = Vec3(-1.36520e+05, 1.93405e+05, 1.36521e+05);
refforces[ 5] = Vec3(-1.79957e+05, -6.54374e+04, -2.45393e+05);
refforces[ 6] = Vec3( 1.30626e+05, -1.36728e+05, 2.93833e+05);
refforces[ 7] = Vec3(-2.74564e+05, 8.02095e+04, -7.09524e+04);
refforces[ 8] = Vec3( 1.43952e+05, 5.64523e+04, -2.22980e+05);
refforces[ 9] = Vec3(-4.22852e+04, 2.14660e+04, -3.23254e+05);
refforces[ 10] = Vec3( 2.28059e+05, -4.44251e+04, 1.62898e+05);
refforces[ 11] = Vec3(-1.85776e+05, 2.29044e+04, 1.60326e+05);
refforces[ 12] = Vec3(-1.02075e+05, 3.27346e+05, 1.47993e+04);
refforces[ 13] = Vec3( 7.77195e+04, -1.44336e+05, 2.10959e+05);
refforces[ 14] = Vec3( 2.44142e+04, -1.83111e+05, -2.25837e+05);
refforces[ 15] = Vec3(-4.81843e+04, -2.72889e+05, -1.75068e+05);
refforces[ 16] = Vec3(-5.46666e+03, 2.18711e+04, 2.62456e+05);
refforces[ 17] = Vec3( 5.35890e+04, 2.51021e+05, -8.74311e+04);
refforces[ 18] = Vec3(-2.04721e+05, 1.58918e+05, 2.20448e+05);
refforces[ 19] = Vec3(-7.05932e+04, -1.64717e+05, -2.17659e+05);
refforces[ 20] = Vec3( 2.75339e+05, 5.73611e+03, -2.86718e+03);
refforces[ 21] = Vec3(-5.65480e+03, -2.81809e+05, -1.38358e+05);
refforces[ 22] = Vec3(-7.85576e+03, 2.25204e+05, -1.15217e+05);
refforces[ 23] = Vec3( 1.34846e+04, 5.66345e+04, 2.53512e+05);
refforces[ 24] = Vec3(-7.73167e+04, -4.43114e+04, 3.22354e+05);
refforces[ 25] = Vec3(-1.24372e+05, 1.61973e+05, -1.88001e+05);
refforces[ 26] = Vec3( 2.01689e+05, -1.17651e+05, -1.34455e+05);
refforces[ 27] = Vec3(-1.79300e+05, -1.97922e+05, 1.94294e+05);
refforces[ 28] = Vec3( 2.38945e+05, -4.88761e+04, -9.50350e+04);
refforces[ 29] = Vec3(-5.95911e+04, 2.46878e+05, -9.93159e+04);
refforces[ 30] = Vec3(-1.31892e+04, -2.15675e+05, 2.68757e+05);
refforces[ 31] = Vec3( 2.31232e+05, 1.08107e+05, -1.32129e+05);
refforces[ 32] = Vec3(-2.18089e+05, 1.07592e+05, -1.36669e+05);
refforces[ 33] = Vec3( 1.90632e+04, -3.62889e+05, 8.61608e+04);
refforces[ 34] = Vec3(-2.16178e+05, 1.59639e+05, -1.66288e+05);
refforces[ 35] = Vec3( 1.97134e+05, 2.03295e+05, 8.00862e+04);
refforces[ 36] = Vec3( 3.40071e+05, -6.87734e+04, 1.22584e+05);
refforces[ 37] = Vec3(-4.17943e+04, 8.35901e+03, -2.64693e+05);
refforces[ 38] = Vec3(-2.98358e+05, 6.03813e+04, 1.42075e+05);
refforces[ 39] = Vec3(-3.21693e+05, 4.40885e+04, 1.41154e+04);
refforces[ 40] = Vec3( 1.28817e+05, 2.02067e+04, -2.07114e+05);
refforces[ 41] = Vec3( 1.92948e+05, -6.43160e+04, 1.92949e+05);
refforces[ 42] = Vec3(-1.46001e+05, 3.20840e+05, 7.97305e+04);
refforces[ 43] = Vec3(-1.27705e+05, -2.55411e+05, -1.24428e+05);
refforces[ 44] = Vec3( 2.73737e+05, -6.54594e+04, 4.46323e+04);
refforces[ 45] = Vec3( 1.50212e+04, 2.43629e+05, -2.20084e+05);
refforces[ 46] = Vec3(-1.07432e+05, 8.26408e+03, 2.42419e+05);
refforces[ 47] = Vec3( 9.23685e+04, -2.51915e+05, -2.23909e+04);
refforces[ 48] = Vec3( 3.14327e+04, -2.94199e+05, 1.55484e+05);
refforces[ 49] = Vec3(-2.23665e+05, 1.52883e+05, -2.54793e+04);
refforces[ 50] = Vec3( 1.92227e+05, 1.41342e+05, -1.30033e+05);
refforces[ 51] = Vec3( 5.73542e+04, -2.08689e+05, -2.68170e+05);
refforces[ 52] = Vec3(-2.26784e+05, 1.85259e+05, 8.30474e+04);
refforces[ 53] = Vec3( 1.69446e+05, 2.34613e+04, 1.85087e+05);
refforces[ 54] = Vec3( 2.25490e+05, -1.91311e+05, -1.40103e+05);
refforces[ 55] = Vec3(-8.20802e+03, 6.83988e+04, 2.54448e+05);
refforces[ 56] = Vec3(-2.17315e+05, 1.22953e+05, -1.14373e+05);
refforces[ 57] = Vec3(-7.09510e+04, 2.05639e+05, -2.69540e+05);
refforces[ 58] = Vec3( 1.93603e+05, 3.38041e+04, 2.18192e+05);
refforces[ 59] = Vec3(-1.22579e+05, -2.39458e+05, 5.13124e+04);
refforces[ 60] = Vec3(-1.07250e+05, 3.35982e+05, 6.89600e+03);
refforces[ 61] = Vec3( 6.90672e-01, -1.44228e+05, -2.24659e+05);
refforces[ 62] = Vec3( 1.07222e+05, -1.91701e+05, 2.17695e+05);
refforces[ 63] = Vec3( 2.64846e+05, 1.94002e+05, 5.27262e+03);
refforces[ 64] = Vec3(-1.12985e+04, -2.71176e+05, 8.47510e+03);
refforces[ 65] = Vec3(-2.53630e+05, 7.71894e+04, -1.37831e+04);
refforces[ 66] = Vec3(-3.04551e+05, 4.21918e+04, 1.88948e+05);
refforces[ 67] = Vec3( 2.87326e+05, 1.22193e+05, 3.30263e+04);
refforces[ 68] = Vec3( 1.73006e+04, -1.64358e+05, -2.22023e+05);
refforces[ 69] = Vec3( 2.45556e+04, 2.20596e+05, 2.41913e+05);
refforces[ 70] = Vec3( 1.50804e+05, -2.17829e+05, -4.46813e+04);
refforces[ 71] = Vec3(-1.75369e+05, -2.74087e+03, -1.97287e+05);
refforces[ 72] = Vec3( 8.65787e+04, -2.77188e+04, -3.15014e+05);
refforces[ 73] = Vec3(-2.42127e+05, 6.26659e+04, 1.11092e+05);
refforces[ 74] = Vec3( 1.55591e+05, -3.48752e+04, 2.03883e+05);
refforces[ 75] = Vec3( 7.06224e+04, 2.96642e+05, -1.51267e+05);
refforces[ 76] = Vec3(-5.39280e+04, -2.57657e+05, -1.13850e+05);
refforces[ 77] = Vec3(-1.67422e+04, -3.90659e+04, 2.65102e+05);
refforces[ 78] = Vec3(-4.52577e+04, -3.21552e+05, -7.01075e+04);
refforces[ 79] = Vec3( 2.35182e+05, 1.45173e+05, 3.48411e+04);
refforces[ 80] = Vec3(-1.89931e+05, 1.76363e+05, 3.52722e+04);
refforces[ 81] = Vec3(-2.29347e+05, 1.06977e+05, -2.70703e+05);
refforces[ 82] = Vec3(-1.17929e+04, -2.56493e+05, 1.17929e+05);
refforces[ 83] = Vec3( 2.41161e+05, 1.49452e+05, 1.52847e+05);
refforces[ 84] = Vec3( 2.32633e+03, 3.03443e+05, 1.27473e+05);
refforces[ 85] = Vec3(-2.11215e+05, -1.63335e+05, -4.50583e+04);
refforces[ 86] = Vec3( 2.08887e+05, -1.40170e+05, -8.24544e+04);
refforces[ 87] = Vec3( 5.83172e+04, 2.82133e+04, -3.26001e+05);
refforces[ 88] = Vec3( 1.76890e+05, -4.71698e+04, 2.15220e+05);
refforces[ 89] = Vec3(-2.35168e+05, 1.89225e+04, 1.10825e+05);
refforces[ 90] = Vec3(-2.72444e+05, -1.46998e+05, -1.00637e+05);
refforces[ 91] = Vec3( 2.78426e+04, 2.39442e+05, 1.16936e+05);
refforces[ 92] = Vec3( 2.44570e+05, -9.23920e+04, -1.63042e+04);
refforces[ 93] = Vec3(-3.10100e+04, 2.93390e+05, -1.87196e+05);
refforces[ 94] = Vec3(-6.38830e+04, -2.90671e+05, -6.38833e+04);
refforces[ 95] = Vec3( 9.48775e+04, -2.79002e+03, 2.51149e+05);
refforces[ 96] = Vec3( 4.18753e+04, -1.23438e+05, -3.10188e+05);
refforces[ 97] = Vec3( 1.29157e+05, 2.04500e+05, 9.41770e+04);
refforces[ 98] = Vec3(-1.71038e+05, -8.10180e+04, 2.16049e+05);
refforces[ 99] = Vec3(-5.61490e+04, 2.26993e+04, -3.44090e+05);
refforces[100] = Vec3(-1.96230e+05, -2.88572e+04, 1.93344e+05);
refforces[101] = Vec3( 2.52383e+05, 6.15570e+03, 1.50813e+05);
refforces[102] = Vec3(-6.33126e+04, 3.55941e+05, 8.51300e+04);
refforces[103] = Vec3(-1.75405e+05, -1.81783e+05, -1.69027e+05);
refforces[104] = Vec3( 2.38759e+05, -1.74232e+05, 8.38891e+04);
refforces[105] = Vec3( 1.51480e+05, -4.90606e+04, 3.17956e+05);
refforces[106] = Vec3( 4.93229e+04, -1.61668e+05, -2.02771e+05);
refforces[107] = Vec3(-2.00831e+05, 2.10712e+05, -1.15233e+05);
refforces[108] = Vec3( 2.20204e+05, -2.33820e+05, 1.51386e+05);
refforces[109] = Vec3( 3.36498e+04, 2.79296e+05, -1.51424e+05);
refforces[110] = Vec3(-2.53896e+05, -4.54334e+04, 2.10242e-01);
refforces[111] = Vec3(-1.94665e+05, 2.05890e+05, 2.40510e+05);
refforces[112] = Vec3(-9.73233e+04, -1.29764e+05, -2.62775e+05);
refforces[113] = Vec3( 2.92049e+05, -7.61856e+04, 2.22208e+04);
refforces[114] = Vec3( 1.60261e+05, -3.43716e+05, 1.52456e+04);
refforces[115] = Vec3( 1.11151e+05, 3.08358e+05, -8.60527e+04);
refforces[116] = Vec3(-2.71443e+05, 3.54056e+04, 7.08103e+04);
refforces[117] = Vec3(-4.27331e+04, -3.19871e+05, -1.68415e+05);
refforces[118] = Vec3( 2.28408e+05, 2.15171e+05, -2.31720e+04);
refforces[119] = Vec3(-1.85616e+05, 1.04782e+05, 1.91602e+05);
refforces[120] = Vec3(-1.66057e+05, -9.58191e+04, -2.78448e+05);
refforces[121] = Vec3( 1.91258e+05, 2.19476e+05, 6.89779e+04);
refforces[122] = Vec3(-2.52379e+04, -1.23674e+05, 2.09489e+05);
refforces[123] = Vec3( 6.55172e+03, -9.23173e+04, 3.29554e+05);
refforces[124] = Vec3(-2.14685e+05, 1.13143e+05, -1.36353e+05);
refforces[125] = Vec3( 2.08124e+05, -2.08124e+04, -1.93257e+05);
refforces[126] = Vec3( 1.02696e+05, -3.39299e+05, -4.47114e+04);
refforces[127] = Vec3(-1.81786e+05, 1.75407e+05, -1.69029e+05);
refforces[128] = Vec3( 7.90534e+04, 1.63962e+05, 2.13738e+05);
refforces[129] = Vec3(-3.45588e+05, 9.36838e+04, 5.67939e+04);
refforces[130] = Vec3( 1.44967e+05, -2.60943e+05, 7.08730e+04);
refforces[131] = Vec3( 2.00649e+05, 1.67207e+05, -1.27685e+05);
refforces[132] = Vec3(-2.70181e+05, 2.05707e+05, -3.11852e+04);
refforces[133] = Vec3( 1.09331e+05, -1.83207e+05, -1.86162e+05);
refforces[134] = Vec3( 1.60883e+05, -2.25804e+04, 2.17340e+05);
refforces[135] = Vec3(-1.04496e+05, -2.97000e+05, -1.63733e+05);
refforces[136] = Vec3( 2.11303e+05, 1.73661e+04, 1.79462e+05);
refforces[137] = Vec3(-1.06849e+05, 2.79694e+05, -1.57134e+04);
refforces[138] = Vec3(-3.82271e+04, 2.11942e+05, 2.60118e+05);
refforces[139] = Vec3(-1.96098e+05, -1.23692e+05, -1.71962e+05);
refforces[140] = Vec3( 2.34334e+05, -8.82195e+04, -8.82188e+04);
refforces[141] = Vec3( 2.17634e+05, 2.72527e+05, 1.42967e+05);
refforces[142] = Vec3( 9.30924e+04, -1.86185e+05, -1.98197e+05);
refforces[143] = Vec3(-3.10770e+05, -8.63246e+04, 5.52480e+04);
refforces[144] = Vec3(-1.63880e+05, -2.98869e+05, 1.01299e+05);
refforces[145] = Vec3( 6.83424e+04, 2.39196e+05, 1.61538e+05);
refforces[146] = Vec3( 9.55787e+04, 5.97354e+04, -2.62846e+05);
refforces[147] = Vec3( 1.06430e+05, -2.97083e+05, -7.97261e+04);
refforces[148] = Vec3(-1.14920e+05, 6.41394e+04, 2.21823e+05);
refforces[149] = Vec3( 8.52531e+03, 2.33043e+05, -1.42101e+05);
refforces[150] = Vec3(-4.96390e+04, -4.12076e+04, -3.67834e+05);
refforces[151] = Vec3( 1.25352e+05, -1.99962e+05, 1.61166e+05);
refforces[152] = Vec3(-7.57841e+04, 2.41138e+05, 2.06689e+05);
refforces[153] = Vec3(-3.06397e+05, -5.15222e+04, -1.37080e+05);
refforces[154] = Vec3( 1.92949e+05, -1.92945e+05, 6.43163e+04);
refforces[155] = Vec3( 1.13490e+05, 2.44443e+05, 7.27504e+04);
refforces[156] = Vec3(-3.74471e+03, 3.83223e+05, -2.14754e+04);
refforces[157] = Vec3( 2.17881e+05, -1.85835e+05, -1.05735e+05);
refforces[158] = Vec3(-2.14191e+05, -1.97454e+05, 1.27176e+05);
refforces[159] = Vec3(-3.33357e+05, -1.38307e+04, -1.17320e+05);
refforces[160] = Vec3( 2.04157e+05, -9.93173e+04, -1.37945e+05);
refforces[161] = Vec3( 1.29262e+05, 1.13105e+05, 2.55294e+05);
refforces[162] = Vec3( 2.50185e+05, 2.64217e+05, -7.18219e+04);
refforces[163] = Vec3(-2.46668e+05, 1.94013e+04, -9.97745e+04);
refforces[164] = Vec3(-3.50266e+03, -2.83658e+05, 1.71598e+05);
refforces[165] = Vec3(-2.05824e+05, 2.71177e+05, -1.16442e+05);
refforces[166] = Vec3(-3.52163e+04, -1.88897e+05, 2.36923e+05);
refforces[167] = Vec3( 2.41012e+05, -8.22954e+04, -1.20505e+05);
refforces[168] = Vec3( 6.89329e+04, 2.09489e+05, 2.76583e+05);
refforces[169] = Vec3( 1.87999e+05, -1.61968e+05, -1.24368e+05);
refforces[170] = Vec3(-2.56932e+05, -4.75793e+04, -1.52255e+05);
refforces[171] = Vec3( 3.39431e+05, -5.75509e+04, 1.62795e+05);
refforces[172] = Vec3(-1.27767e+05, 2.66184e+05, -1.59709e+05);
refforces[173] = Vec3(-2.11726e+05, -2.08613e+05, -3.11349e+03);
refforces[174] = Vec3(-2.58601e+05, 4.61975e+04, -2.46016e+05);
refforces[175] = Vec3( 7.15587e+04, -2.52015e+05, 1.40007e+05);
refforces[176] = Vec3( 1.87109e+05, 2.05820e+05, 1.06028e+05);
refforces[177] = Vec3( 3.92176e+03, 2.94819e+05, -1.84065e+05);
refforces[178] = Vec3(-1.67230e+05, -8.36141e+04, 2.29167e+05);
refforces[179] = Vec3( 1.63334e+05, -2.11213e+05, -4.50586e+04);
refforces[180] = Vec3( 1.11151e+05, 2.40551e+05, -2.68210e+05);
refforces[181] = Vec3(-1.76495e+05, -2.47099e+05, -3.53002e+04);
refforces[182] = Vec3( 6.52872e+04, 6.52855e+03, 3.03586e+05);
refforces[183] = Vec3(-4.84049e+04, -2.73305e+05, -2.95224e+05);
refforces[184] = Vec3(-9.04206e+04, -1.44672e+04, 3.29135e+05);
refforces[185] = Vec3( 1.38830e+05, 2.87820e+05, -3.38610e+04);
refforces[186] = Vec3(-2.09072e+05, -1.53610e+05, -2.86654e+05);
refforces[187] = Vec3(-1.30322e+05, 9.09223e+04, 2.42461e+05);
refforces[188] = Vec3( 3.39380e+05, 6.27113e+04, 4.42669e+04);
refforces[189] = Vec3(-3.15692e+05, 1.48900e+05, -9.20420e+04);
refforces[190] = Vec3( 7.13687e+04, -2.72503e+05, 1.26518e+05);
refforces[191] = Vec3( 2.44351e+05, 1.23612e+05, -3.44964e+04);
refforces[192] = Vec3(-2.80727e+04, 3.15077e+05, -2.05427e+05);
refforces[193] = Vec3(-2.29004e+05, -2.08496e+05, 9.57028e+04);
refforces[194] = Vec3( 2.57096e+05, -1.06603e+05, 1.09738e+05);
refforces[195] = Vec3( 3.33213e+05, -7.80040e+04, -5.04749e+03);
refforces[196] = Vec3(-2.07680e+05, -7.82574e+04, 1.83605e+05);
refforces[197] = Vec3(-1.25574e+05, 1.56274e+05, -1.78599e+05);
refforces[198] = Vec3( 2.66795e+05, -2.82879e+04, -2.26620e+05);
refforces[199] = Vec3(-2.28291e+05, -1.82015e+05, 4.01046e+04);
refforces[200] = Vec3(-3.85027e+04, 2.10288e+05, 1.86592e+05);
refforces[201] = Vec3( 1.93076e+05, 2.05300e+05, 2.64591e+05);
refforces[202] = Vec3(-3.32259e+05, -3.65117e+04, -8.39768e+04);
refforces[203] = Vec3( 1.39204e+05, -1.68822e+05, -1.80669e+05);
refforces[204] = Vec3( 2.15422e+05, 2.88264e+05, 2.49786e+04);
refforces[205] = Vec3( 4.29235e+04, -2.66744e+05, 1.13441e+05);
refforces[206] = Vec3(-2.58339e+05, -2.15280e+04, -1.38395e+05);
refforces[207] = Vec3( 3.27580e+05, -4.93781e+04, 7.43625e+03);
refforces[208] = Vec3(-2.11622e+05, -1.58716e+05, -9.69925e+04);
refforces[209] = Vec3(-1.15917e+05, 2.08125e+05, 8.95715e+04);
refforces[210] = Vec3( 1.10967e+05, -2.71544e+05, -2.06279e+05);
refforces[211] = Vec3(-8.86155e+04, 1.96918e+04, 2.98676e+05);
refforces[212] = Vec3(-2.23913e+04, 2.51912e+05, -9.23690e+04);
refforces[213] = Vec3( 1.91611e+05, -7.99998e+04, -2.83463e+05);
refforces[214] = Vec3( 7.08725e+04, 1.44963e+05, 2.60941e+05);
refforces[215] = Vec3(-2.62503e+05, -6.49202e+04, 2.25808e+04);
refforces[216] = Vec3(-6.63168e+04, -2.84265e+04, 3.72700e+05);
refforces[217] = Vec3(-2.02131e+05, -6.33547e+04, -1.96097e+05);
refforces[218] = Vec3( 2.68466e+05, 9.18414e+04, -1.76621e+05);
refforces[219] = Vec3(-6.80052e+03, 2.72744e+05, -2.21849e+05);
refforces[220] = Vec3( 1.52709e+05, -5.52356e+04, 2.63181e+05);
refforces[221] = Vec3(-1.45890e+05, -2.17461e+05, -4.12893e+04);
refforces[222] = Vec3( 3.07522e+05, -1.21146e+05, 1.14593e+05);
refforces[223] = Vec3(-2.11787e+05, -1.56664e+05, -8.99363e+04);
refforces[224] = Vec3(-9.57076e+04, 2.77857e+05, -2.46987e+04);
refforces[225] = Vec3(-3.24882e+05, -3.09840e+04, -1.31947e+05);
refforces[226] = Vec3( 8.33124e+04, -5.05809e+04, 2.67793e+05);
refforces[227] = Vec3( 2.41536e+05, 8.15185e+04, -1.35863e+05);
refforces[228] = Vec3(-2.16561e+04, -1.67607e+05, -2.70252e+05);
refforces[229] = Vec3( 1.10825e+05, -7.29802e+04, 2.24354e+05);
refforces[230] = Vec3(-8.91995e+04, 2.40572e+05, 4.59512e+04);
refforces[231] = Vec3(-2.22246e+05, 1.96766e+05, -2.46638e+05);
refforces[232] = Vec3( 3.04748e+05, 5.66971e+04, 1.27568e+05);
refforces[233] = Vec3(-8.24632e+04, -2.53495e+05, 1.19113e+05);
refforces[234] = Vec3( 2.20621e+05, -2.03896e+05, 6.63128e+04);
refforces[235] = Vec3(-9.59082e+04, 1.64055e+05, 1.53960e+05);
refforces[236] = Vec3(-1.24758e+05, 3.98170e+04, -2.20320e+05);
refforces[237] = Vec3(-7.79583e+03, -3.49688e+04, 3.64330e+05);
refforces[238] = Vec3(-1.43293e+05, -1.65580e+05, -2.10163e+05);
refforces[239] = Vec3( 1.51159e+05, 2.00522e+05, -1.54247e+05);
refforces[240] = Vec3( 1.82058e+05, -3.72909e+04, -2.80373e+05);
refforces[241] = Vec3(-1.95792e+05, 1.98809e+05, 7.22936e+04);
refforces[242] = Vec3( 1.36910e+04, -1.61546e+05, 2.08094e+05);
refforces[243] = Vec3( 1.40288e+05, 3.27379e+05, 4.78569e+03);
refforces[244] = Vec3(-1.70016e+05, -1.73349e+05, 2.03353e+05);
refforces[245] = Vec3( 2.97331e+04, -1.54072e+05, -2.08134e+05);
refforces[246] = Vec3( 1.21932e+05, 3.52267e+05, 4.69291e+04);
refforces[247] = Vec3(-2.91621e+05, -1.24021e+05, 3.01674e+04);
refforces[248] = Vec3( 1.69673e+05, -2.28288e+05, -7.71238e+04);
refforces[249] = Vec3(-1.41105e+05, 1.52818e+05, 2.59197e+05);
refforces[250] = Vec3( 2.15511e+05, -1.77650e+05, -5.82442e+03);
refforces[251] = Vec3(-7.43779e+04, 2.47926e+04, -2.53438e+05);
refforces[252] = Vec3(-3.34214e+04, 3.09554e+05, 1.58194e+05);
refforces[253] = Vec3(-2.05877e+05, -1.71563e+05, -6.00467e+04);
refforces[254] = Vec3( 2.39329e+05, -1.38076e+05, -9.81875e+04);
refforces[255] = Vec3( 1.32793e+05, -3.72271e+05, 2.88491e+04);
refforces[256] = Vec3(-9.02633e+04, 2.78646e+05, 2.23700e+05);
refforces[257] = Vec3(-4.25632e+04, 9.36427e+04, -2.52553e+05);
refforces[258] = Vec3( 2.97252e+05, 2.17294e+05, -2.50945e+03);
refforces[259] = Vec3(-1.35724e+05, -1.48966e+05, 2.41658e+05);
refforces[260] = Vec3(-1.61536e+05, -6.83423e+04, -2.39199e+05);
refforces[261] = Vec3( 2.50550e+05, -1.39926e+05, 2.48375e+05);
refforces[262] = Vec3( 5.51783e+04, -1.65530e+04, -2.59341e+05);
refforces[263] = Vec3(-3.05734e+05, 1.56505e+05, 1.09189e+04);
refforces[264] = Vec3(-4.44616e+04, 4.17040e+04, -3.31507e+05);
refforces[265] = Vec3(-1.79702e+05, -8.54319e+04, 2.00323e+05);
refforces[266] = Vec3( 2.24182e+05, 4.37421e+04, 1.31227e+05);
refforces[267] = Vec3(-9.89367e+04, -3.76136e+05, 2.17157e+04);
refforces[268] = Vec3(-4.44424e+04, 1.68244e+05, -2.47606e+05);
refforces[269] = Vec3( 1.43421e+05, 2.07965e+05, 2.25893e+05);
refforces[270] = Vec3(-1.09030e+03, -2.44686e+05, -2.30145e+05);
refforces[271] = Vec3(-1.86963e+05, 1.89757e+05, 3.34863e+04);
refforces[272] = Vec3( 1.88003e+05, 5.49541e+04, 1.96680e+05);
refforces[273] = Vec3(-1.15452e+05, -1.55243e+05, 2.81412e+05);
refforces[274] = Vec3(-1.35893e+05, 1.74355e+05, -1.12817e+05);
refforces[275] = Vec3( 2.51361e+05, -1.90905e+04, -1.68633e+05);
refforces[276] = Vec3( 1.76202e+05, -2.31601e+05, -2.00886e+05);
refforces[277] = Vec3(-2.96697e+05, 3.00025e+04, 1.06676e+05);
refforces[278] = Vec3( 1.20457e+05, 2.01635e+05, 9.42700e+04);
refforces[279] = Vec3(-1.66320e+05, -9.08355e+02, 2.65478e+05);
refforces[280] = Vec3( 2.44823e+05, 9.45895e+04, -5.28589e+04);
refforces[281] = Vec3(-7.84765e+04, -9.36654e+04, -2.12648e+05);
refforces[282] = Vec3(-6.58002e+03, -1.21918e+05, 3.16459e+05);
refforces[283] = Vec3( 2.15225e+05, 5.96416e+04, -1.14097e+05);
refforces[284] = Vec3(-2.08615e+05, 6.22725e+04, -2.02387e+05);
refforces[285] = Vec3( 7.09186e+04, 1.83619e+05, 2.71862e+05);
refforces[286] = Vec3( 1.78911e+05, -1.02234e+05, -1.78910e+05);
refforces[287] = Vec3(-2.49882e+05, -8.13582e+04, -9.29803e+04);
refforces[288] = Vec3(-1.35529e+04, -3.20226e+05, -1.16293e+05);
refforces[289] = Vec3( 2.28053e+05, 1.65034e+05, 5.70125e+04);
refforces[290] = Vec3(-2.14515e+05, 1.55237e+05, 5.92732e+04);
refforces[291] = Vec3(-2.65006e+05, 1.75233e+05, 1.91268e+05);
refforces[292] = Vec3( 2.29905e+05, 1.02940e+05, -2.05886e+05);
refforces[293] = Vec3( 3.51345e+04, -2.78156e+05, 1.46393e+04);
refforces[294] = Vec3( 1.59458e+05, 2.25128e+05, 2.11611e+05);
refforces[295] = Vec3( 1.24813e+05, -1.16492e+05, -2.05249e+05);
refforces[296] = Vec3(-2.84281e+05, -1.08601e+05, -6.38824e+03);
refforces[297] = Vec3( 2.61767e+05, -7.55993e+04, -2.32576e+05);
refforces[298] = Vec3(-2.07803e+05, -1.78116e+05, 7.71831e+04);
refforces[299] = Vec3(-5.39242e+04, 2.53755e+05, 1.55427e+05);
refforces[300] = Vec3(-6.44117e+03, 2.31328e+05, -2.54922e+05);
refforces[301] = Vec3(-2.61097e+04, 4.93208e+04, 2.72709e+05);
refforces[302] = Vec3( 3.25053e+04, -2.80718e+05, -1.77304e+04);
refforces[303] = Vec3( 7.06280e+04, 7.26140e+04, 3.28446e+05);
refforces[304] = Vec3( 1.45890e+05, 7.98271e+04, -2.06449e+05);
refforces[305] = Vec3(-2.16516e+05, -1.52473e+05, -1.21980e+05);
refforces[306] = Vec3( 1.94879e+05, -2.83084e+05, 1.41824e+05);
refforces[307] = Vec3(-2.57149e+05, 1.96432e+05, 9.64284e+04);
refforces[308] = Vec3( 6.22633e+04, 8.66280e+04, -2.38228e+05);
refforces[309] = Vec3( 3.26456e+04, 1.17141e+05, -3.28374e+05);
refforces[310] = Vec3( 2.01298e+05, -1.11486e+05, 1.85810e+05);
refforces[311] = Vec3(-2.33937e+05, -5.70482e+03, 1.42641e+05);
refforces[312] = Vec3( 6.42964e+04, 1.88719e+05, -2.86572e+05);
refforces[313] = Vec3( 1.22184e+05, -2.53768e+05, 1.00254e+05);
refforces[314] = Vec3(-1.86433e+05, 6.49694e+04, 1.86429e+05);
refforces[315] = Vec3(-4.12317e+04, -1.73607e+04, -3.68620e+05);
refforces[316] = Vec3(-1.78981e+05, 1.43186e+05, 2.08269e+05);
refforces[317] = Vec3( 2.20155e+05, -1.25802e+05, 1.60395e+05);
refforces[318] = Vec3(-1.58613e+05, 3.01594e+05, -1.29345e+05);
refforces[319] = Vec3( 2.79698e+05, -2.67790e+04, 4.76063e+04);
refforces[320] = Vec3(-1.21063e+05, -2.74847e+05, 8.17976e+04);
refforces[321] = Vec3( 1.00451e+05, 2.03427e+05, -2.75044e+05);
refforces[322] = Vec3(-2.13956e+04, 7.64144e+04, 2.81199e+05);
refforces[323] = Vec3(-7.91039e+04, -2.79910e+05, -6.08590e+03);
refforces[324] = Vec3(-2.80664e+05, 5.26142e+04, -1.53706e+05);
refforces[325] = Vec3( 2.23923e+05, -1.17559e+05, -9.23685e+04);
refforces[326] = Vec3( 5.68062e+04, 6.49218e+04, 2.46158e+05);
refforces[327] = Vec3( 2.88911e+05, -1.17893e+05, -7.40828e+04);
refforces[328] = Vec3(-6.38612e+04, 2.37565e+05, -2.55450e+04);
refforces[329] = Vec3(-2.25033e+05, -1.19637e+05, 9.96952e+04);
refforces[330] = Vec3( 1.03510e+04, 7.35559e+04, 3.47129e+05);
refforces[331] = Vec3( 1.26778e+05, -2.19542e+05, -1.51515e+05);
refforces[332] = Vec3(-1.37190e+05, 1.45950e+05, -1.95573e+05);
refforces[333] = Vec3(-1.31816e+05, 5.57951e+04, -2.81935e+05);
refforces[334] = Vec3(-1.08367e+05, -9.75306e+04, 2.16731e+05);
refforces[335] = Vec3( 2.40191e+05, 4.17715e+04, 6.52667e+04);
refforces[336] = Vec3(-2.86680e+05, -2.63007e+05, 1.37964e+04);
refforces[337] = Vec3( 1.03914e+05, 1.76653e+05, -2.56324e+05);
refforces[338] = Vec3( 1.82779e+05, 8.64040e+04, 2.42594e+05);
refforces[339] = Vec3( 1.09800e+03, -3.11636e+05, 1.85833e+05);
refforces[340] = Vec3(-2.39750e+05, 1.52568e+05, -8.71817e+04);
refforces[341] = Vec3( 2.38635e+05, 1.59089e+05, -9.86351e+04);
refforces[342] = Vec3(-8.76706e+04, -6.10520e+04, 3.31680e+05);
refforces[343] = Vec3( 2.64692e+05, 5.23233e+04, -1.16959e+05);
refforces[344] = Vec3(-1.76973e+05, 8.70353e+03, -2.14689e+05);
refforces[345] = Vec3(-1.15976e+05, -2.72303e+05, -1.33307e+05);
refforces[346] = Vec3( 2.20682e+05, 1.51896e+05, -6.30516e+04);
refforces[347] = Vec3(-1.04744e+05, 1.20457e+05, 1.96395e+05);
refforces[348] = Vec3( 4.57064e+04, 3.43550e+05, 7.23245e+04);
refforces[349] = Vec3(-1.91414e+05, -1.26580e+05, -1.85241e+05);
refforces[350] = Vec3( 1.45684e+05, -2.17040e+05, 1.12977e+05);
refforces[351] = Vec3(-1.88623e+05, -1.22936e+04, 3.10223e+05);
refforces[352] = Vec3( 3.06931e+05, 5.73380e+04, -7.08300e+04);
refforces[353] = Vec3(-1.18279e+05, -4.50586e+04, -2.39376e+05);
refforces[354] = Vec3( 8.31603e+04, -2.75958e+05, 1.16877e+05);
refforces[355] = Vec3(-2.08784e+05, 1.26300e+05, 5.15494e+04);
refforces[356] = Vec3( 1.25608e+05, 1.49661e+05, -1.68370e+05);
refforces[357] = Vec3( 1.44100e+05, -2.34453e+05, 1.73916e+05);
refforces[358] = Vec3(-8.65072e+04, 2.39988e+05, 8.37141e+04);
refforces[359] = Vec3(-5.75432e+04, -5.48037e+03, -2.57574e+05);
refforces[360] = Vec3( 2.72504e+05, 2.99781e+04, 1.85778e+05);
refforces[361] = Vec3(-3.41026e+04, 7.10483e+04, -2.61466e+05);
refforces[362] = Vec3(-2.38458e+05, -1.00996e+05, 7.57451e+04);
refforces[363] = Vec3( 1.45826e+05, -2.81284e+05, 1.15502e+05);
refforces[364] = Vec3(-2.63407e+05, 3.47332e+04, -8.10477e+04);
refforces[365] = Vec3( 1.17594e+05, 2.46657e+05, -3.44181e+04);
refforces[366] = Vec3( 2.59381e+05, -5.73297e+04, 2.56690e+05);
refforces[367] = Vec3(-1.25834e+05, -2.09725e+05, -1.49803e+05);
refforces[368] = Vec3(-1.33554e+05, 2.67105e+05, -1.06844e+05);
refforces[369] = Vec3( 7.18473e+04, -2.59021e+05, 1.89797e+05);
refforces[370] = Vec3( 1.56664e+05, 2.11783e+05, -8.99369e+04);
refforces[371] = Vec3(-2.28511e+05, 4.72761e+04, -9.98083e+04);
refforces[372] = Vec3(-1.99083e+04, 3.17042e+05, -5.62792e+04);
refforces[373] = Vec3(-1.96875e+05, -1.64948e+05, -7.96758e-01);
refforces[374] = Vec3( 2.16840e+05, -1.52072e+05, 5.63215e+04);
const double longcutoff = 30.0*OpenMM::NmPerAngstrom;
const double longcutoff2 = longcutoff*longcutoff;
const double cutoff2 = cutoff*cutoff;
const double cutoff6inv = 1.0 / (cutoff2*cutoff2*cutoff2);
const int nboxes = ceil(longcutoff/boxEdgeLength);
double refenergy = 0.0;
// Loop over home box first...
for (int i = 0; i < numAtoms; ++ i) {
for (int j = i+1; j < numAtoms; ++j) {
Vec3 dR = positions[i] - positions[j];
double R2 = dR[0]*dR[0] + dR[1]*dR[1] + dR[2]*dR[2];
double sig2 = (sigvals[i] + sigvals[j])*(sigvals[i] + sigvals[j]) / R2;
double sig6 = sig2*sig2*sig2;
double eps = epsvals[i]*epsvals[j];
refenergy += 2.0*eps*(sig6-1.0)*sig6;
if (R2 < cutoff2) {
// Add a shift term for direct space parts withing t
refenergy += 2.0*eps*(pow(sigvals[i]+sigvals[j], 6) - 64.0*pow(sigvals[i]*sigvals[j], 3))*cutoff6inv;
}
}
}
// ... and now add in the image box terms
for (int bx = -nboxes; bx <= nboxes; ++bx) {
for (int by = -nboxes; by <= nboxes; ++by) {
for (int bz = -nboxes; bz <= nboxes; ++bz) {
if (bx==0 && by==0 && bz==0) continue;
Vec3 offset(bx*boxEdgeLength, by*boxEdgeLength, bz*boxEdgeLength);
for (int i = 0; i < numAtoms; ++ i) {
for (int j = 0; j < numAtoms; ++j) {
Vec3 dR = positions[i] - positions[j] + offset;
double R2 = dR[0]*dR[0] + dR[1]*dR[1] + dR[2]*dR[2];
if (R2 > longcutoff2) continue;
double sig2 = (sigvals[i] + sigvals[j])*(sigvals[i] + sigvals[j]) / R2;
double sig6 = sig2*sig2*sig2;
double eps = epsvals[i]*epsvals[j];
refenergy += eps*(sig6-1.0)*sig6;
if (R2 < cutoff2) {
// Add a shift term for direct space parts withing teh
refenergy += eps*(pow(sigvals[i]+sigvals[j], 6) - 64.0*pow(sigvals[i]*sigvals[j], 3))*cutoff6inv;
}
}
}
}
}
}
refenergy *= 0.5;
// For this test the reference energy is 545636 kJ/mol, while the difference between DPME and 30A cutoffs
// is just 1.062 kJ/mol. The difference is due to the fact that arithmetic mean combination rules are used
// up to the cutoff, while the reciprocal space uses the geometric mean. See DOI: 10.1021/acs.jctc.5b00726
ASSERT_EQUAL_TOL(refenergy, energy, 5E-6);
ASSERT_EQUAL_TOL(gromacs_energy, energy, 5E-4);
for (int n = 0; n < numAtoms; ++n)
ASSERT_EQUAL_VEC(refforces[n], forces[n], 5E-4);
}
void testWater125DpmeVsLongCutoffWithExclusions() {
const double cutoff = 11.5*OpenMM::NmPerAngstrom;
const double alpha = 0.45*OpenMM::AngstromsPerNm;
const double dalpha = 4.2760443169;
const int grid = 60;
NonbondedForce* forceField = new NonbondedForce();
vector<Vec3> positions;
vector<double> epsvals;
vector<double> sigvals;
vector<pair<int, int> > bonds;
System system;
const int numAtoms = 375;
double boxEdgeLength = 23.01*OpenMM::NmPerAngstrom;
make_waterbox(numAtoms, boxEdgeLength, forceField, positions, epsvals, sigvals, bonds, system, false);
forceField->setNonbondedMethod(OpenMM::NonbondedForce::LJPME);
forceField->createExceptionsFromBonds(bonds, 1.0, 1.0);
forceField->setPMEParameters(alpha, grid, grid, grid);
forceField->setLJPMEParameters(dalpha, grid, grid, grid);
forceField->setCutoffDistance(cutoff);
forceField->setReactionFieldDielectric(1.0);
system.addForce(forceField);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
double energy = state.getPotentialEnergy();
const vector<Vec3>& forces = state.getForces();
// Gromacs reference values. See comments in testWater2DpmeEnergiesForcesNoExclusions() for details.
double gromacs_energy = -2.17481e+02;
vector<Vec3> refforces(numAtoms);
refforces[ 0] = Vec3(-3.10130e+01, -6.01219e+01, -5.31302e+01);
refforces[ 1] = Vec3( 4.21376e+00, 9.13811e-01, 9.61319e-01);
refforces[ 2] = Vec3( 1.42363e+00, 2.97219e+00, 1.27185e+00);
refforces[ 3] = Vec3(-3.70172e+01, -2.95228e+01, -6.27987e+01);
refforces[ 4] = Vec3(-6.57386e-01, 2.39279e+00, 1.53243e+00);
refforces[ 5] = Vec3(-1.61426e+00, 7.11728e-01, 9.99752e-01);
refforces[ 6] = Vec3( 1.60813e+01, -6.77979e+01, -1.01302e+02);
refforces[ 7] = Vec3(-4.23118e+00, 9.25550e-01, 1.28003e+00);
refforces[ 8] = Vec3( 1.81589e+00, 1.10083e+00, 1.28615e+00);
refforces[ 9] = Vec3(-2.24427e+00, -5.71071e+01, -3.18064e+01);
refforces[ 10] = Vec3( 3.41715e+00, 1.32918e+00, 1.27908e+00);
refforces[ 11] = Vec3(-3.09930e+00, 9.91868e-01, 1.69245e+00);
refforces[ 12] = Vec3( 6.08033e+01, -1.02990e+02, -8.26733e+01);
refforces[ 13] = Vec3(-1.01346e+00, 1.35475e+00, 4.13725e+00);
refforces[ 14] = Vec3(-6.71645e-01, 4.69536e-01, 4.64774e-01);
refforces[ 15] = Vec3(-6.39056e+01, -9.85756e-01, -4.97837e+01);
refforces[ 16] = Vec3( 9.97113e-01, 1.13195e-01, 4.49387e+00);
refforces[ 17] = Vec3( 9.48864e-01, 4.22217e+00, 1.56364e+00);
refforces[ 18] = Vec3( 2.18124e+01, -6.14078e+01, -8.10129e+01);
refforces[ 19] = Vec3(-5.59701e-01, -1.47528e+00, 1.40157e+00);
refforces[ 20] = Vec3( 4.29539e+00, 4.27738e-02, 1.03009e+00);
refforces[ 21] = Vec3(-2.62377e+01, 2.55532e+01, -6.89576e+01);
refforces[ 22] = Vec3( 1.17222e-01, 3.81618e+00, 1.74502e+00);
refforces[ 23] = Vec3( 1.46448e-01, 1.06214e-01, 4.27946e+00);
refforces[ 24] = Vec3(-1.90819e+00, 9.86513e+00, -1.05364e+02);
refforces[ 25] = Vec3(-1.18537e+00, 1.75021e+00, 1.54448e+00);
refforces[ 26] = Vec3( 2.96182e+00, -9.48323e-01, 1.61299e+00);
refforces[ 27] = Vec3( 5.61257e+01, 7.69427e+01, -5.84534e+01);
refforces[ 28] = Vec3(-8.11821e-01, -7.15455e-01, 6.60049e-01);
refforces[ 29] = Vec3(-9.20901e-01, 3.76217e+00, 1.35685e+00);
refforces[ 30] = Vec3(-5.03791e+01, 2.24324e+01, -4.31606e+01);
refforces[ 31] = Vec3( 3.72530e+00, 3.48275e-01, 1.40060e+00);
refforces[ 32] = Vec3( 7.61265e-01, 8.56416e-01, 6.23359e-01);
refforces[ 33] = Vec3( 1.95683e+01, 4.16950e+01, -4.33266e+01);
refforces[ 34] = Vec3(-2.19677e+00, 1.06287e+00, 1.58260e+00);
refforces[ 35] = Vec3( 1.70923e+00, 2.09511e+00, 9.84492e-01);
refforces[ 36] = Vec3(-7.84273e+01, -3.34396e+01, -3.66486e+01);
refforces[ 37] = Vec3(-1.53567e-01, 1.74934e-01, 1.15266e+00);
refforces[ 38] = Vec3(-3.45548e+00, 1.68633e-01, 1.15923e+00);
refforces[ 39] = Vec3( 6.90725e+01, -2.09426e+01, -5.31532e+01);
refforces[ 40] = Vec3( 1.33274e+00, 3.09504e-01, 1.40065e+00);
refforces[ 41] = Vec3( 1.65828e+00, -1.96378e-01, 2.68350e+00);
refforces[ 42] = Vec3( 3.39954e+01, -2.65418e+01, -6.81184e+01);
refforces[ 43] = Vec3(-1.17491e+00, -2.88793e+00, 1.40541e+00);
refforces[ 44] = Vec3(-9.63132e-01, -3.78178e-01, 1.06756e+00);
refforces[ 45] = Vec3(-4.44610e+01, -1.81736e+01, -6.19409e+01);
refforces[ 46] = Vec3( 1.48529e+00, 8.95548e-06, 4.60732e+00);
refforces[ 47] = Vec3( 1.00451e+00, -3.88830e+00, 1.27726e+00);
refforces[ 48] = Vec3(-4.23022e+00, 2.52963e+01, -3.04756e+01);
refforces[ 49] = Vec3(-3.45228e+00, 7.61191e-01, 9.40731e-01);
refforces[ 50] = Vec3( 2.78622e+00, 8.32081e-01, 1.37588e+00);
refforces[ 51] = Vec3( 1.63360e+01, 3.02230e+01, -3.91446e+01);
refforces[ 52] = Vec3(-2.64761e+00, 1.18509e+00, 9.81393e-01);
refforces[ 53] = Vec3( 1.74883e+00, -1.51958e-01, 2.56504e+00);
refforces[ 54] = Vec3(-3.01111e+01, 4.08021e+01, -3.45058e+01);
refforces[ 55] = Vec3(-1.17129e-01, 9.74282e-02, 4.56402e+00);
refforces[ 56] = Vec3(-3.03696e+00, 4.44012e-01, 1.44269e+00);
refforces[ 57] = Vec3( 7.57956e+01, -1.12043e+01, -3.92084e+01);
refforces[ 58] = Vec3(-1.55617e+00, 2.26444e-01, 2.88234e+00);
refforces[ 59] = Vec3(-1.37287e+00, -3.79045e+00, 8.55326e-01);
refforces[ 60] = Vec3(-2.88831e+01, 5.72484e+01, -7.17030e+01);
refforces[ 61] = Vec3( 6.88458e-01, -2.06343e+00, 1.03552e+00);
refforces[ 62] = Vec3( 6.94194e-01, -1.83673e+00, 2.90979e+00);
refforces[ 63] = Vec3(-7.87489e+01, 2.17729e+01, -3.72371e+01);
refforces[ 64] = Vec3( 1.39267e-01, -4.55150e+00, 9.53893e-01);
refforces[ 65] = Vec3(-4.27928e+00, -1.14139e+00, 9.25405e-01);
refforces[ 66] = Vec3( 7.13947e+01, 3.02722e+01, -5.16551e+01);
refforces[ 67] = Vec3( 4.07933e+00, -1.28199e+00, 9.34707e-01);
refforces[ 68] = Vec3(-7.53668e-02, -2.14888e+00, 1.27713e+00);
refforces[ 69] = Vec3(-9.36762e+00, 2.98321e+01, -5.70761e+01);
refforces[ 70] = Vec3( 1.35989e+00, -3.09988e+00, 9.89945e-01);
refforces[ 71] = Vec3(-2.20314e+00, -7.81892e-01, 1.21781e+00);
refforces[ 72] = Vec3( 4.89194e+01, 7.40749e+01, -4.22017e+01);
refforces[ 73] = Vec3(-4.25696e+00, -1.18954e+00, 1.04383e+00);
refforces[ 74] = Vec3(-1.40510e+00, -9.87719e-01, 3.30559e+00);
refforces[ 75] = Vec3(-4.95912e+01, -8.24838e+01, -1.82510e+01);
refforces[ 76] = Vec3( 7.39933e-01, 9.29483e-01, -1.09883e+00);
refforces[ 77] = Vec3( 9.70359e-01, 1.03012e+00, 4.01759e+00);
refforces[ 78] = Vec3(-7.87499e+00, -1.87981e+01, 5.77017e+00);
refforces[ 79] = Vec3( 3.82847e+00, 1.01191e+00, -7.30715e-02);
refforces[ 80] = Vec3(-2.64831e+00, 1.68402e+00, 1.06474e-01);
refforces[ 81] = Vec3( 1.81335e+01, -6.72766e+01, 7.21397e+01);
refforces[ 82] = Vec3(-1.89188e-01, 1.27803e+00, 8.45103e-01);
refforces[ 83] = Vec3( 2.47584e+00, 1.54044e+00, 6.55440e-01);
refforces[ 84] = Vec3(-1.05824e+00, -6.50833e+01, -3.88413e+01);
refforces[ 85] = Vec3(-3.21762e+00, 1.58809e+00, -1.32879e-01);
refforces[ 86] = Vec3( 3.30285e+00, 1.52154e+00, -3.56471e-01);
refforces[ 87] = Vec3( 4.41972e+01, -3.58815e+01, 4.01227e+01);
refforces[ 88] = Vec3(-1.22923e+00, 8.91826e-01, 2.84505e+00);
refforces[ 89] = Vec3(-4.31649e+00, 1.00895e+00, 4.43366e-01);
refforces[ 90] = Vec3(-3.65176e+01, 4.86616e+01, -6.44163e+00);
refforces[ 91] = Vec3( 1.03989e+00, 3.91910e+00, 7.93373e-01);
refforces[ 92] = Vec3( 4.11089e+00, -4.60733e-01, -7.78461e-02);
refforces[ 93] = Vec3(-1.58332e+01, -6.82045e+01, 6.62934e+01);
refforces[ 94] = Vec3(-7.75645e-02, -3.66897e+00, -3.55044e-01);
refforces[ 95] = Vec3( 4.08399e-01, 2.84950e-01, 3.80641e+00);
refforces[ 96] = Vec3(-5.05975e+00, 4.20346e+01, 3.49518e+01);
refforces[ 97] = Vec3( 9.82673e-01, 2.64451e+00, 4.02971e-01);
refforces[ 98] = Vec3(-1.24992e+00, -3.34479e-01, 1.95012e+00);
refforces[ 99] = Vec3( 2.31815e+00, -2.30056e+00, 6.49918e+01);
refforces[100] = Vec3(-2.16986e+00, -1.05184e-01, 1.89395e+00);
refforces[101] = Vec3( 3.51302e+00, 1.83706e-01, 7.08534e-01);
refforces[102] = Vec3( 4.46929e+01, -7.11604e+01, -6.62201e+00);
refforces[103] = Vec3(-1.87730e+00, -1.10206e+00, -1.47504e+00);
refforces[104] = Vec3(-1.41639e+00, -1.36347e+00, 6.10811e-01);
refforces[105] = Vec3(-3.12256e+01, -1.73923e+01, -4.47428e+01);
refforces[106] = Vec3( 7.92004e-01, -1.39066e+00, -2.68309e+00);
refforces[107] = Vec3( 1.54891e+00, 2.50018e+00, -6.21395e-01);
refforces[108] = Vec3(-3.83585e+01, 3.90231e+01, -3.68876e+01);
refforces[109] = Vec3( 1.86446e-01, 3.49120e+00, -4.00101e-01);
refforces[110] = Vec3(-4.05592e+00, -2.21609e-01, 2.13257e-01);
refforces[111] = Vec3( 5.70991e+01, -5.95502e+01, -4.08285e+01);
refforces[112] = Vec3(-4.25039e-01, -3.96206e-01, -3.23550e+00);
refforces[113] = Vec3( 4.14811e+00, -1.47859e-01, 1.11071e-01);
refforces[114] = Vec3(-2.74979e+01, 4.40260e+01, 3.06766e+00);
refforces[115] = Vec3( 2.22804e-01, 3.48934e+00, -1.96162e-01);
refforces[116] = Vec3(-4.21754e+00, 1.18655e-01, 3.36974e-01);
refforces[117] = Vec3( 6.32783e+01, 8.02719e+01, 1.38219e+01);
refforces[118] = Vec3(-1.49058e+00, 1.87045e+00, -1.32164e-01);
refforces[119] = Vec3(-2.30776e+00, 1.73240e-01, 1.92445e+00);
refforces[120] = Vec3(-4.04272e+01, -1.77143e+01, 1.57461e+01);
refforces[121] = Vec3( 1.82378e+00, 2.60376e+00, 2.33866e-01);
refforces[122] = Vec3( 1.33379e+00, -1.16675e+00, 3.34265e+00);
refforces[123] = Vec3(-8.78170e+00, 1.35313e+01, -5.40700e+01);
refforces[124] = Vec3(-2.72817e+00, 3.27413e-01, -6.95012e-01);
refforces[125] = Vec3( 2.41935e+00, -2.66049e-01, -1.62940e+00);
refforces[126] = Vec3(-3.63273e+01, 6.91610e+01, -3.72663e+00);
refforces[127] = Vec3(-1.40546e+00, 7.48503e-01, -9.73230e-01);
refforces[128] = Vec3( 5.39530e-01, 8.56302e-01, 2.57617e+00);
refforces[129] = Vec3( 2.54426e+01, -5.04169e+01, -1.76229e+01);
refforces[130] = Vec3( 6.82595e-01, -3.17362e+00, 2.20610e-01);
refforces[131] = Vec3( 1.94539e+00, 1.53325e+00, -4.24624e-01);
refforces[132] = Vec3( 3.61678e+01, -7.89030e+01, -9.61808e+00);
refforces[133] = Vec3(-1.29295e+00, -1.55223e+00, -1.88241e+00);
refforces[134] = Vec3(-1.51438e+00, 3.14594e-02, 3.60043e+00);
refforces[135] = Vec3(-4.60860e+01, 6.18971e+01, 1.38188e+01);
refforces[136] = Vec3( 3.07506e+00, -9.60659e-01, 1.81485e+00);
refforces[137] = Vec3( 6.46515e-01, -7.30203e-01, -2.17471e-01);
refforces[138] = Vec3( 7.76539e+00, 3.18751e+01, -6.18739e+01);
refforces[139] = Vec3(-2.12790e+00, -1.06577e+00, -1.03098e+00);
refforces[140] = Vec3( 3.70469e+00, -7.70591e-01, -2.00619e-01);
refforces[141] = Vec3(-4.02748e+01, 1.93804e+01, 1.92911e+01);
refforces[142] = Vec3( 5.74429e-01, -1.58840e+00, -2.07083e+00);
refforces[143] = Vec3(-4.21689e+00, -7.25280e-01, 1.61839e-01);
refforces[144] = Vec3( 4.10890e+01, 6.50772e+01, -6.64661e+00);
refforces[145] = Vec3( 2.02022e-01, -1.46124e+00, 1.99785e+00);
refforces[146] = Vec3( 1.91733e-01, -1.14906e+00, -4.18291e+00);
refforces[147] = Vec3( 3.77785e+01, 1.01191e+02, -6.07436e+00);
refforces[148] = Vec3(-1.03030e+00, -1.26650e+00, 3.57188e+00);
refforces[149] = Vec3(-7.42295e-01, -1.05437e+00, -1.47491e+00);
refforces[150] = Vec3(-7.40150e+01, -3.53477e+01, 1.81946e+01);
refforces[151] = Vec3( 1.65267e+00, 1.39873e+00, 1.46780e+00);
refforces[152] = Vec3( 1.18632e+00, 2.66165e+00, 1.61236e+00);
refforces[153] = Vec3( 3.89536e+01, -2.96071e+01, -1.38610e+01);
refforces[154] = Vec3( 2.05061e+00, 1.54050e+00, 5.35476e-01);
refforces[155] = Vec3( 4.98336e-01, 3.85036e+00, 4.21301e-01);
refforces[156] = Vec3(-5.53456e+01, -6.87157e+01, -3.55693e+01);
refforces[157] = Vec3( 3.17070e+00, 1.65800e+00, -3.99476e-01);
refforces[158] = Vec3(-2.02395e+00, 1.48143e+00, 1.00879e+00);
refforces[159] = Vec3( 5.94087e+01, -4.57694e+01, 2.77585e+01);
refforces[160] = Vec3( 2.05570e+00, 1.46552e+00, -1.41447e+00);
refforces[161] = Vec3( 2.97741e-01, 9.12876e-01, 3.27902e+00);
refforces[162] = Vec3( 1.93442e+01, -4.16391e+01, 3.34803e-01);
refforces[163] = Vec3(-3.93865e+00, 8.46322e-01, -4.47285e-01);
refforces[164] = Vec3(-7.34898e-01, 9.82679e-01, 1.44017e+00);
refforces[165] = Vec3(-3.34824e+01, -1.38834e+01, -2.62952e+01);
refforces[166] = Vec3( 1.26693e+00, -1.10171e+00, 3.22806e+00);
refforces[167] = Vec3( 3.49758e+00, -1.84534e-01, -4.62412e-01);
refforces[168] = Vec3( 1.82122e+00, -5.69776e+01, -3.86605e+01);
refforces[169] = Vec3( 1.92404e+00, -1.05303e+00, -4.52186e-01);
refforces[170] = Vec3(-3.25172e+00, 9.44050e-02, -5.87318e-01);
refforces[171] = Vec3(-5.98475e+01, 1.85708e+01, -2.67060e+01);
refforces[172] = Vec3(-3.77230e-01, 3.29609e+00, -4.81590e-01);
refforces[173] = Vec3(-1.66002e+00, -2.41098e+00, 1.03425e-01);
refforces[174] = Vec3( 6.47852e+01, 4.38661e+00, 1.77482e+01);
refforces[175] = Vec3(-1.29162e-01, -3.40031e+00, 3.91521e-01);
refforces[176] = Vec3( 1.28253e+00, 2.14633e+00, 2.64792e-01);
refforces[177] = Vec3( 2.95010e+01, -5.60376e+00, 4.16733e+01);
refforces[178] = Vec3(-1.43378e+00, -1.96178e-01, 2.40594e+00);
refforces[179] = Vec3(-1.56255e+00, -3.08967e+00, -3.14335e-01);
refforces[180] = Vec3(-6.02384e+01, -1.59585e+01, 7.16798e+01);
refforces[181] = Vec3( 1.68669e+00, -3.54228e+00, -2.98122e-01);
refforces[182] = Vec3( 9.46412e-01, -8.03852e-02, 4.17305e+00);
refforces[183] = Vec3( 3.87313e+00, 4.46632e+01, 4.59130e+01);
refforces[184] = Vec3(-9.83299e-02, -8.11669e-02, 4.04515e+00);
refforces[185] = Vec3( 6.64172e-01, 3.66814e+00, -2.58278e-01);
refforces[186] = Vec3(-1.65450e+01, 2.35336e+01, 7.09485e+01);
refforces[187] = Vec3(-6.98821e-01, 2.45516e-01, 2.69560e+00);
refforces[188] = Vec3( 4.04145e+00, 5.46258e-02, -1.82210e-02);
refforces[189] = Vec3( 2.39311e+01, 1.22785e+01, -2.13260e+01);
refforces[190] = Vec3(-3.33802e-02, -3.60205e+00, 6.21747e-01);
refforces[191] = Vec3( 3.50616e+00, 6.09623e-01, -7.40284e-02);
refforces[192] = Vec3( 2.32693e+01, -1.88836e+01, 1.24193e+01);
refforces[193] = Vec3(-2.25948e+00, -1.74718e+00, 2.65705e-01);
refforces[194] = Vec3(-1.32949e+00, -8.67446e-01, 7.75386e-01);
refforces[195] = Vec3(-4.40626e+01, 1.17032e+01, -4.18284e+01);
refforces[196] = Vec3( 1.61723e+00, -6.18309e-01, 2.45312e+00);
refforces[197] = Vec3( 1.42535e+00, 1.71801e+00, -1.86477e+00);
refforces[198] = Vec3( 3.37157e+00, -1.65818e+01, 7.59773e+01);
refforces[199] = Vec3(-2.81989e+00, -1.37877e+00, -9.60015e-02);
refforces[200] = Vec3(-8.77602e-02, 2.44299e+00, 1.17362e+00);
refforces[201] = Vec3( 2.44644e+01, -3.26831e+01, -5.34506e+01);
refforces[202] = Vec3(-4.14853e+00, -9.48873e-02, -2.18126e-01);
refforces[203] = Vec3( 8.13810e-01, -1.30429e+00, -1.62539e+00);
refforces[204] = Vec3( 1.03414e+01, -4.14898e+00, 2.56841e+01);
refforces[205] = Vec3(-1.50990e-01, -3.90514e+00, 2.98649e-01);
refforces[206] = Vec3(-3.60035e+00, -7.83546e-02, -7.95300e-01);
refforces[207] = Vec3( 4.49059e+01, 2.88959e+01, 1.53626e+01);
refforces[208] = Vec3(-2.55855e+00, -1.55231e+00, -3.96734e-01);
refforces[209] = Vec3(-1.14072e+00, 3.25255e+00, 2.39860e-01);
refforces[210] = Vec3(-4.12850e+01, 6.11654e+01, 2.43179e+01);
refforces[211] = Vec3( 1.20781e+00, -8.28196e-01, 4.26212e+00);
refforces[212] = Vec3( 7.30387e-01, -9.26965e-01, -9.32605e-01);
refforces[213] = Vec3(-1.64972e+01, 4.58667e+01, 5.58154e+01);
refforces[214] = Vec3( 4.43484e-01, -1.67205e+00, 3.42164e+00);
refforces[215] = Vec3(-4.14170e+00, -9.68400e-01, -9.21231e-02);
refforces[216] = Vec3( 1.79252e+01, 6.24205e+01, -1.47777e+01);
refforces[217] = Vec3(-2.53437e+00, -9.16373e-01, -1.63636e+00);
refforces[218] = Vec3( 3.32247e+00, -1.29776e+00, -1.07427e+00);
refforces[219] = Vec3( 1.79752e+01, 5.16430e+01, 3.90249e+01);
refforces[220] = Vec3( 7.14180e-01, -1.00018e+00, 3.14118e+00);
refforces[221] = Vec3(-1.07965e+00, -3.41285e+00, -2.24161e-01);
refforces[222] = Vec3( 3.16317e+01, 4.98025e+01, -4.17518e+01);
refforces[223] = Vec3(-2.55899e+00, -1.63433e+00, -3.76149e-01);
refforces[224] = Vec3(-1.19443e+00, -1.02227e+00, -5.37349e-02);
refforces[225] = Vec3(-3.77249e+01, -4.85845e+01, -2.11073e+01);
refforces[226] = Vec3( 7.98995e-01, 1.26056e+00, 4.28442e+00);
refforces[227] = Vec3( 3.35648e+00, 9.11653e-01, -8.07025e-01);
refforces[228] = Vec3(-3.16004e+01, -2.04156e+01, 5.01542e+01);
refforces[229] = Vec3( 8.97766e-01, 1.34997e+00, 2.86585e+00);
refforces[230] = Vec3(-2.09603e-01, 4.05651e+00, -1.91043e-02);
refforces[231] = Vec3( 3.61582e+01, -3.35593e+01, 4.19940e+01);
refforces[232] = Vec3( 3.66075e+00, 7.71021e-01, 3.45598e-01);
refforces[233] = Vec3(-7.50361e-01, 1.22549e+00, 7.98677e-01);
refforces[234] = Vec3(-4.42511e+01, -2.71049e+01, -4.56576e+01);
refforces[235] = Vec3(-3.30181e-01, 1.98824e+00, 2.21005e+00);
refforces[236] = Vec3(-7.68719e-01, 9.09063e-01, -3.77633e+00);
refforces[237] = Vec3( 7.33817e+01, -3.03886e+01, -7.59758e+01);
refforces[238] = Vec3(-1.71701e+00, 1.41048e+00, -1.84182e+00);
refforces[239] = Vec3(-1.35491e+00, 2.27816e+00, -1.08799e+00);
refforces[240] = Vec3(-4.58218e+01, -2.91931e+01, 1.12369e+01);
refforces[241] = Vec3( 1.68546e+00, 2.81258e+00, 3.93755e-01);
refforces[242] = Vec3( 8.28917e-01, -1.32237e+00, 2.91182e+00);
refforces[243] = Vec3( 5.44446e+00, -3.99466e+01, 6.77923e+00);
refforces[244] = Vec3(-1.09231e+00, -5.21927e-01, 1.83581e+00);
refforces[245] = Vec3( 5.24849e-02, -7.21832e-01, -3.35896e+00);
refforces[246] = Vec3(-1.29863e+01, -3.94851e+01, -2.70347e+01);
refforces[247] = Vec3(-3.94725e+00, -2.01688e-01, 5.93703e-02);
refforces[248] = Vec3( 1.30447e+00, -2.35362e+00, -2.94278e-01);
refforces[249] = Vec3( 2.56542e+01, -3.79434e+01, -6.19782e+01);
refforces[250] = Vec3( 2.48025e+00, -1.19994e+00, 1.41640e-01);
refforces[251] = Vec3(-5.01379e-01, 2.48607e-01, -3.97535e+00);
refforces[252] = Vec3( 3.46461e+01, -8.37214e+01, -3.92225e+01);
refforces[253] = Vec3(-2.80216e+00, -1.13524e+00, 1.85582e-02);
refforces[254] = Vec3(-1.28421e+00, -9.50174e-01, -5.56828e-01);
refforces[255] = Vec3(-3.56755e+01, 1.44176e+01, -7.63345e-01);
refforces[256] = Vec3( 1.25547e+00, 2.64846e+00, 1.29226e+00);
refforces[257] = Vec3( 1.22691e+00, 5.72301e-01, -4.09853e+00);
refforces[258] = Vec3(-6.02997e+00, -1.31579e+01, -5.03304e+01);
refforces[259] = Vec3(-4.59947e-01, -8.09031e-01, 3.08383e+00);
refforces[260] = Vec3(-8.93872e-01, -3.70797e-01, -2.89773e+00);
refforces[261] = Vec3(-1.92458e+00, 2.50787e+01, -4.30937e+01);
refforces[262] = Vec3( 2.10381e-01, -1.24125e-01, -4.01554e+00);
refforces[263] = Vec3(-3.85853e+00, 6.72311e-01, 4.06873e-02);
refforces[264] = Vec3( 1.66952e+01, 1.47383e+01, 4.13458e+01);
refforces[265] = Vec3(-2.12261e+00, -5.40916e-01, 1.54532e+00);
refforces[266] = Vec3( 3.54041e+00, -4.73740e-02, 4.73489e-01);
refforces[267] = Vec3( 4.43789e+01, 6.96271e+01, 4.06335e+00);
refforces[268] = Vec3(-9.59563e-01, 9.94730e-01, -3.12464e+00);
refforces[269] = Vec3(-1.42363e+00, 1.62107e+00, 1.87365e+00);
refforces[270] = Vec3(-5.38380e+01, 2.27365e+01, 1.95666e+01);
refforces[271] = Vec3( 1.47405e+00, 2.11523e+00, 1.97777e-01);
refforces[272] = Vec3( 2.54377e+00, -4.04439e-02, 1.97927e+00);
refforces[273] = Vec3( 1.33568e+01, 1.88750e+01, -3.59233e+01);
refforces[274] = Vec3(-1.09293e+00, 2.25841e+00, -4.61222e-01);
refforces[275] = Vec3( 3.27762e+00, -1.71208e-01, -8.67824e-01);
refforces[276] = Vec3(-3.41864e+01, 3.38579e+01, 5.95219e+01);
refforces[277] = Vec3(-4.18249e+00, -8.81154e-02, 1.97498e-01);
refforces[278] = Vec3( 1.06177e+00, 2.34089e+00, 2.42037e-01);
refforces[279] = Vec3( 2.35073e+01, 1.61625e+01, -2.58858e+01);
refforces[280] = Vec3( 3.87903e+00, 1.67313e-01, -4.03473e-02);
refforces[281] = Vec3(-5.12341e-01, -5.62857e-01, -3.19237e+00);
refforces[282] = Vec3( 3.39154e+01, -5.09470e+00, -2.29146e+01);
refforces[283] = Vec3(-1.24992e+00, 5.24960e-01, -1.16022e+00);
refforces[284] = Vec3(-2.39537e+00, 1.82818e-01, -1.53421e+00);
refforces[285] = Vec3(-5.56195e+01, 2.89266e+01, -2.61137e+01);
refforces[286] = Vec3( 2.49596e+00, -1.03213e+00, -1.51258e+00);
refforces[287] = Vec3( 1.02471e+00, -1.05342e+00, -6.79809e-01);
refforces[288] = Vec3(-1.52895e+01, 4.83734e+01, -7.33233e+00);
refforces[289] = Vec3( 3.77837e+00, -1.59224e+00, 2.02675e-01);
refforces[290] = Vec3(-3.51854e+00, -1.54234e+00, 2.89348e-01);
refforces[291] = Vec3( 3.22262e+01, 2.32542e+01, 2.37269e+01);
refforces[292] = Vec3( 1.88520e+00, -1.38396e+00, -1.98750e+00);
refforces[293] = Vec3( 4.99036e-02, -4.53129e+00, -2.13859e-01);
refforces[294] = Vec3(-7.48274e+00, 3.71318e+01, -2.35667e+01);
refforces[295] = Vec3( 7.81671e-01, -1.07371e+00, -2.37009e+00);
refforces[296] = Vec3(-3.98896e+00, -9.36146e-01, 2.62843e-02);
refforces[297] = Vec3( 4.33081e+01, 4.24806e+01, 3.21190e+01);
refforces[298] = Vec3(-2.52531e+00, -1.90285e+00, 2.72091e-01);
refforces[299] = Vec3(-9.70927e-01, -1.13219e+00, 1.47351e+00);
refforces[300] = Vec3(-4.71070e+01, -7.19253e+01, 5.82986e+01);
refforces[301] = Vec3( 6.82929e-01, 1.00679e+00, -6.94522e-01);
refforces[302] = Vec3( 8.31359e-01, 7.09804e-01, -8.12652e-01);
refforces[303] = Vec3( 3.62309e+00, -3.42931e+01, 1.98231e+01);
refforces[304] = Vec3( 1.23138e+00, 8.49297e-01, -2.39283e+00);
refforces[305] = Vec3(-2.87428e+00, 1.41050e+00, -1.03948e+00);
refforces[306] = Vec3(-3.83149e+00, -2.61638e+01, 2.98550e+01);
refforces[307] = Vec3(-2.90010e+00, 1.38356e+00, -1.22906e+00);
refforces[308] = Vec3( 2.62337e-01, 9.72795e-01, -4.02660e+00);
refforces[309] = Vec3( 7.84655e+00, -5.09531e+01, 7.96762e+01);
refforces[310] = Vec3( 2.46967e+00, 9.48901e-01, -1.17317e+00);
refforces[311] = Vec3(-4.11596e+00, 7.95633e-01, -1.39335e+00);
refforces[312] = Vec3( 5.03705e+01, -8.09993e+01, 1.13172e+02);
refforces[313] = Vec3(-4.48925e-01, 4.29309e-01, -5.50572e-01);
refforces[314] = Vec3(-2.66201e+00, 1.05662e+00, -1.44247e+00);
refforces[315] = Vec3(-6.12660e+01, 2.31218e+01, 4.57287e+01);
refforces[316] = Vec3( 8.42017e-01, 1.41042e+00, -7.78795e-01);
refforces[317] = Vec3( 3.11298e+00, -8.04273e-01, -1.51273e+00);
refforces[318] = Vec3( 1.83823e+01, -2.83588e+01, 6.13597e+01);
refforces[319] = Vec3( 4.37781e+00, 8.12091e-02, -1.33992e+00);
refforces[320] = Vec3(-5.81396e-01, -3.61991e+00, -1.22489e+00);
refforces[321] = Vec3(-4.85270e+01, -6.50314e+01, 7.16441e+01);
refforces[322] = Vec3(-3.40093e-02, 9.01514e-01, -1.26573e+00);
refforces[323] = Vec3(-8.67193e-02, -3.94828e+00, -8.97127e-01);
refforces[324] = Vec3( 6.25833e+01, -2.31957e+01, 8.66089e+01);
refforces[325] = Vec3( 2.49809e+00, -7.64197e-01, -1.27775e+00);
refforces[326] = Vec3( 2.11019e-01, 7.81764e-01, -1.23664e+00);
refforces[327] = Vec3( 2.04801e+01, 3.14002e+01, 6.96727e+01);
refforces[328] = Vec3(-7.99932e-01, 4.35586e+00, -8.77957e-01);
refforces[329] = Vec3(-2.87129e+00, -1.02321e+00, -1.42702e+00);
refforces[330] = Vec3(-6.36347e+01, -3.58428e+01, 4.52682e+01);
refforces[331] = Vec3( 1.32210e+00, -2.58500e+00, -1.43327e+00);
refforces[332] = Vec3( 1.52218e+00, 1.63513e+00, -2.29784e+00);
refforces[333] = Vec3( 4.36105e+00, 3.70776e+01, 6.46133e+01);
refforces[334] = Vec3(-1.19452e+00, -1.01252e+00, -1.43172e+00);
refforces[335] = Vec3( 4.34983e+00, -6.52342e-02, -1.33662e+00);
refforces[336] = Vec3( 1.13050e+01, 4.99187e+01, 7.16119e+01);
refforces[337] = Vec3( 2.29221e-01, 6.35843e-01, -3.59259e+00);
refforces[338] = Vec3( 1.65239e+00, 4.20995e-01, -1.42878e+00);
refforces[339] = Vec3(-1.79210e+01, 1.92423e+01, 1.77516e+01);
refforces[340] = Vec3(-2.91278e+00, 9.22214e-01, -8.41281e-01);
refforces[341] = Vec3( 2.96465e+00, 1.05962e+00, -6.85280e-01);
refforces[342] = Vec3( 5.19378e+01, -2.55266e+01, 3.63518e+01);
refforces[343] = Vec3(-1.13088e+00, 4.54600e-01, -1.30862e+00);
refforces[344] = Vec3(-2.05369e+00, -9.69459e-03, -2.69351e+00);
refforces[345] = Vec3(-4.22214e+01, 4.88282e+01, 3.76741e+01);
refforces[346] = Vec3( 3.46996e+00, 9.57280e-01, -7.60128e-01);
refforces[347] = Vec3( 7.62585e-01, 1.14548e+00, -8.06697e-01);
refforces[348] = Vec3(-2.35024e+01, -6.73585e+01, 6.49050e+01);
refforces[349] = Vec3(-1.58984e+00, -6.44551e-01, -2.37758e+00);
refforces[350] = Vec3( 1.32604e+00, -2.37576e+00, -1.54939e+00);
refforces[351] = Vec3( 2.57776e+01, -1.40743e+01, 2.06580e+01);
refforces[352] = Vec3( 4.24916e+00, 6.10665e-02, -8.19360e-01);
refforces[353] = Vec3(-7.94423e-01, -1.75764e-01, -3.51414e+00);
refforces[354] = Vec3(-1.24260e+01, 6.96334e-01, 5.97705e+01);
refforces[355] = Vec3(-3.38899e+00, 9.44919e-01, -1.25780e+00);
refforces[356] = Vec3( 6.81664e-01, 1.16965e+00, -2.34256e+00);
refforces[357] = Vec3( 5.15292e+01, 5.13086e+01, 6.16724e+01);
refforces[358] = Vec3(-1.04216e+00, 3.34685e+00, -1.33787e+00);
refforces[359] = Vec3(-9.57017e-01, -1.59610e-01, -4.31963e+00);
refforces[360] = Vec3(-5.88173e+01, 3.30524e+01, 6.23031e+01);
refforces[361] = Vec3( 9.35413e-01, -1.09829e+00, -4.65202e+00);
refforces[362] = Vec3( 6.95250e-01, -1.24375e+00, -6.50832e-01);
refforces[363] = Vec3( 1.64454e+01, 1.08071e+02, 3.76968e+01);
refforces[364] = Vec3(-4.25249e+00, -1.10053e+00, -7.56357e-01);
refforces[365] = Vec3( 1.17898e+00, -1.10215e+00, -8.21366e-01);
refforces[366] = Vec3(-5.20527e+00, 5.49522e+01, 4.55303e+01);
refforces[367] = Vec3(-7.98794e-01, -2.78246e+00, -1.27815e+00);
refforces[368] = Vec3(-1.02109e+00, -1.21921e+00, -1.26706e+00);
refforces[369] = Vec3( 3.05185e+00, 3.99846e+01, 5.39902e+01);
refforces[370] = Vec3( 1.93675e+00, -1.28986e+00, -1.21655e+00);
refforces[371] = Vec3(-4.14952e+00, -1.06509e+00, -9.52154e-01);
refforces[372] = Vec3( 6.06000e+01, 2.50872e+01, 4.29623e+01);
refforces[373] = Vec3(-3.50284e+00, -1.47848e+00, -7.98049e-01);
refforces[374] = Vec3(-8.66087e-01, -1.73056e+00, -6.59554e-01);
// Find the exclusion information
vector<set<int> > exclusions(numAtoms);
for (int i = 0; i < forceField->getNumExceptions(); i++) {
int particle1, particle2;
double chargeProd, sigma, epsilon;
forceField->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon);
exclusions[particle1].insert(particle2);
exclusions[particle2].insert(particle1);
}
const double longcutoff = 35.0*OpenMM::NmPerAngstrom;
const double longcutoff2 = longcutoff*longcutoff;
const double cutoff2 = cutoff*cutoff;
const double cutoff6inv = 1.0 / (cutoff2*cutoff2*cutoff2);
const int nboxes = ceil(longcutoff/boxEdgeLength);
double refenergy = 0.0;
// Loop over home box first...
for (int i = 0; i < numAtoms; ++ i) {
for (int j = i+1; j < numAtoms; ++j) {
Vec3 dR = positions[i] - positions[j];
double R2 = dR[0]*dR[0] + dR[1]*dR[1] + dR[2]*dR[2];
double sig2 = (sigvals[i] + sigvals[j])*(sigvals[i] + sigvals[j]) / R2;
double sig6 = sig2*sig2*sig2;
double eps = epsvals[i]*epsvals[j];
refenergy += 2.0*eps*(sig6-1.0)*sig6;
if (R2 < cutoff2) {
// Add a shift term for direct space parts withing t
refenergy += 2.0*eps*(pow(sigvals[i]+sigvals[j], 6) - 64.0*pow(sigvals[i]*sigvals[j], 3))*cutoff6inv;
}
}
}
// ... back out exclusions
for (int ii = 0; ii < numAtoms; ii++) {
for (set<int>::const_iterator iter = exclusions[ii].begin(); iter != exclusions[ii].end(); ++iter) {
if (*iter > ii) {
int i = ii;
int j = *iter;
Vec3 dR = positions[i] - positions[j];
double R2 = dR[0]*dR[0] + dR[1]*dR[1] + dR[2]*dR[2];
double sig2 = (sigvals[i] + sigvals[j])*(sigvals[i] + sigvals[j]) / R2;
double sig6 = sig2*sig2*sig2;
double eps = epsvals[i]*epsvals[j];
refenergy -= 2.0*eps*(sig6-1.0)*sig6;
if (R2 < cutoff2) {
// Add a shift term for direct space parts withing t
refenergy -= 2.0*eps*(pow(sigvals[i]+sigvals[j], 6) - 64.0*pow(sigvals[i]*sigvals[j], 3))*cutoff6inv;
}
}
}
}
// ... and now add in the image box terms
for (int bx = -nboxes; bx <= nboxes; ++bx) {
for (int by = -nboxes; by <= nboxes; ++by) {
for (int bz = -nboxes; bz <= nboxes; ++bz) {
if (bx==0 && by==0 && bz==0) continue;
Vec3 offset(bx*boxEdgeLength, by*boxEdgeLength, bz*boxEdgeLength);
for (int i = 0; i < numAtoms; ++ i) {
for (int j = 0; j < numAtoms; ++j) {
Vec3 dR = positions[i] - positions[j] + offset;
double R2 = dR[0]*dR[0] + dR[1]*dR[1] + dR[2]*dR[2];
if (R2 > longcutoff2) continue;
double sig2 = (sigvals[i] + sigvals[j])*(sigvals[i] + sigvals[j]) / R2;
double sig6 = sig2*sig2*sig2;
double eps = epsvals[i]*epsvals[j];
refenergy += eps*(sig6-1.0)*sig6;
if (R2 < cutoff2) {
// Add a shift term for direct space parts withing teh
refenergy += eps*(pow(sigvals[i]+sigvals[j], 6) - 64.0*pow(sigvals[i]*sigvals[j], 3))*cutoff6inv;
}
}
}
}
}
}
refenergy *= 0.5;
// For this test the reference energy is -294.078 kJ/mol, while the difference between DPME and 30A cutoffs
// is just 0.064 kJ/mol. The difference is due to the fact that arithmetic mean combination rules are used
// up to the cutoff, while the reciprocal space uses the geometric mean. See DOI: 10.1021/acs.jctc.5b00726
ASSERT_EQUAL_TOL(refenergy, energy, 5E-4);
ASSERT_EQUAL_TOL(gromacs_energy, energy, 5E-5);
// Forces accumulated in single precision are tested to a more permissive criterion; the double
// precision platform can match to 5E-5.
for (int n = 0; n < numAtoms; ++n)
ASSERT_EQUAL_VEC(refforces[n], forces[n], 1E-4);
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testDMFDpmeEnergiesForcesWithExclusions();
testConvergence();
testErrorTolerance();
testPMEParameters();
testCoulombAndLJ();
testWater2DpmeEnergiesForcesNoExclusions();
testWater2DpmeEnergiesForcesWithExclusions();
testWater125DpmeVsLongCutoffNoExclusions();
testWater125DpmeVsLongCutoffWithExclusions();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
...@@ -365,7 +365,7 @@ void testErrorTolerance(NonbondedForce::NonbondedMethod method) { ...@@ -365,7 +365,7 @@ void testErrorTolerance(NonbondedForce::NonbondedMethod method) {
double expectedAlpha, actualAlpha; double expectedAlpha, actualAlpha;
int expectedSize[3], actualSize[3]; int expectedSize[3], actualSize[3];
NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]); NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2], false);
force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]); force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]);
ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5); ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "SimTKOpenMMRealType.h" #include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h" #include "sfmt/SFMT.h"
#include <iostream> #include <iostream>
#include <iomanip>
#include <vector> #include <vector>
using namespace OpenMM; using namespace OpenMM;
......
...@@ -40,6 +40,7 @@ CutoffNonPeriodic = forcefield.CutoffNonPeriodic ...@@ -40,6 +40,7 @@ CutoffNonPeriodic = forcefield.CutoffNonPeriodic
CutoffPeriodic = forcefield.CutoffPeriodic CutoffPeriodic = forcefield.CutoffPeriodic
Ewald = forcefield.Ewald Ewald = forcefield.Ewald
PME = forcefield.PME PME = forcefield.PME
LJPME = forcefield.LJPME
HBonds = forcefield.HBonds HBonds = forcefield.HBonds
AllBonds = forcefield.AllBonds AllBonds = forcefield.AllBonds
......
...@@ -169,7 +169,7 @@ class AmberPrmtopFile(object): ...@@ -169,7 +169,7 @@ class AmberPrmtopFile(object):
---------- ----------
nonbondedMethod : object=NoCutoff nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME. NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
nonbondedCutoff : distance=1*nanometer nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions The cutoff distance to use for nonbonded interactions
constraints : object=None constraints : object=None
...@@ -202,7 +202,7 @@ class AmberPrmtopFile(object): ...@@ -202,7 +202,7 @@ class AmberPrmtopFile(object):
added to a hydrogen is subtracted from the heavy atom to keep their added to a hydrogen is subtracted from the heavy atom to keep their
total mass the same. total mass the same.
ewaldErrorTolerance : float=0.0005 ewaldErrorTolerance : float=0.0005
The error tolerance to use if nonbondedMethod is Ewald or PME. The error tolerance to use if nonbondedMethod is Ewald, PME, or LJPME.
switchDistance : float=0*nanometers switchDistance : float=0*nanometers
The distance at which the potential energy switching function is The distance at which the potential energy switching function is
turned on for Lennard-Jones interactions. If the switchDistance is 0 turned on for Lennard-Jones interactions. If the switchDistance is 0
...@@ -222,10 +222,11 @@ class AmberPrmtopFile(object): ...@@ -222,10 +222,11 @@ class AmberPrmtopFile(object):
ff.CutoffNonPeriodic:'CutoffNonPeriodic', ff.CutoffNonPeriodic:'CutoffNonPeriodic',
ff.CutoffPeriodic:'CutoffPeriodic', ff.CutoffPeriodic:'CutoffPeriodic',
ff.Ewald:'Ewald', ff.Ewald:'Ewald',
ff.PME:'PME'} ff.PME:'PME',
ff.LJPME:'LJPME'}
if nonbondedMethod not in methodMap: if nonbondedMethod not in methodMap:
raise ValueError('Illegal value for nonbonded method') raise ValueError('Illegal value for nonbonded method')
if not self._prmtop.getIfBox() and nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME): if not self._prmtop.getIfBox() and nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME, ff.LJPME):
raise ValueError('Illegal nonbonded method for a non-periodic system') raise ValueError('Illegal nonbonded method for a non-periodic system')
constraintMap = {None:None, constraintMap = {None:None,
ff.HBonds:'h-bonds', ff.HBonds:'h-bonds',
......
...@@ -690,7 +690,7 @@ class CharmmPsfFile(object): ...@@ -690,7 +690,7 @@ class CharmmPsfFile(object):
The parameter set to use to parametrize this molecule The parameter set to use to parametrize this molecule
nonbondedMethod : object=NoCutoff nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME. NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
nonbondedCutoff : distance=1*nanometer nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions. The cutoff distance to use for nonbonded interactions.
switchDistance : distance=0*nanometer switchDistance : distance=0*nanometer
...@@ -728,7 +728,7 @@ class CharmmPsfFile(object): ...@@ -728,7 +728,7 @@ class CharmmPsfFile(object):
added to a hydrogen is subtracted from the heavy atom to keep their added to a hydrogen is subtracted from the heavy atom to keep their
total mass the same. total mass the same.
ewaldErrorTolerance : float=0.0005 ewaldErrorTolerance : float=0.0005
The error tolerance to use if the nonbonded method is Ewald or PME. The error tolerance to use if the nonbonded method is Ewald, PME, or LJPME.
flexibleConstraints : bool=True flexibleConstraints : bool=True
Are our constraints flexible or not? Are our constraints flexible or not?
verbose : bool=False verbose : bool=False
...@@ -746,10 +746,10 @@ class CharmmPsfFile(object): ...@@ -746,10 +746,10 @@ class CharmmPsfFile(object):
cutoff = cutoff.value_in_unit(u.nanometers) cutoff = cutoff.value_in_unit(u.nanometers)
if nonbondedMethod not in (ff.NoCutoff, ff.CutoffNonPeriodic, if nonbondedMethod not in (ff.NoCutoff, ff.CutoffNonPeriodic,
ff.CutoffPeriodic, ff.Ewald, ff.PME): ff.CutoffPeriodic, ff.Ewald, ff.PME, ff.LJPME):
raise ValueError('Illegal value for nonbonded method') raise ValueError('Illegal value for nonbonded method')
if not hasbox and nonbondedMethod in (ff.CutoffPeriodic, if not hasbox and nonbondedMethod in (ff.CutoffPeriodic,
ff.Ewald, ff.PME): ff.Ewald, ff.PME, ff.LJPME):
raise ValueError('Illegal nonbonded method for a ' raise ValueError('Illegal nonbonded method for a '
'non-periodic system') 'non-periodic system')
if implicitSolvent not in (HCT, OBC1, OBC2, GBn, GBn2, None): if implicitSolvent not in (HCT, OBC1, OBC2, GBn, GBn2, None):
...@@ -1009,6 +1009,8 @@ class CharmmPsfFile(object): ...@@ -1009,6 +1009,8 @@ class CharmmPsfFile(object):
force.setNonbondedMethod(mm.NonbondedForce.Ewald) force.setNonbondedMethod(mm.NonbondedForce.Ewald)
elif nonbondedMethod is ff.PME: elif nonbondedMethod is ff.PME:
force.setNonbondedMethod(mm.NonbondedForce.PME) force.setNonbondedMethod(mm.NonbondedForce.PME)
elif nonbondedMethod is ff.LJPME:
force.setNonbondedMethod(mm.NonbondedForce.LJPME)
else: else:
raise ValueError('Cutoff method is not understood') raise ValueError('Cutoff method is not understood')
...@@ -1088,8 +1090,7 @@ class CharmmPsfFile(object): ...@@ -1088,8 +1090,7 @@ class CharmmPsfFile(object):
mm.Discrete2DFunction(num_lj_types, num_lj_types, bcoef)) mm.Discrete2DFunction(num_lj_types, num_lj_types, bcoef))
cforce.addPerParticleParameter('type') cforce.addPerParticleParameter('type')
cforce.setForceGroup(self.NONBONDED_FORCE_GROUP) cforce.setForceGroup(self.NONBONDED_FORCE_GROUP)
if (nonbondedMethod is ff.PME or nonbondedMethod is ff.Ewald or if (nonbondedMethod in (ff.PME, ff.LJPME, ff.Ewald, ff.CutoffPeriodic)):
nonbondedMethod is ff.CutoffPeriodic):
cforce.setNonbondedMethod(cforce.CutoffPeriodic) cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff) cforce.setCutoffDistance(nonbondedCutoff)
cforce.setUseLongRangeCorrection(True) cforce.setUseLongRangeCorrection(True)
......
...@@ -165,11 +165,11 @@ class DesmondDMSFile(object): ...@@ -165,11 +165,11 @@ class DesmondDMSFile(object):
---------- ----------
nonbondedMethod : object=NoCutoff nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME. NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
nonbondedCutoff : distance=1*nanometer nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions The cutoff distance to use for nonbonded interactions
ewaldErrorTolerance : float=0.0005 ewaldErrorTolerance : float=0.0005
The error tolerance to use if nonbondedMethod is Ewald or PME. The error tolerance to use if nonbondedMethod is Ewald, PME, or LJPME.
removeCMMotion : boolean=True removeCMMotion : boolean=True
If true, a CMMotionRemover will be added to the System If true, a CMMotionRemover will be added to the System
hydrogenMass : mass=None hydrogenMass : mass=None
...@@ -185,7 +185,7 @@ class DesmondDMSFile(object): ...@@ -185,7 +185,7 @@ class DesmondDMSFile(object):
boxSize = self.topology.getUnitCellDimensions() boxSize = self.topology.getUnitCellDimensions()
if boxSize is not None: if boxSize is not None:
sys.setDefaultPeriodicBoxVectors((boxSize[0], 0, 0), (0, boxSize[1], 0), (0, 0, boxSize[2])) sys.setDefaultPeriodicBoxVectors((boxSize[0], 0, 0), (0, boxSize[1], 0), (0, 0, boxSize[2]))
elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME): elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME, ff.LJPME):
raise ValueError('Illegal nonbonded method for a non-periodic system') raise ValueError('Illegal nonbonded method for a non-periodic system')
# Create all of the particles # Create all of the particles
...@@ -207,7 +207,8 @@ class DesmondDMSFile(object): ...@@ -207,7 +207,8 @@ class DesmondDMSFile(object):
ff.CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic, ff.CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic,
ff.CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic, ff.CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic,
ff.Ewald:mm.NonbondedForce.Ewald, ff.Ewald:mm.NonbondedForce.Ewald,
ff.PME:mm.NonbondedForce.PME} ff.PME:mm.NonbondedForce.PME,
ff.LJPME:mm.NonbondedForce.LJPME}
nb.setNonbondedMethod(methodMap[nonbondedMethod]) nb.setNonbondedMethod(methodMap[nonbondedMethod])
nb.setCutoffDistance(nonbondedCutoff) nb.setCutoffDistance(nonbondedCutoff)
nb.setEwaldErrorTolerance(ewaldErrorTolerance) nb.setEwaldErrorTolerance(ewaldErrorTolerance)
......
...@@ -115,6 +115,11 @@ class PME(Singleton): ...@@ -115,6 +115,11 @@ class PME(Singleton):
return 'PME' return 'PME'
PME = PME() PME = PME()
class LJPME(Singleton):
def __repr__(self):
return 'LJPME'
LJPME = LJPME()
# Enumerated values for constraint type # Enumerated values for constraint type
class HBonds(Singleton): class HBonds(Singleton):
...@@ -971,7 +976,7 @@ class ForceField(object): ...@@ -971,7 +976,7 @@ class ForceField(object):
The Topology for which to create a System The Topology for which to create a System
nonbondedMethod : object=NoCutoff nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME. NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
nonbondedCutoff : distance=1*nanometer nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions The cutoff distance to use for nonbonded interactions
constraints : object=None constraints : object=None
...@@ -2195,7 +2200,8 @@ class NonbondedGenerator(object): ...@@ -2195,7 +2200,8 @@ class NonbondedGenerator(object):
CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic, CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic,
CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic, CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic,
Ewald:mm.NonbondedForce.Ewald, Ewald:mm.NonbondedForce.Ewald,
PME:mm.NonbondedForce.PME} PME:mm.NonbondedForce.PME,
LJPME:mm.NonbondedForce.LJPME}
if nonbondedMethod not in methodMap: if nonbondedMethod not in methodMap:
raise ValueError('Illegal nonbonded method for NonbondedForce') raise ValueError('Illegal nonbonded method for NonbondedForce')
force = mm.NonbondedForce() force = mm.NonbondedForce()
...@@ -2307,7 +2313,7 @@ class LennardJonesGenerator(object): ...@@ -2307,7 +2313,7 @@ class LennardJonesGenerator(object):
self.force.addTabulatedFunction('acoef', mm.Discrete2DFunction(numLjTypes, numLjTypes, acoef)) self.force.addTabulatedFunction('acoef', mm.Discrete2DFunction(numLjTypes, numLjTypes, acoef))
self.force.addTabulatedFunction('bcoef', mm.Discrete2DFunction(numLjTypes, numLjTypes, bcoef)) self.force.addTabulatedFunction('bcoef', mm.Discrete2DFunction(numLjTypes, numLjTypes, bcoef))
self.force.addPerParticleParameter('type') self.force.addPerParticleParameter('type')
if nonbondedMethod in [CutoffPeriodic, Ewald, PME]: if nonbondedMethod in [CutoffPeriodic, Ewald, PME, LJPME]:
self.force.setNonbondedMethod(mm.CustomNonbondedForce.CutoffPeriodic) self.force.setNonbondedMethod(mm.CustomNonbondedForce.CutoffPeriodic)
elif nonbondedMethod is NoCutoff: elif nonbondedMethod is NoCutoff:
self.force.setNonbondedMethod(mm.CustomNonbondedForce.NoCutoff) self.force.setNonbondedMethod(mm.CustomNonbondedForce.NoCutoff)
......
...@@ -552,7 +552,7 @@ class GromacsTopFile(object): ...@@ -552,7 +552,7 @@ class GromacsTopFile(object):
---------- ----------
nonbondedMethod : object=NoCutoff nonbondedMethod : object=NoCutoff
The method to use for nonbonded interactions. Allowed values are The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME. NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, or LJPME.
nonbondedCutoff : distance=1*nanometer nonbondedCutoff : distance=1*nanometer
The cutoff distance to use for nonbonded interactions The cutoff distance to use for nonbonded interactions
constraints : object=None constraints : object=None
...@@ -570,7 +570,7 @@ class GromacsTopFile(object): ...@@ -570,7 +570,7 @@ class GromacsTopFile(object):
The solvent dielectric constant to use in the implicit solvent The solvent dielectric constant to use in the implicit solvent
model. model.
ewaldErrorTolerance : float=0.0005 ewaldErrorTolerance : float=0.0005
The error tolerance to use if nonbondedMethod is Ewald or PME. The error tolerance to use if nonbondedMethod is Ewald, PME, or LJPME.
removeCMMotion : boolean=True removeCMMotion : boolean=True
If true, a CMMotionRemover will be added to the System If true, a CMMotionRemover will be added to the System
hydrogenMass : mass=None hydrogenMass : mass=None
...@@ -589,7 +589,7 @@ class GromacsTopFile(object): ...@@ -589,7 +589,7 @@ class GromacsTopFile(object):
boxVectors = self.topology.getPeriodicBoxVectors() boxVectors = self.topology.getPeriodicBoxVectors()
if boxVectors is not None: if boxVectors is not None:
sys.setDefaultPeriodicBoxVectors(*boxVectors) sys.setDefaultPeriodicBoxVectors(*boxVectors)
elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME): elif nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME, ff.LJPME):
raise ValueError('Illegal nonbonded method for a non-periodic system') raise ValueError('Illegal nonbonded method for a non-periodic system')
nb = mm.NonbondedForce() nb = mm.NonbondedForce()
sys.addForce(nb) sys.addForce(nb)
...@@ -877,7 +877,8 @@ class GromacsTopFile(object): ...@@ -877,7 +877,8 @@ class GromacsTopFile(object):
ff.CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic, ff.CutoffNonPeriodic:mm.NonbondedForce.CutoffNonPeriodic,
ff.CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic, ff.CutoffPeriodic:mm.NonbondedForce.CutoffPeriodic,
ff.Ewald:mm.NonbondedForce.Ewald, ff.Ewald:mm.NonbondedForce.Ewald,
ff.PME:mm.NonbondedForce.PME} ff.PME:mm.NonbondedForce.PME,
ff.LJPME:mm.NonbondedForce.LJPME}
nb.setNonbondedMethod(methodMap[nonbondedMethod]) nb.setNonbondedMethod(methodMap[nonbondedMethod])
nb.setCutoffDistance(nonbondedCutoff) nb.setCutoffDistance(nonbondedCutoff)
nb.setEwaldErrorTolerance(ewaldErrorTolerance) nb.setEwaldErrorTolerance(ewaldErrorTolerance)
......
...@@ -776,6 +776,8 @@ def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=No ...@@ -776,6 +776,8 @@ def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=No
force.setNonbondedMethod(mm.NonbondedForce.Ewald) force.setNonbondedMethod(mm.NonbondedForce.Ewald)
elif nonbondedMethod == 'PME': elif nonbondedMethod == 'PME':
force.setNonbondedMethod(mm.NonbondedForce.PME) force.setNonbondedMethod(mm.NonbondedForce.PME)
elif nonbondedMethod == 'LJPME':
force.setNonbondedMethod(mm.NonbondedForce.LJPME)
else: else:
raise Exception("Cutoff method not understood.") raise Exception("Cutoff method not understood.")
...@@ -885,7 +887,7 @@ def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=No ...@@ -885,7 +887,7 @@ def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=No
ii, jj, chg, sig, eps = force.getExceptionParameters(i) ii, jj, chg, sig, eps = force.getExceptionParameters(i)
cforce.addExclusion(ii, jj) cforce.addExclusion(ii, jj)
# Now set the various properties based on the NonbondedForce object # Now set the various properties based on the NonbondedForce object
if nonbondedMethod in ('PME', 'Ewald', 'CutoffPeriodic'): if nonbondedMethod in ('PME', 'LJPME', 'Ewald', 'CutoffPeriodic'):
cforce.setNonbondedMethod(cforce.CutoffPeriodic) cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff) cforce.setCutoffDistance(nonbondedCutoff)
cforce.setUseLongRangeCorrection(True) cforce.setUseLongRangeCorrection(True)
......
...@@ -186,6 +186,8 @@ class TestAPIUnits(unittest.TestCase): ...@@ -186,6 +186,8 @@ class TestAPIUnits(unittest.TestCase):
self.assertTrue(force.usesPeriodicBoundaryConditions()) self.assertTrue(force.usesPeriodicBoundaryConditions())
force.setNonbondedMethod(NonbondedForce.PME) force.setNonbondedMethod(NonbondedForce.PME)
self.assertTrue(force.usesPeriodicBoundaryConditions()) self.assertTrue(force.usesPeriodicBoundaryConditions())
force.setNonbondedMethod(NonbondedForce.LJPME)
self.assertTrue(force.usesPeriodicBoundaryConditions())
def testCmapForce(self): def testCmapForce(self):
""" Tests the CMAPTorsionForce API features """ """ Tests the CMAPTorsionForce API features """
......
...@@ -21,12 +21,14 @@ class TestAmberPrmtopFile(unittest.TestCase): ...@@ -21,12 +21,14 @@ class TestAmberPrmtopFile(unittest.TestCase):
"""Test the AmberPrmtopFile.createSystem() method.""" """Test the AmberPrmtopFile.createSystem() method."""
def test_NonbondedMethod(self): def test_NonbondedMethod(self):
"""Test all five options for the nonbondedMethod parameter.""" """Test all six options for the nonbondedMethod parameter."""
methodMap = {NoCutoff:NonbondedForce.NoCutoff, methodMap = {NoCutoff:NonbondedForce.NoCutoff,
CutoffNonPeriodic:NonbondedForce.CutoffNonPeriodic, CutoffNonPeriodic:NonbondedForce.CutoffNonPeriodic,
CutoffPeriodic:NonbondedForce.CutoffPeriodic, CutoffPeriodic:NonbondedForce.CutoffPeriodic,
Ewald:NonbondedForce.Ewald, PME: NonbondedForce.PME} Ewald:NonbondedForce.Ewald,
PME:NonbondedForce.PME,
LJPME:NonbondedForce.LJPME}
for method in methodMap: for method in methodMap:
system = prmtop1.createSystem(nonbondedMethod=method) system = prmtop1.createSystem(nonbondedMethod=method)
forces = system.getForces() forces = system.getForces()
...@@ -37,7 +39,7 @@ class TestAmberPrmtopFile(unittest.TestCase): ...@@ -37,7 +39,7 @@ class TestAmberPrmtopFile(unittest.TestCase):
def test_Cutoff(self): def test_Cutoff(self):
"""Test to make sure the nonbondedCutoff parameter is passed correctly.""" """Test to make sure the nonbondedCutoff parameter is passed correctly."""
for method in [CutoffNonPeriodic, CutoffPeriodic, Ewald, PME]: for method in [CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, LJPME]:
system = prmtop1.createSystem(nonbondedMethod=method, system = prmtop1.createSystem(nonbondedMethod=method,
nonbondedCutoff=2*nanometer, nonbondedCutoff=2*nanometer,
constraints=HBonds) constraints=HBonds)
...@@ -51,7 +53,7 @@ class TestAmberPrmtopFile(unittest.TestCase): ...@@ -51,7 +53,7 @@ class TestAmberPrmtopFile(unittest.TestCase):
def test_EwaldErrorTolerance(self): def test_EwaldErrorTolerance(self):
"""Test to make sure the ewaldErrorTolerance parameter is passed correctly.""" """Test to make sure the ewaldErrorTolerance parameter is passed correctly."""
for method in [Ewald, PME]: for method in [Ewald, PME, LJPME]:
system = prmtop1.createSystem(nonbondedMethod=method, system = prmtop1.createSystem(nonbondedMethod=method,
ewaldErrorTolerance=1e-6, ewaldErrorTolerance=1e-6,
constraints=HBonds) constraints=HBonds)
......
...@@ -14,12 +14,14 @@ class TestDesmondDMSFile(unittest.TestCase): ...@@ -14,12 +14,14 @@ class TestDesmondDMSFile(unittest.TestCase):
self.dms = DesmondDMSFile(path) self.dms = DesmondDMSFile(path)
def test_NonbondedMethod(self): def test_NonbondedMethod(self):
"""Test all five options for the nonbondedMethod parameter.""" """Test all six options for the nonbondedMethod parameter."""
methodMap = {NoCutoff:NonbondedForce.NoCutoff, methodMap = {NoCutoff:NonbondedForce.NoCutoff,
CutoffNonPeriodic:NonbondedForce.CutoffNonPeriodic, CutoffNonPeriodic:NonbondedForce.CutoffNonPeriodic,
CutoffPeriodic:NonbondedForce.CutoffPeriodic, CutoffPeriodic:NonbondedForce.CutoffPeriodic,
Ewald:NonbondedForce.Ewald, PME: NonbondedForce.PME} Ewald:NonbondedForce.Ewald,
PME:NonbondedForce.PME,
LJPME:NonbondedForce.LJPME}
for method in methodMap: for method in methodMap:
system = self.dms.createSystem(nonbondedMethod=method) system = self.dms.createSystem(nonbondedMethod=method)
forces = system.getForces() forces = system.getForces()
...@@ -30,7 +32,7 @@ class TestDesmondDMSFile(unittest.TestCase): ...@@ -30,7 +32,7 @@ class TestDesmondDMSFile(unittest.TestCase):
def test_Cutoff(self): def test_Cutoff(self):
"""Test to make sure the nonbondedCutoff parameter is passed correctly.""" """Test to make sure the nonbondedCutoff parameter is passed correctly."""
for method in [CutoffNonPeriodic, CutoffPeriodic, Ewald, PME]: for method in [CutoffNonPeriodic, CutoffPeriodic, Ewald, PME, LJPME]:
system = self.dms.createSystem(nonbondedMethod=method, system = self.dms.createSystem(nonbondedMethod=method,
nonbondedCutoff=2*nanometer) nonbondedCutoff=2*nanometer)
cutoff_distance = 0.0*nanometer cutoff_distance = 0.0*nanometer
...@@ -43,7 +45,7 @@ class TestDesmondDMSFile(unittest.TestCase): ...@@ -43,7 +45,7 @@ class TestDesmondDMSFile(unittest.TestCase):
def test_EwaldErrorTolerance(self): def test_EwaldErrorTolerance(self):
"""Test to make sure the ewaldErrorTolerance parameter is passed correctly.""" """Test to make sure the ewaldErrorTolerance parameter is passed correctly."""
for method in [Ewald, PME]: for method in [Ewald, PME, LJPME]:
system = self.dms.createSystem(nonbondedMethod=method, system = self.dms.createSystem(nonbondedMethod=method,
ewaldErrorTolerance=1e-6) ewaldErrorTolerance=1e-6)
tolerance = 0 tolerance = 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