Commit 83d57922 authored by Peter Eastman's avatar Peter Eastman
Browse files

Automatically select Ewald parameters based on error tolerance

parent 9eb02774
......@@ -119,14 +119,28 @@ public:
void setNonbondedMethod(NonbondedMethod method);
/**
* Get the cutoff distance (in nm) being used for nonbonded interactions. If the NonbondedMethod in use
* does not use cutoffs, this value will have no effect.
* is NoCutoff, this value will have no effect.
*/
double getCutoffDistance() const;
/**
* Set the cutoff distance (in nm) being used for nonbonded interactions. If the NonbondedMethod in use
* does not use cutoffs, this value will have no effect.
* is NoCutoff, this value will have no effect.
*/
void setCutoffDistance(double distance);
/**
* Get the error tolerance for Ewald summation. This corresponds to the fractional error in the forces
* which is acceptable. This value is used to select the reciprocal space cutoff and separation
* parameter so that the average error level will be less than the tolerance. There is not a
* rigorous guarantee that all forces on all atoms will be less than the tolerance, however.
*/
double getEwaldErrorTolerance() const;
/**
* Get the error tolerance for Ewald summation. This corresponds to the fractional error in the forces
* which is acceptable. This value is used to select the reciprocal space cutoff and separation
* parameter so that the average error level will be less than the tolerance. There is not a
* rigorous guarantee that all forces on all atoms will be less than the tolerance, however.
*/
void setEwaldErrorTolerance(double tol);
/**
* Get the vectors which define the axes of the periodic box (measured in nm). If the NonbondedMethod
* in use does not use periodic boundary conditions, these values will have no effect.
......@@ -242,7 +256,7 @@ private:
class ParticleInfo;
class ExceptionInfo;
NonbondedMethod nonbondedMethod;
double cutoffDistance;
double cutoffDistance, ewaldErrorTol;
Vec3 periodicBoxVectors[3];
void addExclusionsToSet(const std::vector<std::set<int> >& bonded12, std::set<int>& exclusions, int baseParticle, int fromParticle, int currentLevel) const;
......
......@@ -41,7 +41,7 @@ using std::pair;
using std::set;
using std::vector;
NonbondedForce::NonbondedForce() : nonbondedMethod(NoCutoff), cutoffDistance(1.0) {
NonbondedForce::NonbondedForce() : nonbondedMethod(NoCutoff), cutoffDistance(1.0), ewaldErrorTol(1e-4) {
periodicBoxVectors[0] = Vec3(2, 0, 0);
periodicBoxVectors[1] = Vec3(0, 2, 0);
periodicBoxVectors[2] = Vec3(0, 0, 2);
......@@ -63,6 +63,15 @@ void NonbondedForce::setCutoffDistance(double distance) {
cutoffDistance = distance;
}
double NonbondedForce::getEwaldErrorTolerance() const {
return ewaldErrorTol;
}
void NonbondedForce::setEwaldErrorTolerance(double tol)
{
ewaldErrorTol = tol;
}
void NonbondedForce::getPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) const {
a = periodicBoxVectors[0];
b = periodicBoxVectors[1];
......
......@@ -304,9 +304,17 @@ void CudaCalcNonbondedForceKernel::initialize(const System& system, const Nonbon
Vec3 boxVectors[3];
force.getPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2]);
gpuSetPeriodicBoxSize(gpu, (float)boxVectors[0][0], (float)boxVectors[1][1], (float)boxVectors[2][2]);
gpuSetEwaldParameters(gpu);//, (float)alphaEwald, (int)kmax);
double ewaldErrorTol = force.getEwaldErrorTolerance();
double alpha = (1.0/force.getCutoffDistance())*std::sqrt(-std::log(ewaldErrorTol));
double mx = boxVectors[0][0]/force.getCutoffDistance();
double my = boxVectors[1][1]/force.getCutoffDistance();
double mz = boxVectors[2][2]/force.getCutoffDistance();
double pi = 3.1415926535897932385;
int kmaxx = std::ceil(-(mx/pi)*std::log(ewaldErrorTol));;
int kmaxy = std::ceil(-(my/pi)*std::log(ewaldErrorTol));;
int kmaxz = std::ceil(-(mz/pi)*std::log(ewaldErrorTol));;
gpuSetEwaldParameters(gpu, alpha, kmaxx, kmaxy, kmaxz);
method = EWALD;
}
data.nonbondedMethod = method;
gpuSetCoulombParameters(gpu, 138.935485f, particle, c6, c12, q, symbol, exclusionList, method);
......
......@@ -300,7 +300,9 @@ struct cudaGmxSimulation {
float cellVolume; // Ewald parameter alpha (a.k.a. kappa)
float alphaEwald; // Ewald parameter alpha (a.k.a. kappa)
float factorEwald; // - 1 ( 4 * alphaEwald * alphaEwald)
int kmax; // Maximum number of reciprocal vectors
int kmaxX; // Maximum number of reciprocal vectors in the X direction
int kmaxY; // Maximum number of reciprocal vectors in the Y direction
int kmaxZ; // Maximum number of reciprocal vectors in the Z direction
float reactionFieldK; // Constant for reaction field correction
float probeRadius; // SASA probe radius
float surfaceAreaFactor; // ACE approximation surface area factor
......
......@@ -424,15 +424,14 @@ void gpuSetNonbondedCutoff(gpuContext gpu, float cutoffDistance, float solventDi
}
extern "C"
void gpuSetEwaldParameters(gpuContext gpu)//, float alphaEwald, int kmax )
void gpuSetEwaldParameters(gpuContext gpu, float alpha, int kmaxx, int kmaxy, int kmaxz)
{
// hard coded alphaEwald and kmax, no interface yet
float alpha = 3.123413f;
gpu->sim.alphaEwald = alpha;
gpu->sim.factorEwald = -1 / (4*alpha*alpha);
gpu->sim.kmax = 20+1;
gpu->psEwaldCosSinSum = new CUDAStream<float2>((gpu->sim.kmax*2-1) * (gpu->sim.kmax*2-1) * (gpu->sim.kmax*2-1), 1, "EwaldCosSinSum");
gpu->sim.kmaxX = kmaxx;
gpu->sim.kmaxY = kmaxy;
gpu->sim.kmaxZ = kmaxz;
gpu->psEwaldCosSinSum = new CUDAStream<float2>((gpu->sim.kmaxX*2-1) * (gpu->sim.kmaxY*2-1) * (gpu->sim.kmaxZ*2-1), 1, "EwaldCosSinSum");
gpu->sim.pEwaldCosSinSum = gpu->psEwaldCosSinSum->_pDevStream[0];
}
......
......@@ -176,7 +176,7 @@ extern "C"
void gpuSetNonbondedCutoff(gpuContext gpu, float cutoffDistance, float solventDielectric);
extern "C"
void gpuSetEwaldParameters(gpuContext gpu);//, float alphaEwald, int kmax);
void gpuSetEwaldParameters(gpuContext gpu, float alpha, int kmaxx, int kmaxy, int kmaxz);
extern "C"
void gpuSetPeriodicBoxSize(gpuContext gpu, float xsize, float ysize, float zsize);
......
......@@ -53,18 +53,20 @@ __device__ float2 ConjMultofFloat2(float2 a, float2 b)
__global__ void kCalculateEwaldFastCosSinSums_kernel()
{
const unsigned int ksize = 2*cSim.kmax-1;
const unsigned int totalK = ksize*ksize*ksize;
const unsigned int ksizex = 2*cSim.kmaxX-1;
const unsigned int ksizey = 2*cSim.kmaxY-1;
const unsigned int ksizez = 2*cSim.kmaxZ-1;
const unsigned int totalK = ksizex*ksizey*ksizez;
unsigned int index = threadIdx.x + blockIdx.x * blockDim.x;
while (index < totalK)
{
// Find the wave vector (kx, ky, kz) this index corresponds to.
int rx = index/(ksize*ksize);
int remainder = index - rx*ksize*ksize;
int ry = remainder/ksize;
int rz = remainder - ry*ksize - cSim.kmax + 1;
ry += -cSim.kmax + 1;
int rx = index/(ksizey*ksizez);
int remainder = index - rx*ksizey*ksizez;
int ry = remainder/ksizez;
int rz = remainder - ry*ksizez - cSim.kmaxZ + 1;
ry += -cSim.kmaxY + 1;
float kx = rx*cSim.recipBoxSizeX;
float ky = ry*cSim.recipBoxSizeY;
float kz = rz*cSim.recipBoxSizeZ;
......@@ -101,10 +103,6 @@ __global__ void kCalculateEwaldFastForces_kernel()
const float epsilon = 1.0;
float recipCoeff = cSim.epsfac*(4*PI/cSim.cellVolume/epsilon);
const int numRx = cSim.kmax;
const int numRy = cSim.kmax;
const int numRz = cSim.kmax;
unsigned int atom = threadIdx.x + blockIdx.x * blockDim.x;
while (atom < cSim.atoms)
......@@ -116,20 +114,20 @@ __global__ void kCalculateEwaldFastForces_kernel()
int lowry = 0;
int lowrz = 1;
for (int rx = 0; rx < numRx; rx++) {
for (int rx = 0; rx < cSim.kmaxX; rx++) {
float kx = rx * cSim.recipBoxSizeX;
for (int ry = lowry; ry < numRy; ry++) {
for (int ry = lowry; ry < cSim.kmaxY; ry++) {
float ky = ry * cSim.recipBoxSizeY;
float phase = apos.x*kx;
float2 tab_xy = make_float2(cos(phase), sin(phase));
phase = apos.y*ky;
tab_xy = MultofFloat2(tab_xy, make_float2(cos(phase), sin(phase)));
for (int rz = lowrz; rz < numRz; rz++) {
for (int rz = lowrz; rz < cSim.kmaxZ; rz++) {
float kz = rz * cSim.recipBoxSizeZ;
// Compute the force contribution of this wave vector.
int index = rx*(numRy*2-1)*(numRz*2-1) + (ry+numRy-1)*(numRz*2-1) + (rz+numRz-1);
int index = rx*(cSim.kmaxY*2-1)*(cSim.kmaxZ*2-1) + (ry+cSim.kmaxY-1)*(cSim.kmaxZ*2-1) + (rz+cSim.kmaxZ-1);
float k2 = kx*kx + ky*ky + kz*kz;
float ak = exp(k2*cSim.factorEwald) / k2;
phase = apos.z*kz;
......@@ -139,9 +137,9 @@ __global__ void kCalculateEwaldFastForces_kernel()
force.x += 2 * recipCoeff * dEdR * kx;
force.y += 2 * recipCoeff * dEdR * ky;
force.z += 2 * recipCoeff * dEdR * kz;
lowrz = 1 - numRz;
lowrz = 1 - cSim.kmaxZ;
}
lowry = 1 - numRy;
lowry = 1 - cSim.kmaxY;
}
}
......
......@@ -49,13 +49,13 @@ __global__ void kCalculateCDLJEwaldReciprocalForces_kernel()
int lowry = 0;
int lowrz = 1;
for(int rx = 0; rx < cSim.kmax; rx++)
for(int rx = 0; rx < cSim.kmaxX; rx++)
{
float kx = rx*cSim.recipBoxSizeX;
for(int ry = lowry; ry < cSim.kmax; ry++)
for(int ry = lowry; ry < cSim.kmaxY; ry++)
{
float ky = ry*cSim.recipBoxSizeY;
for (int rz = lowrz; rz < cSim.kmax; rz++)
for (int rz = lowrz; rz < cSim.kmaxZ; rz++)
{
float kz = rz*cSim.recipBoxSizeZ;
float k2 = kx*kx + ky*ky + kz*kz;
......@@ -73,9 +73,9 @@ __global__ void kCalculateCDLJEwaldReciprocalForces_kernel()
af.y -= ky*f;
af.z -= kz*f;
lowrz = 1 - cSim.kmax;
lowrz = 1 - cSim.kmaxZ;
}
lowry = 1 - cSim.kmax;
lowry = 1 - cSim.kmaxY;
}
}
atomID2++;
......
......@@ -43,7 +43,6 @@ __global__ void METHOD_NAME(kCalculateCDLJ, Forces_kernel)(unsigned int* workUni
#endif
#ifdef USE_EWALD
float alphaEwald = 3.123413;
float PI = 3.14159265358979323846f;
float SQRT_PI = sqrt(PI);
#endif
......@@ -112,7 +111,7 @@ __global__ void METHOD_NAME(kCalculateCDLJ, Forces_kernel)(unsigned int* workUni
#ifdef USE_CUTOFF
#ifdef USE_EWALD
float r = sqrt(r2);
float alphaR = alphaEwald * r;
float alphaR = cSim.alphaEwald * r;
dEdR += apos.w * psA[j].q * invR * (erfc(alphaR) + 2.0 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI );
#else
dEdR += apos.w * psA[j].q * (invR - 2.0f * cSim.reactionFieldK * r2);
......@@ -161,7 +160,7 @@ __global__ void METHOD_NAME(kCalculateCDLJ, Forces_kernel)(unsigned int* workUni
#ifdef USE_CUTOFF
#ifdef USE_EWALD
float r = sqrt(r2);
float alphaR = alphaEwald * r;
float alphaR = cSim.alphaEwald * r;
dEdR += apos.w * psA[j].q * invR * (erfc(alphaR) + 2.0 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI );
#else
dEdR += apos.w * psA[j].q * (invR - 2.0f * cSim.reactionFieldK * r2);
......@@ -259,7 +258,7 @@ __global__ void METHOD_NAME(kCalculateCDLJ, Forces_kernel)(unsigned int* workUni
#ifdef USE_CUTOFF
#ifdef USE_EWALD
float r = sqrt(r2);
float alphaR = alphaEwald * r;
float alphaR = cSim.alphaEwald * r;
dEdR += apos.w * psA[tj].q * invR * (erfc(alphaR) + 2.0 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI );
#else
dEdR += apos.w * psA[tj].q * (invR - 2.0f * cSim.reactionFieldK * r2);
......@@ -314,7 +313,7 @@ __global__ void METHOD_NAME(kCalculateCDLJ, Forces_kernel)(unsigned int* workUni
#ifdef USE_CUTOFF
#ifdef USE_EWALD
float r = sqrt(r2);
float alphaR = alphaEwald * r;
float alphaR = cSim.alphaEwald * r;
dEdR += apos.w * psA[j].q * invR * (erfc(alphaR) + 2.0 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI );
#else
dEdR += apos.w * psA[j].q * (invR - 2.0f * cSim.reactionFieldK * r2);
......@@ -405,7 +404,7 @@ __global__ void METHOD_NAME(kCalculateCDLJ, Forces_kernel)(unsigned int* workUni
#ifdef USE_CUTOFF
#ifdef USE_EWALD
float r = sqrt(r2);
float alphaR = alphaEwald * r;
float alphaR = cSim.alphaEwald * r;
dEdR += apos.w * psA[tj].q * invR * (erfc(alphaR) + 2.0 * alphaR * exp ( - alphaR * alphaR) / SQRT_PI );
#else
dEdR += apos.w * psA[tj].q * (invR - 2.0f * cSim.reactionFieldK * r2);
......
......@@ -369,6 +369,7 @@ void testEwald() {
nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
const double cutoff = 2.0;
nonbonded->setCutoffDistance(cutoff);
nonbonded->setEwaldErrorTolerance(TOL);
nonbonded->setPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6));
system.addForce(nonbonded);
OpenMMContext context(system, integrator, platform);
......@@ -379,9 +380,9 @@ void testEwald() {
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3( 123.711, -64.1877, 302.716), forces[1], TOL);
ASSERT_EQUAL_TOL(-217.276, state.getPotentialEnergy(), TOL);
ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 123.711, -64.1877, 302.716), forces[1], 10*TOL);
// ASSERT_EQUAL_TOL(-217.276, state.getPotentialEnergy(), 10*TOL);
}
......
......@@ -392,7 +392,17 @@ void ReferenceCalcNonbondedForceKernel::initialize(const System& system, const N
neighborList = NULL;
else
neighborList = new NeighborList();
if (nonbondedMethod == Ewald) {
RealOpenMM ewaldErrorTol = (RealOpenMM) force.getEwaldErrorTolerance();
ewaldAlpha = (RealOpenMM) (std::sqrt(-std::log(ewaldErrorTol))/nonbondedCutoff);
RealOpenMM mx = periodicBoxSize[0]/nonbondedCutoff;
RealOpenMM my = periodicBoxSize[1]/nonbondedCutoff;
RealOpenMM mz = periodicBoxSize[2]/nonbondedCutoff;
RealOpenMM pi = (RealOpenMM) 3.1415926535897932385;
kmax[0] = std::ceil(-(mx/pi)*std::log(ewaldErrorTol));
kmax[1] = std::ceil(-(my/pi)*std::log(ewaldErrorTol));
kmax[2] = std::ceil(-(mz/pi)*std::log(ewaldErrorTol));
}
}
void ReferenceCalcNonbondedForceKernel::executeForces(OpenMMContextImpl& context) {
......@@ -407,13 +417,9 @@ void ReferenceCalcNonbondedForceKernel::executeForces(OpenMMContextImpl& context
}
if (periodic||ewald)
clj.setPeriodic(periodicBoxSize);
if (ewald) {
clj.setRecipVectors();
clj.calculateEwaldIxn(numParticles, posData, particleParamArray, exclusionArray, 0, forceData, 0, 0);
}
else {
clj.calculatePairIxn(numParticles, posData, particleParamArray, exclusionArray, 0, forceData, 0, 0);
}
if (ewald)
clj.setUseEwald(ewaldAlpha, kmax[0], kmax[1], kmax[2]);
clj.calculatePairIxn(numParticles, posData, particleParamArray, exclusionArray, 0, forceData, 0, 0);
ReferenceBondForce refBondForce;
ReferenceLJCoulomb14 nonbonded14;
if (nonbondedMethod != NoCutoff)
......@@ -434,13 +440,9 @@ double ReferenceCalcNonbondedForceKernel::executeEnergy(OpenMMContextImpl& conte
}
if (periodic || ewald)
clj.setPeriodic(periodicBoxSize);
if (ewald) {
clj.setRecipVectors();
clj.calculateEwaldIxn(numParticles, posData, particleParamArray, exclusionArray, 0, forceData, 0, &energy);
}
else {
clj.calculatePairIxn(numParticles, posData, particleParamArray, exclusionArray, 0, forceData, 0, &energy);
}
if (ewald)
clj.setUseEwald(ewaldAlpha, kmax[0], kmax[1], kmax[2]);
clj.calculatePairIxn(numParticles, posData, particleParamArray, exclusionArray, 0, forceData, 0, &energy);
ReferenceBondForce refBondForce;
ReferenceLJCoulomb14 nonbonded14;
if (nonbondedMethod != NoCutoff)
......
......@@ -266,7 +266,8 @@ private:
int numParticles, num14;
int **exclusionArray, **bonded14IndexArray;
RealOpenMM **particleParamArray, **bonded14ParamArray;
RealOpenMM nonbondedCutoff, periodicBoxSize[3];
RealOpenMM nonbondedCutoff, periodicBoxSize[3], ewaldAlpha;
int kmax[3];
std::vector<std::set<int> > exclusions;
NonbondedMethod nonbondedMethod;
NeighborList* neighborList;
......
......@@ -44,7 +44,7 @@ using std::vector;
--------------------------------------------------------------------------------------- */
ReferenceLJCoulombIxn::ReferenceLJCoulombIxn( ) : cutoff(false), periodic(false) {
ReferenceLJCoulombIxn::ReferenceLJCoulombIxn( ) : cutoff(false), periodic(false), ewald(false) {
// ---------------------------------------------------------------------------------------
......@@ -119,6 +119,25 @@ ReferenceLJCoulombIxn::~ReferenceLJCoulombIxn( ){
}
/**---------------------------------------------------------------------------------------
Set the force to use Ewald summation.
@param alpha the Ewald separation parameter
@param kmaxx the largest wave vector in the x direction
@param kmaxy the largest wave vector in the y direction
@param kmaxz the largest wave vector in the z direction
--------------------------------------------------------------------------------------- */
void ReferenceLJCoulombIxn::setUseEwald(RealOpenMM alpha, int kmaxx, int kmaxy, int kmaxz) {
alphaEwald = alpha;
numRx = kmaxx;
numRy = kmaxy;
numRz = kmaxz;
ewald = true;
}
/**---------------------------------------------------------------------------------------
Calculate parameters for LJ Coulomb ixn
......@@ -171,44 +190,6 @@ int ReferenceLJCoulombIxn::getDerivedParameters( RealOpenMM c6, RealOpenMM c12,
return ReferenceForce::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
Set the reciprocal space vectors to use with Ewald
// Currently a dumb routine, vectors are set in calculateEwaldIxn
@return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */
int ReferenceLJCoulombIxn::setRecipVectors() {
return ReferenceForce::DefaultReturn;
}
/**---------------------------------------------------------------------------------------
Calculate the Ewald parameter based on the cutoff and the desired tolerance using
erfc( alpha*cutoff )/cutoff < tolerance
@return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */
/* int ReferenceLJCoulombIxn::setAlphaEwald(RealOpenMM cutoff, RealOpenMM tolerance,
RealOpenMM alphaEwald) {
alphaEwald = 1.0f;
while ( erfc(alphaEwald*cutoff) >= tolerance*cutoff) {
alphaEwald= 1.2 * alphaEwald;
}
return ReferenceForce::DefaultReturn;
}
*/
/**---------------------------------------------------------------------------------------
Calculate Ewald ixn
......@@ -232,20 +213,13 @@ int ReferenceLJCoulombIxn::getDerivedParameters( RealOpenMM c6, RealOpenMM c12,
int ReferenceLJCoulombIxn::calculateEwaldIxn( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const {
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy) const {
#include "../SimTKUtilities/RealTypeSimTk.h"
typedef std::complex<RealOpenMM> d_complex;
// Number of R-vectors (real space vectors)
// to be calculated automatically eventually from alphaEwald and desired precision
int numRx = 20+1;
int numRy = 20+1;
int numRz = 20+1;
int kmax = std::max(numRx, std::max(numRy,numRz));
static const RealOpenMM alphaEwald = (RealOpenMM) 3.123413;
RealOpenMM factorEwald = -1 / (4*alphaEwald*alphaEwald);
......@@ -466,6 +440,8 @@ int ReferenceLJCoulombIxn::calculatePairIxn( int numberOfAtoms, RealOpenMM** ato
RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const {
if (ewald)
return calculateEwaldIxn(numberOfAtoms, atomCoordinates, atomParameters, exclusions, fixedParameters, forces, energyByAtom, totalEnergy);
if (cutoff) {
for (int i = 0; i < (int) neighborList->size(); i++) {
OpenMM::AtomPair pair = (*neighborList)[i];
......
......@@ -36,10 +36,13 @@ class ReferenceLJCoulombIxn : public ReferencePairIxn {
bool cutoff;
bool periodic;
bool ewald;
const OpenMM::NeighborList* neighborList;
RealOpenMM periodicBoxSize[3];
RealOpenMM cutoffDistance;
RealOpenMM krf, crf;
RealOpenMM alphaEwald;
int numRx, numRy, numRz;
// parameter indices
......@@ -116,15 +119,16 @@ class ReferenceLJCoulombIxn : public ReferencePairIxn {
/**---------------------------------------------------------------------------------------
Set the reciprocal vectors to use with Ewald
Set the force to use Ewald summation.
@param
@return ReferenceForce::DefaultReturn
@param alpha the Ewald separation parameter
@param kmaxx the largest wave vector in the x direction
@param kmaxy the largest wave vector in the y direction
@param kmaxz the largest wave vector in the z direction
--------------------------------------------------------------------------------------- */
int setRecipVectors();
void setUseEwald(RealOpenMM alpha, int kmaxx, int kmaxy, int kmaxz);
/**---------------------------------------------------------------------------------------
......@@ -172,7 +176,8 @@ class ReferenceLJCoulombIxn : public ReferencePairIxn {
RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const;
private:
/**---------------------------------------------------------------------------------------
Calculate Ewald ixn
......@@ -188,7 +193,7 @@ class ReferenceLJCoulombIxn : public ReferencePairIxn {
@param forces force array (forces added)
@param energyByAtom atom energy
@param totalEnergy total energy
@return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */
......
......@@ -72,30 +72,7 @@ class ReferencePairIxn {
RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const = 0;
/**---------------------------------------------------------------------------------------
Calculate Ewald ixn
@param numberOfAtoms number of atoms
@param atomCoordinates atom coordinates
@param atomParameters atom parameters (charges, c6, c12, ...) atomParameters[atomIndex][paramterIndex]
@param exclusions atom exclusion indices exclusions[atomIndex][atomToExcludeIndex]
@param fixedParameters non-atom parameters
@param forces force array (forces added)
@param energyByAtom atom energy
@param totalEnergy total energy
@return ReferenceForce::DefaultReturn
--------------------------------------------------------------------------------------- */
virtual int calculateEwaldIxn( int numberOfAtoms, RealOpenMM** atomCoordinates,
RealOpenMM** atomParameters, int** exclusions,
RealOpenMM* fixedParameters, RealOpenMM** forces,
RealOpenMM* energyByAtom, RealOpenMM* totalEnergy ) const = 0;
};
// ---------------------------------------------------------------------------------------
......
......@@ -62,6 +62,7 @@ void testEwald() {
const double cutoff = 2.0;
nonbonded->setCutoffDistance(cutoff);
nonbonded->setPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6));
nonbonded->setEwaldErrorTolerance(TOL);
system.addForce(nonbonded);
OpenMMContext context(system, integrator, platform);
vector<Vec3> positions(2);
......@@ -73,8 +74,8 @@ void testEwald() {
cout << "force 0: " << forces[0] << endl;
cout << "force 1: " << forces[1] << endl;
cout << "PotentialEnergy: " << state.getPotentialEnergy() << endl;
ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(123.711, -64.1877, 302.716), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(-123.711, 64.1877, -302.716), forces[0], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(123.711, -64.1877, 302.716), forces[1], 10*TOL);
// const double eps = 78.3;
// const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
// const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
......
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