Commit 8647eaad authored by Peter Eastman's avatar Peter Eastman
Browse files

Revised calculation for dispersion PME grid size

parent d326d15d
...@@ -458,7 +458,7 @@ The formula used to compute the number of nodes along each dimension of the mesh ...@@ -458,7 +458,7 @@ The formula used to compute the number of nodes along each dimension of the mesh
is slightly different from the one used for Coulomb interactions: is slightly different from the one used for Coulomb interactions:
.. math:: .. math::
n_\mathit{mesh}=\frac{\alpha d}{{3\delta}^{1/20}} n_\mathit{mesh}=\frac{\alpha d}{{3\delta}^{1/5}}
As before, this is an empirical formula. It will usually produce an average As before, this is an empirical formula. It will usually produce an average
relative error in the forces less than or similar to :math:`\delta`\ , but that relative error in the forces less than or similar to :math:`\delta`\ , but that
......
...@@ -160,9 +160,9 @@ void NonbondedForceImpl::calcPMEParameters(const System& system, const Nonbonded ...@@ -160,9 +160,9 @@ void NonbondedForceImpl::calcPMEParameters(const System& system, const Nonbonded
double tol = force.getEwaldErrorTolerance(); double tol = force.getEwaldErrorTolerance();
alpha = (1.0/force.getCutoffDistance())*std::sqrt(-log(2.0*tol)); alpha = (1.0/force.getCutoffDistance())*std::sqrt(-log(2.0*tol));
if (lj) { if (lj) {
xsize = (int) ceil(alpha*boxVectors[0][0]/(3*pow(tol, 0.05))); xsize = (int) ceil(alpha*boxVectors[0][0]/(3*pow(tol, 0.2)));
ysize = (int) ceil(alpha*boxVectors[1][1]/(3*pow(tol, 0.05))); ysize = (int) ceil(alpha*boxVectors[1][1]/(3*pow(tol, 0.2)));
zsize = (int) ceil(alpha*boxVectors[2][2]/(3*pow(tol, 0.05))); zsize = (int) ceil(alpha*boxVectors[2][2]/(3*pow(tol, 0.2)));
} }
else { else {
xsize = (int) ceil(2*alpha*boxVectors[0][0]/(3*pow(tol, 0.2))); xsize = (int) ceil(2*alpha*boxVectors[0][0]/(3*pow(tol, 0.2)));
......
...@@ -1629,6 +1629,10 @@ CudaCalcNonbondedForceKernel::~CudaCalcNonbondedForceKernel() { ...@@ -1629,6 +1629,10 @@ CudaCalcNonbondedForceKernel::~CudaCalcNonbondedForceKernel() {
if (useCudaFFT) { if (useCudaFFT) {
cufftDestroy(fftForward); cufftDestroy(fftForward);
cufftDestroy(fftBackward); cufftDestroy(fftBackward);
if (doLJPME) {
cufftDestroy(dispersionFftForward);
cufftDestroy(dispersionFftBackward);
}
} }
if (usePmeStream) { if (usePmeStream) {
cuStreamDestroy(pmeStream); cuStreamDestroy(pmeStream);
......
...@@ -43,8 +43,60 @@ ...@@ -43,8 +43,60 @@
using namespace OpenMM; using namespace OpenMM;
using namespace std; 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 = 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() { void testErrorTolerance() {
// Create a cloud of random point charges. // Create a cloud of random particles.
const int numParticles = 200; const int numParticles = 200;
const double boxWidth = 5.0; const double boxWidth = 5.0;
...@@ -118,7 +170,7 @@ void testErrorTolerance() { ...@@ -118,7 +170,7 @@ void testErrorTolerance() {
} }
void testPMEParameters() { void testPMEParameters() {
// Create a cloud of random point charges. // Create a cloud of random particles.
const int numParticles = 51; const int numParticles = 51;
const double boxWidth = 4.7; const double boxWidth = 4.7;
...@@ -136,10 +188,11 @@ void testPMEParameters() { ...@@ -136,10 +188,11 @@ void testPMEParameters() {
positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt)); positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
} }
force->setNonbondedMethod(NonbondedForce::LJPME); force->setNonbondedMethod(NonbondedForce::LJPME);
force->setCutoffDistance(0.5);
// Compute the energy with an error tolerance of 1e-3. // Compute the energy with an error tolerance of 0.1.
force->setEwaldErrorTolerance(1e-3); force->setEwaldErrorTolerance(0.1);
VerletIntegrator integrator1(0.01); VerletIntegrator integrator1(0.01);
Context context1(system, integrator1, platform); Context context1(system, integrator1, platform);
context1.setPositions(positions); context1.setPositions(positions);
...@@ -157,7 +210,7 @@ void testPMEParameters() { ...@@ -157,7 +210,7 @@ void testPMEParameters() {
double energy2 = context2.getState(State::Energy).getPotentialEnergy(); double energy2 = context2.getState(State::Energy).getPotentialEnergy();
// Now explicitly set the parameters. These should match the values that were // Now explicitly set the parameters. These should match the values that were
// used for tolerance 1e-3. // used for tolerance 0.1.
force->setLJPMEParameters(alpha, gridx, gridy, gridz); force->setLJPMEParameters(alpha, gridx, gridy, gridz);
VerletIntegrator integrator3(0.01); VerletIntegrator integrator3(0.01);
...@@ -1806,6 +1859,7 @@ void runPlatformTests(); ...@@ -1806,6 +1859,7 @@ void runPlatformTests();
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
initializeTests(argc, argv); initializeTests(argc, argv);
testConvergence();
testErrorTolerance(); testErrorTolerance();
testPMEParameters(); testPMEParameters();
testWater2DpmeEnergiesForcesNoExclusions(); testWater2DpmeEnergiesForcesNoExclusions();
......
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