Commit 91247209 authored by Peter Eastman's avatar Peter Eastman
Browse files

OpenCL implementation of multiple time step integrators

parent 85636c52
...@@ -816,6 +816,8 @@ void CudaCalcNonbondedForceKernel::initialize(const System& system, const Nonbon ...@@ -816,6 +816,8 @@ void CudaCalcNonbondedForceKernel::initialize(const System& system, const Nonbon
method = PERIODIC; method = PERIODIC;
} }
if (force.getNonbondedMethod() == NonbondedForce::Ewald || force.getNonbondedMethod() == NonbondedForce::PME) { if (force.getNonbondedMethod() == NonbondedForce::Ewald || force.getNonbondedMethod() == NonbondedForce::PME) {
if (force.getReciprocalSpaceForceGroup() != 0)
throw OpenMMException("CudaPlatform does not support force groups");
if (force.getNonbondedMethod() == NonbondedForce::Ewald) { if (force.getNonbondedMethod() == NonbondedForce::Ewald) {
double alpha; double alpha;
int kmaxx, kmaxy, kmaxz; int kmaxx, kmaxy, kmaxz;
......
...@@ -99,6 +99,9 @@ void CudaPlatform::contextCreated(ContextImpl& context, const map<string, string ...@@ -99,6 +99,9 @@ void CudaPlatform::contextCreated(ContextImpl& context, const map<string, string
for (int i = 0; i < system.getNumParticles(); i++) for (int i = 0; i < system.getNumParticles(); i++)
if (system.isVirtualSite(i)) if (system.isVirtualSite(i))
throw OpenMMException("CudaPlatform does not support virtual sites"); throw OpenMMException("CudaPlatform does not support virtual sites");
for (int i = 0; i < system.getNumForces(); i++)
if (system.getForce(i).getForceGroup() != 0)
throw OpenMMException("CudaPlatform does not support force groups");
unsigned int device = 0; unsigned int device = 0;
const string& devicePropValue = (properties.find(CudaDevice()) == properties.end() ? const string& devicePropValue = (properties.find(CudaDevice()) == properties.end() ?
getPropertyDefaultValue(CudaDevice()) : properties.find(CudaDevice())->second); getPropertyDefaultValue(CudaDevice()) : properties.find(CudaDevice())->second);
......
...@@ -43,10 +43,11 @@ OpenCLBondedUtilities::~OpenCLBondedUtilities() { ...@@ -43,10 +43,11 @@ OpenCLBondedUtilities::~OpenCLBondedUtilities() {
delete bufferIndices[i]; delete bufferIndices[i];
} }
void OpenCLBondedUtilities::addInteraction(const vector<vector<int> >& atoms, const string& source) { void OpenCLBondedUtilities::addInteraction(const vector<vector<int> >& atoms, const string& source, int group) {
if (atoms.size() > 0) { if (atoms.size() > 0) {
forceAtoms.push_back(atoms); forceAtoms.push_back(atoms);
forceSource.push_back(source); forceSource.push_back(source);
forceGroup.push_back(group);
int width = 1; int width = 1;
while (width < atoms[0].size()) while (width < atoms[0].size())
width *= 2; width *= 2;
...@@ -154,7 +155,7 @@ void OpenCLBondedUtilities::initialize(const System& system) { ...@@ -154,7 +155,7 @@ void OpenCLBondedUtilities::initialize(const System& system) {
const vector<int>& set = *iter; const vector<int>& set = *iter;
int setSize = set.size(); int setSize = set.size();
stringstream s; stringstream s;
s<<"__kernel void computeBondedForces(__global float4* restrict forceBuffers, __global float* restrict energyBuffer, __global const float4* restrict posq"; s<<"__kernel void computeBondedForces(__global float4* restrict forceBuffers, __global float* restrict energyBuffer, __global const float4* restrict posq, int groups";
for (int i = 0; i < setSize; i++) { for (int i = 0; i < setSize; i++) {
int force = set[i]; int force = set[i];
string indexType = "uint"+(indexWidth[force] == 1 ? "" : OpenCLExpressionUtilities::intToString(indexWidth[force])); string indexType = "uint"+(indexWidth[force] == 1 ? "" : OpenCLExpressionUtilities::intToString(indexWidth[force]));
...@@ -167,7 +168,7 @@ void OpenCLBondedUtilities::initialize(const System& system) { ...@@ -167,7 +168,7 @@ void OpenCLBondedUtilities::initialize(const System& system) {
s<<"float energy = 0.0f;\n"; s<<"float energy = 0.0f;\n";
for (int i = 0; i < setSize; i++) { for (int i = 0; i < setSize; i++) {
int force = set[i]; int force = set[i];
s<<createForceSource(i, forceAtoms[force].size(), forceAtoms[force][0].size(), forceSource[force]); s<<createForceSource(i, forceAtoms[force].size(), forceAtoms[force][0].size(), forceGroup[force], forceSource[force]);
} }
s<<"energyBuffer[get_global_id(0)] += energy;\n"; s<<"energyBuffer[get_global_id(0)] += energy;\n";
s<<"}\n"; s<<"}\n";
...@@ -180,7 +181,7 @@ void OpenCLBondedUtilities::initialize(const System& system) { ...@@ -180,7 +181,7 @@ void OpenCLBondedUtilities::initialize(const System& system) {
forceSource.clear(); forceSource.clear();
} }
string OpenCLBondedUtilities::createForceSource(int forceIndex, int numBonds, int numAtoms, const string& computeForce) { string OpenCLBondedUtilities::createForceSource(int forceIndex, int numBonds, int numAtoms, int group, const string& computeForce) {
maxBonds = max(maxBonds, numBonds); maxBonds = max(maxBonds, numBonds);
int width = 1; int width = 1;
while (width < numAtoms) while (width < numAtoms)
...@@ -198,6 +199,7 @@ string OpenCLBondedUtilities::createForceSource(int forceIndex, int numBonds, in ...@@ -198,6 +199,7 @@ string OpenCLBondedUtilities::createForceSource(int forceIndex, int numBonds, in
suffix = suffix16; suffix = suffix16;
string indexType = "uint"+(width == 1 ? "" : OpenCLExpressionUtilities::intToString(width)); string indexType = "uint"+(width == 1 ? "" : OpenCLExpressionUtilities::intToString(width));
stringstream s; stringstream s;
s<<"if ((groups&"<<(1<<group)<<") != 0)\n";
s<<"for (unsigned int index = get_global_id(0); index < "<<numBonds<<"; index += get_global_size(0)) {\n"; s<<"for (unsigned int index = get_global_id(0); index < "<<numBonds<<"; index += get_global_size(0)) {\n";
s<<" "<<indexType<<" atoms = atomIndices"<<forceIndex<<"[index];\n"; s<<" "<<indexType<<" atoms = atomIndices"<<forceIndex<<"[index];\n";
s<<" "<<indexType<<" buffers = bufferIndices"<<forceIndex<<"[index];\n"; s<<" "<<indexType<<" buffers = bufferIndices"<<forceIndex<<"[index];\n";
...@@ -218,7 +220,7 @@ string OpenCLBondedUtilities::createForceSource(int forceIndex, int numBonds, in ...@@ -218,7 +220,7 @@ string OpenCLBondedUtilities::createForceSource(int forceIndex, int numBonds, in
return s.str(); return s.str();
} }
void OpenCLBondedUtilities::computeInteractions() { void OpenCLBondedUtilities::computeInteractions(int groups) {
if (!hasInitializedKernels) { if (!hasInitializedKernels) {
hasInitializedKernels = true; hasInitializedKernels = true;
for (int i = 0; i < (int) forceSets.size(); i++) { for (int i = 0; i < (int) forceSets.size(); i++) {
...@@ -227,6 +229,7 @@ void OpenCLBondedUtilities::computeInteractions() { ...@@ -227,6 +229,7 @@ void OpenCLBondedUtilities::computeInteractions() {
kernel.setArg<cl::Buffer>(index++, context.getForceBuffers().getDeviceBuffer()); kernel.setArg<cl::Buffer>(index++, context.getForceBuffers().getDeviceBuffer());
kernel.setArg<cl::Buffer>(index++, context.getEnergyBuffer().getDeviceBuffer()); kernel.setArg<cl::Buffer>(index++, context.getEnergyBuffer().getDeviceBuffer());
kernel.setArg<cl::Buffer>(index++, context.getPosq().getDeviceBuffer()); kernel.setArg<cl::Buffer>(index++, context.getPosq().getDeviceBuffer());
index++;
for (int j = 0; j < (int) forceSets[i].size(); j++) { for (int j = 0; j < (int) forceSets[i].size(); j++) {
kernel.setArg<cl::Buffer>(index++, atomIndices[forceSets[i][j]]->getDeviceBuffer()); kernel.setArg<cl::Buffer>(index++, atomIndices[forceSets[i][j]]->getDeviceBuffer());
kernel.setArg<cl::Buffer>(index++, bufferIndices[forceSets[i][j]]->getDeviceBuffer()); kernel.setArg<cl::Buffer>(index++, bufferIndices[forceSets[i][j]]->getDeviceBuffer());
...@@ -235,6 +238,8 @@ void OpenCLBondedUtilities::computeInteractions() { ...@@ -235,6 +238,8 @@ void OpenCLBondedUtilities::computeInteractions() {
kernel.setArg<cl::Memory>(index++, *arguments[j]); kernel.setArg<cl::Memory>(index++, *arguments[j]);
} }
} }
for (int i = 0; i < (int) kernels.size(); i++) for (int i = 0; i < (int) kernels.size(); i++) {
kernels[i].setArg<cl_int>(3, groups);
context.executeKernel(kernels[i], maxBonds); context.executeKernel(kernels[i], maxBonds);
}
} }
...@@ -88,8 +88,9 @@ public: ...@@ -88,8 +88,9 @@ public:
* @param atoms this should have one entry for each bond, and that entry should contain the list * @param atoms this should have one entry for each bond, and that entry should contain the list
* of atoms involved in the bond. Every entry must have the same number of atoms. * of atoms involved in the bond. Every entry must have the same number of atoms.
* @param source the code to evaluate the interaction * @param source the code to evaluate the interaction
* @param group the force group in which the interaction should be calculated
*/ */
void addInteraction(const std::vector<std::vector<int> >& atoms, const std::string& source); void addInteraction(const std::vector<std::vector<int> >& atoms, const std::string& source, int group);
/** /**
* Add an argument that should be passed to the interaction kernel. * Add an argument that should be passed to the interaction kernel.
* *
...@@ -111,15 +112,18 @@ public: ...@@ -111,15 +112,18 @@ public:
} }
/** /**
* Compute the bonded interactions. * Compute the bonded interactions.
*
* @param groups a set of bit flags for which force groups to include
*/ */
void computeInteractions(); void computeInteractions(int groups);
private: private:
std::string createForceSource(int forceIndex, int numBonds, int numAtoms, const std::string& computeForce); std::string createForceSource(int forceIndex, int numBonds, int numAtoms, int group, const std::string& computeForce);
OpenCLContext& context; OpenCLContext& context;
std::vector<cl::Kernel> kernels; std::vector<cl::Kernel> kernels;
std::vector<std::vector<std::vector<int> > > forceAtoms; std::vector<std::vector<std::vector<int> > > forceAtoms;
std::vector<int> indexWidth; std::vector<int> indexWidth;
std::vector<std::string> forceSource; std::vector<std::string> forceSource;
std::vector<int> forceGroup;
std::vector<std::vector<int> > forceSets; std::vector<std::vector<int> > forceSets;
std::vector<cl::Memory*> arguments; std::vector<cl::Memory*> arguments;
std::vector<std::string> argTypes; std::vector<std::string> argTypes;
......
...@@ -94,18 +94,22 @@ void OpenCLCalcForcesAndEnergyKernel::initialize(const System& system) { ...@@ -94,18 +94,22 @@ void OpenCLCalcForcesAndEnergyKernel::initialize(const System& system) {
} }
void OpenCLCalcForcesAndEnergyKernel::beginComputation(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) { void OpenCLCalcForcesAndEnergyKernel::beginComputation(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
OpenCLNonbondedUtilities& nb = cl.getNonbondedUtilities();
bool includeNonbonded = ((groups&(1<<nb.getForceGroup())) != 0);
cl.setAtomsWereReordered(false); cl.setAtomsWereReordered(false);
if (cl.getNonbondedUtilities().getUseCutoff() && cl.getComputeForceCount()%100 == 0) { if (nb.getUseCutoff() && includeNonbonded && cl.getComputeForceCount()%100 == 0) {
cl.reorderAtoms(); cl.reorderAtoms();
cl.getNonbondedUtilities().updateNeighborListSize(); nb.updateNeighborListSize();
}
cl.setComputeForceCount(cl.getComputeForceCount()+1); cl.setComputeForceCount(cl.getComputeForceCount()+1);
}
cl.clearAutoclearBuffers(); cl.clearAutoclearBuffers();
cl.getNonbondedUtilities().prepareInteractions(); if (includeNonbonded)
nb.prepareInteractions();
} }
double OpenCLCalcForcesAndEnergyKernel::finishComputation(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) { double OpenCLCalcForcesAndEnergyKernel::finishComputation(ContextImpl& context, bool includeForces, bool includeEnergy, int groups) {
cl.getBondedUtilities().computeInteractions(); cl.getBondedUtilities().computeInteractions(groups);
if ((groups&(1<<cl.getNonbondedUtilities().getForceGroup())) != 0)
cl.getNonbondedUtilities().computeInteractions(); cl.getNonbondedUtilities().computeInteractions();
cl.reduceForces(); cl.reduceForces();
cl.getIntegrationUtilities().distributeForcesFromVirtualSites(); cl.getIntegrationUtilities().distributeForcesFromVirtualSites();
...@@ -293,7 +297,7 @@ void OpenCLCalcHarmonicBondForceKernel::initialize(const System& system, const H ...@@ -293,7 +297,7 @@ void OpenCLCalcHarmonicBondForceKernel::initialize(const System& system, const H
params->upload(paramVector); params->upload(paramVector);
map<string, string> replacements; map<string, string> replacements;
replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float2"); replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float2");
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::harmonicBondForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::harmonicBondForce, replacements), force.getForceGroup());
cl.addForce(new OpenCLBondForceInfo(0, force)); cl.addForce(new OpenCLBondForceInfo(0, force));
} }
...@@ -399,7 +403,7 @@ void OpenCLCalcCustomBondForceKernel::initialize(const System& system, const Cus ...@@ -399,7 +403,7 @@ void OpenCLCalcCustomBondForceKernel::initialize(const System& system, const Cus
compute << OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", ""); compute << OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", "");
map<string, string> replacements; map<string, string> replacements;
replacements["COMPUTE_FORCE"] = compute.str(); replacements["COMPUTE_FORCE"] = compute.str();
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customBondForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customBondForce, replacements), force.getForceGroup());
} }
double OpenCLCalcCustomBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double OpenCLCalcCustomBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -468,7 +472,7 @@ void OpenCLCalcHarmonicAngleForceKernel::initialize(const System& system, const ...@@ -468,7 +472,7 @@ void OpenCLCalcHarmonicAngleForceKernel::initialize(const System& system, const
params->upload(paramVector); params->upload(paramVector);
map<string, string> replacements; map<string, string> replacements;
replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float2"); replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float2");
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::harmonicAngleForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::harmonicAngleForce, replacements), force.getForceGroup());
cl.addForce(new OpenCLAngleForceInfo(0, force)); cl.addForce(new OpenCLAngleForceInfo(0, force));
} }
...@@ -575,7 +579,7 @@ void OpenCLCalcCustomAngleForceKernel::initialize(const System& system, const Cu ...@@ -575,7 +579,7 @@ void OpenCLCalcCustomAngleForceKernel::initialize(const System& system, const Cu
compute << OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", ""); compute << OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", "");
map<string, string> replacements; map<string, string> replacements;
replacements["COMPUTE_FORCE"] = compute.str(); replacements["COMPUTE_FORCE"] = compute.str();
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customAngleForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customAngleForce, replacements), force.getForceGroup());
} }
double OpenCLCalcCustomAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double OpenCLCalcCustomAngleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -646,7 +650,7 @@ void OpenCLCalcPeriodicTorsionForceKernel::initialize(const System& system, cons ...@@ -646,7 +650,7 @@ void OpenCLCalcPeriodicTorsionForceKernel::initialize(const System& system, cons
params->upload(paramVector); params->upload(paramVector);
map<string, string> replacements; map<string, string> replacements;
replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float4"); replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float4");
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::periodicTorsionForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::periodicTorsionForce, replacements), force.getForceGroup());
cl.addForce(new OpenCLPeriodicTorsionForceInfo(0, force)); cl.addForce(new OpenCLPeriodicTorsionForceInfo(0, force));
} }
...@@ -706,7 +710,7 @@ void OpenCLCalcRBTorsionForceKernel::initialize(const System& system, const RBTo ...@@ -706,7 +710,7 @@ void OpenCLCalcRBTorsionForceKernel::initialize(const System& system, const RBTo
params->upload(paramVector); params->upload(paramVector);
map<string, string> replacements; map<string, string> replacements;
replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float8"); replacements["PARAMS"] = cl.getBondedUtilities().addArgument(params->getDeviceBuffer(), "float8");
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::rbTorsionForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::rbTorsionForce, replacements), force.getForceGroup());
cl.addForce(new OpenCLRBTorsionForceInfo(0, force)); cl.addForce(new OpenCLRBTorsionForceInfo(0, force));
} }
...@@ -793,7 +797,7 @@ void OpenCLCalcCMAPTorsionForceKernel::initialize(const System& system, const CM ...@@ -793,7 +797,7 @@ void OpenCLCalcCMAPTorsionForceKernel::initialize(const System& system, const CM
replacements["COEFF"] = cl.getBondedUtilities().addArgument(coefficients->getDeviceBuffer(), "float4"); replacements["COEFF"] = cl.getBondedUtilities().addArgument(coefficients->getDeviceBuffer(), "float4");
replacements["MAP_POS"] = cl.getBondedUtilities().addArgument(mapPositions->getDeviceBuffer(), "int2"); replacements["MAP_POS"] = cl.getBondedUtilities().addArgument(mapPositions->getDeviceBuffer(), "int2");
replacements["MAPS"] = cl.getBondedUtilities().addArgument(torsionMaps->getDeviceBuffer(), "int"); replacements["MAPS"] = cl.getBondedUtilities().addArgument(torsionMaps->getDeviceBuffer(), "int");
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::cmapTorsionForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::cmapTorsionForce, replacements), force.getForceGroup());
cl.addForce(new OpenCLCMAPTorsionForceInfo(0, force)); cl.addForce(new OpenCLCMAPTorsionForceInfo(0, force));
} }
...@@ -902,7 +906,7 @@ void OpenCLCalcCustomTorsionForceKernel::initialize(const System& system, const ...@@ -902,7 +906,7 @@ void OpenCLCalcCustomTorsionForceKernel::initialize(const System& system, const
map<string, string> replacements; map<string, string> replacements;
replacements["COMPUTE_FORCE"] = compute.str(); replacements["COMPUTE_FORCE"] = compute.str();
replacements["M_PI"] = doubleToString(M_PI); replacements["M_PI"] = doubleToString(M_PI);
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customTorsionForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customTorsionForce, replacements), force.getForceGroup());
} }
double OpenCLCalcCustomTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double OpenCLCalcCustomTorsionForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -1170,7 +1174,7 @@ void OpenCLCalcNonbondedForceKernel::initialize(const System& system, const Nonb ...@@ -1170,7 +1174,7 @@ void OpenCLCalcNonbondedForceKernel::initialize(const System& system, const Nonb
// Add the interaction to the default nonbonded kernel. // Add the interaction to the default nonbonded kernel.
string source = cl.replaceStrings(OpenCLKernelSources::coulombLennardJones, defines); string source = cl.replaceStrings(OpenCLKernelSources::coulombLennardJones, defines);
cl.getNonbondedUtilities().addInteraction(useCutoff, usePeriodic, true, force.getCutoffDistance(), exclusionList, source); cl.getNonbondedUtilities().addInteraction(useCutoff, usePeriodic, true, force.getCutoffDistance(), exclusionList, source, force.getForceGroup());
if (hasLJ) if (hasLJ)
cl.getNonbondedUtilities().addParameter(OpenCLNonbondedUtilities::ParameterInfo("sigmaEpsilon", "float", 2, sizeof(cl_float2), sigmaEpsilon->getDeviceBuffer())); cl.getNonbondedUtilities().addParameter(OpenCLNonbondedUtilities::ParameterInfo("sigmaEpsilon", "float", 2, sizeof(cl_float2), sigmaEpsilon->getDeviceBuffer()));
...@@ -1192,7 +1196,7 @@ void OpenCLCalcNonbondedForceKernel::initialize(const System& system, const Nonb ...@@ -1192,7 +1196,7 @@ void OpenCLCalcNonbondedForceKernel::initialize(const System& system, const Nonb
exceptionParams->upload(exceptionParamsVector); exceptionParams->upload(exceptionParamsVector);
map<string, string> replacements; map<string, string> replacements;
replacements["PARAMS"] = cl.getBondedUtilities().addArgument(exceptionParams->getDeviceBuffer(), "float4"); replacements["PARAMS"] = cl.getBondedUtilities().addArgument(exceptionParams->getDeviceBuffer(), "float4");
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::nonbondedExceptions, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::nonbondedExceptions, replacements), force.getForceGroup());
} }
cl.addForce(new OpenCLNonbondedForceInfo(cl.getNonbondedUtilities().getNumForceBuffers(), force)); cl.addForce(new OpenCLNonbondedForceInfo(cl.getNonbondedUtilities().getNumForceBuffers(), force));
} }
...@@ -1252,7 +1256,7 @@ double OpenCLCalcNonbondedForceKernel::execute(ContextImpl& context, bool includ ...@@ -1252,7 +1256,7 @@ double OpenCLCalcNonbondedForceKernel::execute(ContextImpl& context, bool includ
} }
} }
} }
if (cosSinSums != NULL && cl.getContextIndex() == 0) { if (cosSinSums != NULL && cl.getContextIndex() == 0 && includeReciprocal) {
mm_float4 boxSize = cl.getPeriodicBoxSize(); mm_float4 boxSize = cl.getPeriodicBoxSize();
mm_float4 recipBoxSize = mm_float4((float) (2*M_PI/boxSize.x), (float) (2*M_PI/boxSize.y), (float) (2*M_PI/boxSize.z), 0); mm_float4 recipBoxSize = mm_float4((float) (2*M_PI/boxSize.x), (float) (2*M_PI/boxSize.y), (float) (2*M_PI/boxSize.z), 0);
float recipCoefficient = (float) (ONE_4PI_EPS0*4*M_PI/(boxSize.x*boxSize.y*boxSize.z)); float recipCoefficient = (float) (ONE_4PI_EPS0*4*M_PI/(boxSize.x*boxSize.y*boxSize.z));
...@@ -1263,7 +1267,7 @@ double OpenCLCalcNonbondedForceKernel::execute(ContextImpl& context, bool includ ...@@ -1263,7 +1267,7 @@ double OpenCLCalcNonbondedForceKernel::execute(ContextImpl& context, bool includ
ewaldForcesKernel.setArg<cl_float>(4, recipCoefficient); ewaldForcesKernel.setArg<cl_float>(4, recipCoefficient);
cl.executeKernel(ewaldForcesKernel, cl.getNumAtoms()); cl.executeKernel(ewaldForcesKernel, cl.getNumAtoms());
} }
if (pmeGrid != NULL && cl.getContextIndex() == 0) { if (pmeGrid != NULL && cl.getContextIndex() == 0 && includeReciprocal) {
mm_float4 boxSize = cl.getPeriodicBoxSize(); mm_float4 boxSize = cl.getPeriodicBoxSize();
mm_float4 invBoxSize = cl.getInvPeriodicBoxSize(); mm_float4 invBoxSize = cl.getInvPeriodicBoxSize();
pmeUpdateBsplinesKernel.setArg<mm_float4>(4, boxSize); pmeUpdateBsplinesKernel.setArg<mm_float4>(4, boxSize);
...@@ -1443,7 +1447,7 @@ void OpenCLCalcCustomNonbondedForceKernel::initialize(const System& system, cons ...@@ -1443,7 +1447,7 @@ void OpenCLCalcCustomNonbondedForceKernel::initialize(const System& system, cons
map<string, string> replacements; map<string, string> replacements;
replacements["COMPUTE_FORCE"] = compute.str(); replacements["COMPUTE_FORCE"] = compute.str();
string source = cl.replaceStrings(OpenCLKernelSources::customNonbonded, replacements); string source = cl.replaceStrings(OpenCLKernelSources::customNonbonded, replacements);
cl.getNonbondedUtilities().addInteraction(useCutoff, usePeriodic, true, force.getCutoffDistance(), exclusionList, source); cl.getNonbondedUtilities().addInteraction(useCutoff, usePeriodic, true, force.getCutoffDistance(), exclusionList, source, force.getForceGroup());
for (int i = 0; i < (int) params->getBuffers().size(); i++) { for (int i = 0; i < (int) params->getBuffers().size(); i++) {
const OpenCLNonbondedUtilities::ParameterInfo& buffer = params->getBuffers()[i]; const OpenCLNonbondedUtilities::ParameterInfo& buffer = params->getBuffers()[i];
cl.getNonbondedUtilities().addParameter(OpenCLNonbondedUtilities::ParameterInfo(prefix+"params"+intToString(i+1), buffer.getComponentType(), buffer.getNumComponents(), buffer.getSize(), buffer.getMemory())); cl.getNonbondedUtilities().addParameter(OpenCLNonbondedUtilities::ParameterInfo(prefix+"params"+intToString(i+1), buffer.getComponentType(), buffer.getNumComponents(), buffer.getSize(), buffer.getMemory()));
...@@ -1538,7 +1542,7 @@ void OpenCLCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOB ...@@ -1538,7 +1542,7 @@ void OpenCLCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOB
bool useCutoff = (force.getNonbondedMethod() != GBSAOBCForce::NoCutoff); bool useCutoff = (force.getNonbondedMethod() != GBSAOBCForce::NoCutoff);
bool usePeriodic = (force.getNonbondedMethod() != GBSAOBCForce::NoCutoff && force.getNonbondedMethod() != GBSAOBCForce::CutoffNonPeriodic); bool usePeriodic = (force.getNonbondedMethod() != GBSAOBCForce::NoCutoff && force.getNonbondedMethod() != GBSAOBCForce::CutoffNonPeriodic);
string source = OpenCLKernelSources::gbsaObc2; string source = OpenCLKernelSources::gbsaObc2;
nb.addInteraction(useCutoff, usePeriodic, false, force.getCutoffDistance(), vector<vector<int> >(), source); nb.addInteraction(useCutoff, usePeriodic, false, force.getCutoffDistance(), vector<vector<int> >(), source, force.getForceGroup());
nb.addParameter(OpenCLNonbondedUtilities::ParameterInfo("obcParams", "float", 2, sizeof(cl_float2), params->getDeviceBuffer()));; nb.addParameter(OpenCLNonbondedUtilities::ParameterInfo("obcParams", "float", 2, sizeof(cl_float2), params->getDeviceBuffer()));;
nb.addParameter(OpenCLNonbondedUtilities::ParameterInfo("bornForce", "float", 1, sizeof(cl_float), bornForce->getDeviceBuffer()));; nb.addParameter(OpenCLNonbondedUtilities::ParameterInfo("bornForce", "float", 1, sizeof(cl_float), bornForce->getDeviceBuffer()));;
cl.addForce(new OpenCLGBSAOBCForceInfo(nb.getNumForceBuffers(), force)); cl.addForce(new OpenCLGBSAOBCForceInfo(nb.getNumForceBuffers(), force));
...@@ -2351,7 +2355,7 @@ void OpenCLCalcCustomGBForceKernel::initialize(const System& system, const Custo ...@@ -2351,7 +2355,7 @@ void OpenCLCalcCustomGBForceKernel::initialize(const System& system, const Custo
globals->upload(globalParamValues); globals->upload(globalParamValues);
arguments.push_back(OpenCLNonbondedUtilities::ParameterInfo(prefix+"globals", "float", 1, sizeof(cl_float), globals->getDeviceBuffer())); arguments.push_back(OpenCLNonbondedUtilities::ParameterInfo(prefix+"globals", "float", 1, sizeof(cl_float), globals->getDeviceBuffer()));
} }
cl.getNonbondedUtilities().addInteraction(useCutoff, usePeriodic, force.getNumExclusions() > 0, force.getCutoffDistance(), exclusionList, source); cl.getNonbondedUtilities().addInteraction(useCutoff, usePeriodic, force.getNumExclusions() > 0, force.getCutoffDistance(), exclusionList, source, force.getForceGroup());
for (int i = 0; i < (int) parameters.size(); i++) for (int i = 0; i < (int) parameters.size(); i++)
cl.getNonbondedUtilities().addParameter(parameters[i]); cl.getNonbondedUtilities().addParameter(parameters[i]);
for (int i = 0; i < (int) arguments.size(); i++) for (int i = 0; i < (int) arguments.size(); i++)
...@@ -2660,7 +2664,7 @@ void OpenCLCalcCustomExternalForceKernel::initialize(const System& system, const ...@@ -2660,7 +2664,7 @@ void OpenCLCalcCustomExternalForceKernel::initialize(const System& system, const
compute << OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", ""); compute << OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", "");
map<string, string> replacements; map<string, string> replacements;
replacements["COMPUTE_FORCE"] = compute.str(); replacements["COMPUTE_FORCE"] = compute.str();
cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customExternalForce, replacements)); cl.getBondedUtilities().addInteraction(atoms, cl.replaceStrings(OpenCLKernelSources::customExternalForce, replacements), force.getForceGroup());
} }
double OpenCLCalcCustomExternalForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double OpenCLCalcCustomExternalForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -3536,6 +3540,8 @@ public: ...@@ -3536,6 +3540,8 @@ public:
void execute() { void execute() {
// Reorder the per-DOF variables to reflect the new atom order. // Reorder the per-DOF variables to reflect the new atom order.
if (perDofValues.getNumParameters() == 0)
return;
int numAtoms = cl.getNumAtoms(); int numAtoms = cl.getNumAtoms();
if (deviceValuesAreCurrent) if (deviceValuesAreCurrent)
perDofValues.getParameterValues(localPerDofValues); perDofValues.getParameterValues(localPerDofValues);
...@@ -3623,7 +3629,7 @@ string OpenCLIntegrateCustomStepKernel::createGlobalComputation(const string& va ...@@ -3623,7 +3629,7 @@ string OpenCLIntegrateCustomStepKernel::createGlobalComputation(const string& va
return OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", ""); return OpenCLExpressionUtilities::createExpressions(expressions, variables, functions, "temp", "");
} }
string OpenCLIntegrateCustomStepKernel::createPerDofComputation(const string& variable, const Lepton::ParsedExpression& expr, int component, CustomIntegrator& integrator) { string OpenCLIntegrateCustomStepKernel::createPerDofComputation(const string& variable, const Lepton::ParsedExpression& expr, int component, CustomIntegrator& integrator, const string& forceName) {
const string suffixes[] = {".x", ".y", ".z"}; const string suffixes[] = {".x", ".y", ".z"};
string suffix = suffixes[component]; string suffix = suffixes[component];
map<string, Lepton::ParsedExpression> expressions; map<string, Lepton::ParsedExpression> expressions;
...@@ -3643,7 +3649,7 @@ string OpenCLIntegrateCustomStepKernel::createPerDofComputation(const string& va ...@@ -3643,7 +3649,7 @@ string OpenCLIntegrateCustomStepKernel::createPerDofComputation(const string& va
map<string, string> variables; map<string, string> variables;
variables["x"] = "position"+suffix; variables["x"] = "position"+suffix;
variables["v"] = "velocity"+suffix; variables["v"] = "velocity"+suffix;
variables["f"] = "f"+suffix; variables[forceName] = "f"+suffix;
variables["gaussian"] = "gaussian"+suffix; variables["gaussian"] = "gaussian"+suffix;
variables["uniform"] = "uniform"+suffix; variables["uniform"] = "uniform"+suffix;
variables["m"] = "mass"; variables["m"] = "mass";
...@@ -3681,6 +3687,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr ...@@ -3681,6 +3687,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr
requiredUniform.resize(integrator.getNumComputations(), 0); requiredUniform.resize(integrator.getNumComputations(), 0);
needsForces.resize(numSteps, false); needsForces.resize(numSteps, false);
needsEnergy.resize(numSteps, false); needsEnergy.resize(numSteps, false);
forceGroup.resize(numSteps, -2);
invalidatesForces.resize(numSteps, false); invalidatesForces.resize(numSteps, false);
merged.resize(numSteps, false); merged.resize(numSteps, false);
modifiesParameters = false; modifiesParameters = false;
...@@ -3722,15 +3729,39 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr ...@@ -3722,15 +3729,39 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr
stepType.resize(numSteps); stepType.resize(numSteps);
vector<string> variable(numSteps); vector<string> variable(numSteps);
vector<Lepton::ParsedExpression> expression(numSteps); vector<Lepton::ParsedExpression> expression(numSteps);
vector<string> forceGroupName;
for (int i = 0; i < 32; i++) {
stringstream str;
str << "f" << i;
forceGroupName.push_back(str.str());
}
vector<string> forceName(numSteps, "f");
for (int step = 0; step < numSteps; step++) { for (int step = 0; step < numSteps; step++) {
string expr; string expr;
integrator.getComputationStep(step, stepType[step], variable[step], expr); integrator.getComputationStep(step, stepType[step], variable[step], expr);
if (expr.size() > 0) { if (expr.size() > 0) {
expression[step] = Lepton::Parser::parse(expr).optimize(); expression[step] = Lepton::Parser::parse(expr).optimize();
needsForces[step] = usesVariable(expression[step], "f"); if (usesVariable(expression[step], "f")) {
needsEnergy[step] = usesVariable(expression[step], "energy"); needsForces[step] = true;
forceGroup[step] = -1;
}
if (usesVariable(expression[step], "energy")) {
needsEnergy[step] = true;
forceGroup[step] = -1;
}
for (int i = 0; i < 32; i++) {
if (usesVariable(expression[step], forceGroupName[i])) {
if (forceGroup[step] != -2)
throw OpenMMException("A single computation step cannot depend on multiple force groups");
needsForces[step] = true;
forceGroup[step] = 1<<i;
forceName[step] = forceGroupName[i];
}
}
} }
invalidatesForces[step] = (stepType[step] == CustomIntegrator::ConstrainPositions || affectsForce.find(variable[step]) != affectsForce.end()); invalidatesForces[step] = (stepType[step] == CustomIntegrator::ConstrainPositions || affectsForce.find(variable[step]) != affectsForce.end());
if (forceGroup[step] == -2 && step > 0)
forceGroup[step] = forceGroup[step-1];
} }
// Determine how each step will represent the position (as just a value, or a value plus a delta). // Determine how each step will represent the position (as just a value, or a value plus a delta).
...@@ -3756,7 +3787,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr ...@@ -3756,7 +3787,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr
// Identify steps that can be merged into a single kernel. // Identify steps that can be merged into a single kernel.
for (int step = 1; step < numSteps; step++) { for (int step = 1; step < numSteps; step++) {
if ((needsForces[step] || needsEnergy[step]) && invalidatesForces[step-1]) if ((needsForces[step] || needsEnergy[step]) && (invalidatesForces[step-1] || forceGroup[step] != forceGroup[step-1]))
continue; continue;
if (stepType[step-1] == CustomIntegrator::ComputeGlobal && stepType[step] == CustomIntegrator::ComputeGlobal) if (stepType[step-1] == CustomIntegrator::ComputeGlobal && stepType[step] == CustomIntegrator::ComputeGlobal)
merged[step] = true; merged[step] = true;
...@@ -3784,7 +3815,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr ...@@ -3784,7 +3815,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr
for (int j = step; j < numSteps && (j == step || merged[j]); j++) { for (int j = step; j < numSteps && (j == step || merged[j]); j++) {
compute << "{\n"; compute << "{\n";
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
compute << createPerDofComputation(stepType[j] == CustomIntegrator::ComputePerDof ? variable[j] : "", expression[j], i, integrator); compute << createPerDofComputation(stepType[j] == CustomIntegrator::ComputePerDof ? variable[j] : "", expression[j], i, integrator, forceName[j]);
if (variable[j] == "x") { if (variable[j] == "x") {
if (storePosAsDelta[j]) { if (storePosAsDelta[j]) {
if (cl.getSupportsDoublePrecision()) if (cl.getSupportsDoublePrecision())
...@@ -3934,7 +3965,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr ...@@ -3934,7 +3965,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr
// Loop over computation steps in the integrator and execute them. // Loop over computation steps in the integrator and execute them.
for (int i = 0; i < numSteps; i++) { for (int i = 0; i < numSteps; i++) {
if ((needsForces[i] || needsEnergy[i]) && !forcesAreValid) { if ((needsForces[i] || needsEnergy[i]) && (!forcesAreValid || context.getLastForceGroups() != forceGroup[i])) {
// Recompute forces and/or energy. Figure out what is actually needed // Recompute forces and/or energy. Figure out what is actually needed
// between now and the next time they get invalidated again. // between now and the next time they get invalidated again.
...@@ -3952,7 +3983,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr ...@@ -3952,7 +3983,7 @@ void OpenCLIntegrateCustomStepKernel::execute(ContextImpl& context, CustomIntegr
break; break;
} }
recordChangedParameters(context); recordChangedParameters(context);
context.calcForcesAndEnergy(computeForce, false); context.calcForcesAndEnergy(computeForce, false, forceGroup[i]);
if (computeEnergy) if (computeEnergy)
cl.executeKernel(sumEnergyKernel, OpenCLContext::ThreadBlockSize, OpenCLContext::ThreadBlockSize); cl.executeKernel(sumEnergyKernel, OpenCLContext::ThreadBlockSize, OpenCLContext::ThreadBlockSize);
forcesAreValid = true; forcesAreValid = true;
......
...@@ -978,7 +978,7 @@ public: ...@@ -978,7 +978,7 @@ public:
private: private:
class ReorderListener; class ReorderListener;
std::string createGlobalComputation(const std::string& variable, const Lepton::ParsedExpression& expr, CustomIntegrator& integrator); std::string createGlobalComputation(const std::string& variable, const Lepton::ParsedExpression& expr, CustomIntegrator& integrator);
std::string createPerDofComputation(const std::string& variable, const Lepton::ParsedExpression& expr, int component, CustomIntegrator& integrator); std::string createPerDofComputation(const std::string& variable, const Lepton::ParsedExpression& expr, int component, CustomIntegrator& integrator, const std::string& forceName);
void recordChangedParameters(ContextImpl& context); void recordChangedParameters(ContextImpl& context);
OpenCLContext& cl; OpenCLContext& cl;
double prevStepSize; double prevStepSize;
...@@ -1000,6 +1000,7 @@ private: ...@@ -1000,6 +1000,7 @@ private:
std::vector<bool> needsEnergy; std::vector<bool> needsEnergy;
std::vector<bool> invalidatesForces; std::vector<bool> invalidatesForces;
std::vector<bool> merged; std::vector<bool> merged;
std::vector<int> forceGroup;
std::vector<int> requiredGaussian; std::vector<int> requiredGaussian;
std::vector<int> requiredUniform; std::vector<int> requiredUniform;
std::vector<std::string> parameterNames; std::vector<std::string> parameterNames;
......
...@@ -37,7 +37,7 @@ using namespace std; ...@@ -37,7 +37,7 @@ using namespace std;
OpenCLNonbondedUtilities::OpenCLNonbondedUtilities(OpenCLContext& context) : context(context), cutoff(-1.0), useCutoff(false), anyExclusions(false), OpenCLNonbondedUtilities::OpenCLNonbondedUtilities(OpenCLContext& context) : context(context), cutoff(-1.0), useCutoff(false), anyExclusions(false),
numForceBuffers(0), exclusionIndices(NULL), exclusionRowIndices(NULL), exclusions(NULL), interactingTiles(NULL), interactionFlags(NULL), numForceBuffers(0), exclusionIndices(NULL), exclusionRowIndices(NULL), exclusions(NULL), interactingTiles(NULL), interactionFlags(NULL),
interactionCount(NULL), blockCenter(NULL), blockBoundingBox(NULL) { interactionCount(NULL), blockCenter(NULL), blockBoundingBox(NULL), nonbondedForceGroup(0) {
// Decide how many thread blocks and force buffers to use. // Decide how many thread blocks and force buffers to use.
deviceIsCpu = (context.getDevice().getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU); deviceIsCpu = (context.getDevice().getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU);
...@@ -91,7 +91,7 @@ OpenCLNonbondedUtilities::~OpenCLNonbondedUtilities() { ...@@ -91,7 +91,7 @@ OpenCLNonbondedUtilities::~OpenCLNonbondedUtilities() {
delete blockBoundingBox; delete blockBoundingBox;
} }
void OpenCLNonbondedUtilities::addInteraction(bool usesCutoff, bool usesPeriodic, bool usesExclusions, double cutoffDistance, const vector<vector<int> >& exclusionList, const string& kernel) { void OpenCLNonbondedUtilities::addInteraction(bool usesCutoff, bool usesPeriodic, bool usesExclusions, double cutoffDistance, const vector<vector<int> >& exclusionList, const string& kernel, int forceGroup) {
if (cutoff != -1.0) { if (cutoff != -1.0) {
if (usesCutoff != useCutoff) if (usesCutoff != useCutoff)
throw OpenMMException("All Forces must agree on whether to use a cutoff"); throw OpenMMException("All Forces must agree on whether to use a cutoff");
...@@ -99,6 +99,8 @@ void OpenCLNonbondedUtilities::addInteraction(bool usesCutoff, bool usesPeriodic ...@@ -99,6 +99,8 @@ void OpenCLNonbondedUtilities::addInteraction(bool usesCutoff, bool usesPeriodic
throw OpenMMException("All Forces must agree on whether to use periodic boundary conditions"); throw OpenMMException("All Forces must agree on whether to use periodic boundary conditions");
if (cutoffDistance != cutoff) if (cutoffDistance != cutoff)
throw OpenMMException("All Forces must use the same cutoff distance"); throw OpenMMException("All Forces must use the same cutoff distance");
if (forceGroup != nonbondedForceGroup)
throw OpenMMException("All nonbonded forces must be in the same force group");
} }
if (usesExclusions) if (usesExclusions)
requestExclusions(exclusionList); requestExclusions(exclusionList);
...@@ -106,6 +108,7 @@ void OpenCLNonbondedUtilities::addInteraction(bool usesCutoff, bool usesPeriodic ...@@ -106,6 +108,7 @@ void OpenCLNonbondedUtilities::addInteraction(bool usesCutoff, bool usesPeriodic
usePeriodic = usesPeriodic; usePeriodic = usesPeriodic;
cutoff = cutoffDistance; cutoff = cutoffDistance;
kernelSource += kernel+"\n"; kernelSource += kernel+"\n";
nonbondedForceGroup = forceGroup;
} }
void OpenCLNonbondedUtilities::addParameter(const ParameterInfo& parameter) { void OpenCLNonbondedUtilities::addParameter(const ParameterInfo& parameter) {
......
...@@ -74,8 +74,9 @@ public: ...@@ -74,8 +74,9 @@ public:
* @param cutoffDistance the cutoff distance for this interaction (ignored if usesCutoff is false) * @param cutoffDistance the cutoff distance for this interaction (ignored if usesCutoff is false)
* @param exclusionList for each atom, specifies the list of other atoms whose interactions should be excluded * @param exclusionList for each atom, specifies the list of other atoms whose interactions should be excluded
* @param kernel the code to evaluate the interaction * @param kernel the code to evaluate the interaction
* @param forceGroup the force group in which the interaction should be calculated
*/ */
void addInteraction(bool usesCutoff, bool usesPeriodic, bool usesExclusions, double cutoffDistance, const std::vector<std::vector<int> >& exclusionList, const std::string& kernel); void addInteraction(bool usesCutoff, bool usesPeriodic, bool usesExclusions, double cutoffDistance, const std::vector<std::vector<int> >& exclusionList, const std::string& kernel, int forceGroup);
/** /**
* Add a per-atom parameter that the default interaction kernel may depend on. * Add a per-atom parameter that the default interaction kernel may depend on.
*/ */
...@@ -148,6 +149,12 @@ public: ...@@ -148,6 +149,12 @@ public:
bool getHasInteractions() { bool getHasInteractions() {
return cutoff != -1.0; return cutoff != -1.0;
} }
/**
* Get the force group in which nonbonded interactions should be computed.
*/
int getForceGroup() {
return nonbondedForceGroup;
}
/** /**
* Prepare to compute interactions. This updates the neighbor list. * Prepare to compute interactions. This updates the neighbor list.
*/ */
...@@ -258,7 +265,7 @@ private: ...@@ -258,7 +265,7 @@ private:
std::map<std::string, std::string> kernelDefines; std::map<std::string, std::string> kernelDefines;
double cutoff; double cutoff;
bool useCutoff, usePeriodic, forceBufferPerAtomBlock, deviceIsCpu, anyExclusions; bool useCutoff, usePeriodic, forceBufferPerAtomBlock, deviceIsCpu, anyExclusions;
int numForceBuffers, startTileIndex, numTiles, numForceThreadBlocks, forceThreadBlockSize; int numForceBuffers, startTileIndex, numTiles, numForceThreadBlocks, forceThreadBlockSize, nonbondedForceGroup;
}; };
/** /**
......
...@@ -525,6 +525,107 @@ void testPerDofVariables() { ...@@ -525,6 +525,107 @@ void testPerDofVariables() {
} }
} }
/**
* Test evaluating force groups separately.
*/
void testForceGroups() {
OpenCLPlatform platform;
System system;
system.addParticle(2.0);
system.addParticle(2.0);
CustomIntegrator integrator(0.01);
integrator.addPerDofVariable("outf", 0);
integrator.addPerDofVariable("outf1", 0);
integrator.addPerDofVariable("outf2", 0);
integrator.addComputePerDof("outf", "f");
integrator.addComputePerDof("outf1", "f1");
integrator.addComputePerDof("outf2", "f2");
HarmonicBondForce* bonds = new HarmonicBondForce();
bonds->addBond(0, 1, 1.5, 1.1);
bonds->setForceGroup(1);
system.addForce(bonds);
NonbondedForce* nb = new NonbondedForce();
nb->addParticle(0.2, 1, 0);
nb->addParticle(0.2, 1, 0);
nb->setForceGroup(2);
system.addForce(nb);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// See if the various forces are computed correctly.
integrator.step(1);
vector<Vec3> f, f1, f2;
integrator.getPerDofVariable(0, f);
integrator.getPerDofVariable(1, f1);
integrator.getPerDofVariable(2, f2);
ASSERT_EQUAL_VEC(Vec3(1.1*0.5, 0, 0), f1[0], 1e-5);
ASSERT_EQUAL_VEC(Vec3(-1.1*0.5, 0, 0), f1[1], 1e-5);
ASSERT_EQUAL_VEC(Vec3(-138.935456*0.2*0.2/4.0, 0, 0), f2[0], 1e-5);
ASSERT_EQUAL_VEC(Vec3(138.935456*0.2*0.2/4.0, 0, 0), f2[1], 1e-5);
ASSERT_EQUAL_VEC(f1[0]+f2[0], f[0], 1e-5);
ASSERT_EQUAL_VEC(f1[1]+f2[1], f[1], 1e-5);
}
/**
* Test a multiple time step r-RESPA integrator.
*/
void testRespa() {
const int numParticles = 8;
OpenCLPlatform platform;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4));
CustomIntegrator integrator(0.002);
integrator.addComputePerDof("v", "v+0.5*dt*f1/m");
for (int i = 0; i < 2; i++) {
integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m");
integrator.addComputePerDof("x", "x+(dt/2)*v");
integrator.addComputePerDof("v", "v+0.5*(dt/2)*f0/m");
}
integrator.addComputePerDof("v", "v+0.5*dt*f1/m");
HarmonicBondForce* bonds = new HarmonicBondForce();
for (int i = 0; i < numParticles-2; i++)
bonds->addBond(i, i+1, 1.0, 0.5);
system.addForce(bonds);
NonbondedForce* nb = new NonbondedForce();
nb->setCutoffDistance(2.0);
nb->setNonbondedMethod(NonbondedForce::Ewald);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(i%2 == 0 ? 5.0 : 10.0);
nb->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
nb->setForceGroup(1);
nb->setReciprocalSpaceForceGroup(0);
system.addForce(nb);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3(i/2, (i+1)/2, 0);
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and monitor energy conservations.
double initialEnergy = 0.0;
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Energy);
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
if (i == 1)
initialEnergy = energy;
else if (i > 1)
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.05);
integrator.step(2);
}
}
int main() { int main() {
try { try {
testSingleBond(); testSingleBond();
...@@ -536,6 +637,8 @@ int main() { ...@@ -536,6 +637,8 @@ int main() {
testParameter(); testParameter();
testRandomDistributions(); testRandomDistributions();
testPerDofVariables(); testPerDofVariables();
testForceGroups();
testRespa();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << 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