"openmmapi/src/ThreadPool.cpp" did not exist on "0be0772b186c1f7193f932b75f355b718ebbb04a"
Commit 9b9002c7 authored by Peter Eastman's avatar Peter Eastman
Browse files

Fixed energy error for Drude particle at same location as its parent atom

parent e82225da
...@@ -386,13 +386,15 @@ void CpuNonbondedForce::threadComputeDirect(ThreadPool& threads, int threadIndex ...@@ -386,13 +386,15 @@ void CpuNonbondedForce::threadComputeDirect(ThreadPool& threads, int threadIndex
float inverseR = 1/r; float inverseR = 1/r;
float chargeProdOverR = scaledChargeI*posq[4*j+3]*inverseR; float chargeProdOverR = scaledChargeI*posq[4*j+3]*inverseR;
float dEdR = chargeProdOverR*inverseR*inverseR; float dEdR = chargeProdOverR*inverseR*inverseR;
dEdR = dEdR * (erfAlphaR-(float)TWO_OVER_SQRT_PI*alphaR*(float)exp(-alphaR*alphaR)); dEdR = dEdR * (erfAlphaR-TWO_OVER_SQRT_PI*alphaR*(float)exp(-alphaR*alphaR));
fvec4 result = deltaR*dEdR; fvec4 result = deltaR*dEdR;
(fvec4(forces+4*i)-result).store(forces+4*i); (fvec4(forces+4*i)-result).store(forces+4*i);
(fvec4(forces+4*j)+result).store(forces+4*j); (fvec4(forces+4*j)+result).store(forces+4*j);
if (includeEnergy) if (includeEnergy)
threadEnergy[threadIndex] -= chargeProdOverR*erfAlphaR; threadEnergy[threadIndex] -= chargeProdOverR*erfAlphaR;
} }
else if (includeEnergy)
threadEnergy[threadIndex] -= alphaEwald*TWO_OVER_SQRT_PI*scaledChargeI*posq[4*j+3];
} }
} }
} }
......
...@@ -25,8 +25,10 @@ ...@@ -25,8 +25,10 @@
tempForce = -prefactor*(erfAlphaR-alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI); tempForce = -prefactor*(erfAlphaR-alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI);
tempEnergy += -prefactor*erfAlphaR; tempEnergy += -prefactor*erfAlphaR;
} }
else else {
includeInteraction = false; includeInteraction = false;
tempEnergy -= TWO_OVER_SQRT_PI*EWALD_ALPHA*138.935456f*posq1.w*posq2.w;
}
} }
else { else {
#if HAS_LENNARD_JONES #if HAS_LENNARD_JONES
......
...@@ -179,10 +179,8 @@ OpenCLContext::OpenCLContext(const System& system, int platformIndex, int device ...@@ -179,10 +179,8 @@ OpenCLContext::OpenCLContext(const System& system, int platformIndex, int device
compilationDefines["WORK_GROUP_SIZE"] = intToString(ThreadBlockSize); compilationDefines["WORK_GROUP_SIZE"] = intToString(ThreadBlockSize);
if (platformVendor.size() >= 5 && platformVendor.substr(0, 5) == "Intel") if (platformVendor.size() >= 5 && platformVendor.substr(0, 5) == "Intel")
defaultOptimizationOptions = ""; defaultOptimizationOptions = "";
else if (platformVendor == "Apple")
defaultOptimizationOptions = "-cl-mad-enable -cl-no-signed-zeros";
else else
defaultOptimizationOptions = "-cl-fast-relaxed-math"; defaultOptimizationOptions = "-cl-mad-enable -cl-no-signed-zeros";
supports64BitGlobalAtomics = (device.getInfo<CL_DEVICE_EXTENSIONS>().find("cl_khr_int64_base_atomics") != string::npos); supports64BitGlobalAtomics = (device.getInfo<CL_DEVICE_EXTENSIONS>().find("cl_khr_int64_base_atomics") != string::npos);
supportsDoublePrecision = (device.getInfo<CL_DEVICE_EXTENSIONS>().find("cl_khr_fp64") != string::npos); supportsDoublePrecision = (device.getInfo<CL_DEVICE_EXTENSIONS>().find("cl_khr_fp64") != string::npos);
if ((useDoublePrecision || useMixedPrecision) && !supportsDoublePrecision) if ((useDoublePrecision || useMixedPrecision) && !supportsDoublePrecision)
......
...@@ -30,8 +30,10 @@ ...@@ -30,8 +30,10 @@
tempForce = -prefactor*(erfAlphaR-alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI); tempForce = -prefactor*(erfAlphaR-alphaR*expAlphaRSqr*TWO_OVER_SQRT_PI);
tempEnergy += -prefactor*erfAlphaR; tempEnergy += -prefactor*erfAlphaR;
} }
else else {
includeInteraction = false; includeInteraction = false;
tempEnergy -= TWO_OVER_SQRT_PI*EWALD_ALPHA*138.935456f*posq1.w*posq2.w;
}
} }
else { else {
#if HAS_LENNARD_JONES #if HAS_LENNARD_JONES
......
...@@ -446,12 +446,15 @@ void ReferenceLJCoulombIxn::calculateEwaldIxn(int numberOfAtoms, vector<RealVec> ...@@ -446,12 +446,15 @@ void ReferenceLJCoulombIxn::calculateEwaldIxn(int numberOfAtoms, vector<RealVec>
// accumulate energies // accumulate energies
realSpaceEwaldEnergy = (RealOpenMM) (ONE_4PI_EPS0*atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR*erf(alphaR)); realSpaceEwaldEnergy = (RealOpenMM) (ONE_4PI_EPS0*atomParameters[ii][QIndex]*atomParameters[jj][QIndex]*inverseR*erf(alphaR));
}
else {
realSpaceEwaldEnergy = (RealOpenMM) (alphaEwald*M_2_SQRTPI*ONE_4PI_EPS0*atomParameters[ii][QIndex]*atomParameters[jj][QIndex]);
}
totalExclusionEnergy += realSpaceEwaldEnergy; totalExclusionEnergy += realSpaceEwaldEnergy;
if (energyByAtom) { if (energyByAtom) {
energyByAtom[ii] -= realSpaceEwaldEnergy; energyByAtom[ii] -= realSpaceEwaldEnergy;
energyByAtom[jj] -= realSpaceEwaldEnergy; energyByAtom[jj] -= realSpaceEwaldEnergy;
}
} }
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2013-2015 Stanford University and the Authors. * * Portions copyright (c) 2013-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -179,6 +179,66 @@ void testWater() { ...@@ -179,6 +179,66 @@ void testWater() {
ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.02); ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.02);
} }
void testForceEnergyConsistency() {
// Create a box of polarizable particles.
const int gridSize = 3;
const int numAtoms = gridSize*gridSize*gridSize;
const double spacing = 0.6;
const double boxSize = spacing*(gridSize+1);
const double temperature = 300.0;
const double temperatureDrude = 10.0;
System system;
vector<Vec3> positions;
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::PME);
nonbonded->setCutoffDistance(1.0);
nonbonded->setUseSwitchingFunction(true);
nonbonded->setSwitchingDistance(0.9);
nonbonded->setEwaldErrorTolerance(5e-5);
for (int i = 0; i < numAtoms; i++) {
int startIndex = system.getNumParticles();
system.addParticle(1.0);
system.addParticle(1.0);
nonbonded->addParticle(1.0, 0.3, 1.0);
nonbonded->addParticle(-1.0, 0.3, 1.0);
nonbonded->addException(startIndex, startIndex+1, 0, 1, 0);
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.0, 0.001, 1, 1);
}
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
}
// Simulate it and check that force and energy remain consistent.
DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.001);
Platform& platform = Platform::getPlatformByName("CUDA");
Context context(system, integ, platform);
context.setPositions(positions);
State prevState;
for (int i = 0; i < 100; i++) {
State state = context.getState(State::Energy | State::Forces | State::Positions);
if (i > 0) {
double expectedEnergyChange = 0;
for (int j = 0; j < system.getNumParticles(); j++) {
Vec3 delta = state.getPositions()[j]-prevState.getPositions()[j];
expectedEnergyChange -= 0.5*(state.getForces()[j]+prevState.getForces()[j]).dot(delta);
}
ASSERT_EQUAL_TOL(expectedEnergyChange, state.getPotentialEnergy()-prevState.getPotentialEnergy(), 0.05);
}
prevState = state;
integ.step(1);
}
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
registerDrudeCudaKernelFactories(); registerDrudeCudaKernelFactories();
...@@ -186,6 +246,7 @@ int main(int argc, char* argv[]) { ...@@ -186,6 +246,7 @@ int main(int argc, char* argv[]) {
Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", string(argv[1])); Platform::getPlatformByName("CUDA").setPropertyDefaultValue("Precision", string(argv[1]));
testSinglePair(); testSinglePair();
testWater(); testWater();
testForceEnergyConsistency();
} }
catch(const std::exception& e) { catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl; std::cout << "exception: " << e.what() << std::endl;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2013-2015 Stanford University and the Authors. * * Portions copyright (c) 2013-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -179,6 +179,66 @@ void testWater() { ...@@ -179,6 +179,66 @@ void testWater() {
ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.02); ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.02);
} }
void testForceEnergyConsistency() {
// Create a box of polarizable particles.
const int gridSize = 3;
const int numAtoms = gridSize*gridSize*gridSize;
const double spacing = 0.6;
const double boxSize = spacing*(gridSize+1);
const double temperature = 300.0;
const double temperatureDrude = 10.0;
System system;
vector<Vec3> positions;
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::PME);
nonbonded->setCutoffDistance(1.0);
nonbonded->setUseSwitchingFunction(true);
nonbonded->setSwitchingDistance(0.9);
nonbonded->setEwaldErrorTolerance(5e-5);
for (int i = 0; i < numAtoms; i++) {
int startIndex = system.getNumParticles();
system.addParticle(1.0);
system.addParticle(1.0);
nonbonded->addParticle(1.0, 0.3, 1.0);
nonbonded->addParticle(-1.0, 0.3, 1.0);
nonbonded->addException(startIndex, startIndex+1, 0, 1, 0);
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.0, 0.001, 1, 1);
}
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
}
// Simulate it and check that force and energy remain consistent.
DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.001);
Platform& platform = Platform::getPlatformByName("OpenCL");
Context context(system, integ, platform);
context.setPositions(positions);
State prevState;
for (int i = 0; i < 100; i++) {
State state = context.getState(State::Energy | State::Forces | State::Positions);
if (i > 0) {
double expectedEnergyChange = 0;
for (int j = 0; j < system.getNumParticles(); j++) {
Vec3 delta = state.getPositions()[j]-prevState.getPositions()[j];
expectedEnergyChange -= 0.5*(state.getForces()[j]+prevState.getForces()[j]).dot(delta);
}
ASSERT_EQUAL_TOL(expectedEnergyChange, state.getPotentialEnergy()-prevState.getPotentialEnergy(), 0.05);
}
prevState = state;
integ.step(1);
}
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
registerDrudeOpenCLKernelFactories(); registerDrudeOpenCLKernelFactories();
...@@ -186,6 +246,7 @@ int main(int argc, char* argv[]) { ...@@ -186,6 +246,7 @@ int main(int argc, char* argv[]) {
Platform::getPlatformByName("OpenCL").setPropertyDefaultValue("Precision", string(argv[1])); Platform::getPlatformByName("OpenCL").setPropertyDefaultValue("Precision", string(argv[1]));
testSinglePair(); testSinglePair();
testWater(); testWater();
testForceEnergyConsistency();
} }
catch(const std::exception& e) { catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl; std::cout << "exception: " << e.what() << std::endl;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2013-2015 Stanford University and the Authors. * * Portions copyright (c) 2013-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -179,11 +179,72 @@ void testWater() { ...@@ -179,11 +179,72 @@ void testWater() {
ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.03); ASSERT_USUALLY_EQUAL_TOL(expectedTemp, ke/(0.5*numDof*BOLTZ), 0.03);
} }
void testForceEnergyConsistency() {
// Create a box of polarizable particles.
const int gridSize = 3;
const int numAtoms = gridSize*gridSize*gridSize;
const double spacing = 0.6;
const double boxSize = spacing*(gridSize+1);
const double temperature = 300.0;
const double temperatureDrude = 10.0;
System system;
vector<Vec3> positions;
NonbondedForce* nonbonded = new NonbondedForce();
DrudeForce* drude = new DrudeForce();
system.addForce(nonbonded);
system.addForce(drude);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setNonbondedMethod(NonbondedForce::PME);
nonbonded->setCutoffDistance(1.0);
nonbonded->setUseSwitchingFunction(true);
nonbonded->setSwitchingDistance(0.9);
nonbonded->setEwaldErrorTolerance(5e-5);
for (int i = 0; i < numAtoms; i++) {
int startIndex = system.getNumParticles();
system.addParticle(1.0);
system.addParticle(1.0);
nonbonded->addParticle(1.0, 0.3, 1.0);
nonbonded->addParticle(-1.0, 0.3, 1.0);
nonbonded->addException(startIndex, startIndex+1, 0, 1, 0);
drude->addParticle(startIndex+1, startIndex, -1, -1, -1, -1.0, 0.001, 1, 1);
}
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
Vec3 pos(i*spacing, j*spacing, k*spacing);
positions.push_back(pos);
positions.push_back(pos);
}
// Simulate it and check that force and energy remain consistent.
DrudeLangevinIntegrator integ(temperature, 50.0, temperatureDrude, 50.0, 0.001);
Platform& platform = Platform::getPlatformByName("Reference");
Context context(system, integ, platform);
context.setPositions(positions);
State prevState;
for (int i = 0; i < 100; i++) {
State state = context.getState(State::Energy | State::Forces | State::Positions);
if (i > 0) {
double expectedEnergyChange = 0;
for (int j = 0; j < system.getNumParticles(); j++) {
Vec3 delta = state.getPositions()[j]-prevState.getPositions()[j];
expectedEnergyChange -= 0.5*(state.getForces()[j]+prevState.getForces()[j]).dot(delta);
}
ASSERT_EQUAL_TOL(expectedEnergyChange, state.getPotentialEnergy()-prevState.getPotentialEnergy(), 0.05);
}
prevState = state;
integ.step(1);
}
}
int main() { int main() {
try { try {
registerDrudeReferenceKernelFactories(); registerDrudeReferenceKernelFactories();
testSinglePair(); testSinglePair();
testWater(); testWater();
testForceEnergyConsistency();
} }
catch(const std::exception& e) { catch(const std::exception& e) {
std::cout << "exception: " << e.what() << std::endl; std::cout << "exception: " << e.what() << std::endl;
......
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