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());
} }
This diff is collapsed.
...@@ -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_*/
This diff is collapsed.
...@@ -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;
......
This diff is collapsed.
...@@ -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
......
...@@ -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 """
......
This diff is collapsed.
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