Commit c053a59a authored by peastman's avatar peastman
Browse files

Began parallelizing CPU implementation of CustomNonbondedForce

parent 7ab954bb
...@@ -40,6 +40,8 @@ namespace OpenMM { ...@@ -40,6 +40,8 @@ namespace OpenMM {
class CpuCustomNonbondedForce { class CpuCustomNonbondedForce {
private: private:
class ComputeForceTask;
class ThreadData;
bool cutoff; bool cutoff;
bool useSwitch; bool useSwitch;
...@@ -47,13 +49,9 @@ class CpuCustomNonbondedForce { ...@@ -47,13 +49,9 @@ class CpuCustomNonbondedForce {
const CpuNeighborList* neighborList; const CpuNeighborList* neighborList;
RealOpenMM periodicBoxSize[3]; RealOpenMM periodicBoxSize[3];
RealOpenMM cutoffDistance, switchingDistance; RealOpenMM cutoffDistance, switchingDistance;
Lepton::CompiledExpression energyExpression; ThreadPool& threads;
Lepton::CompiledExpression forceExpression; std::vector<ThreadData*> threadData;
std::vector<std::string> paramNames; std::vector<std::string> paramNames;
std::vector<double*> energyParticleParams;
std::vector<double*> forceParticleParams;
double* energyR;
double* forceR;
std::vector<std::pair<std::set<int>, std::set<int> > > interactionGroups; std::vector<std::pair<std::set<int>, std::set<int> > > interactionGroups;
std::vector<double> threadEnergy; std::vector<double> threadEnergy;
// The following variables are used to make information accessible to the individual threads. // The following variables are used to make information accessible to the individual threads.
...@@ -61,11 +59,17 @@ class CpuCustomNonbondedForce { ...@@ -61,11 +59,17 @@ class CpuCustomNonbondedForce {
float* posq; float* posq;
RealVec const* atomCoordinates; RealVec const* atomCoordinates;
RealOpenMM** atomParameters; RealOpenMM** atomParameters;
const std::map<std::string, double>* globalParameters;
std::set<int> const* exclusions; std::set<int> const* exclusions;
std::vector<AlignedArray<float> >* threadForce; std::vector<AlignedArray<float> >* threadForce;
bool includeEnergy; bool includeForce, includeEnergy;
void* atomicCounter; void* atomicCounter;
/**
* This routine contains the code executed by each thread.
*/
void threadComputeForce(ThreadPool& threads, int threadIndex);
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
Calculate custom pair ixn between two atoms Calculate custom pair ixn between two atoms
...@@ -79,7 +83,7 @@ class CpuCustomNonbondedForce { ...@@ -79,7 +83,7 @@ class CpuCustomNonbondedForce {
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void calculateOneIxn(int atom1, int atom2, float* forces, RealOpenMM* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize); void calculateOneIxn(int atom1, int atom2, ThreadData& data, float* forces, double& totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize);
public: public:
...@@ -91,7 +95,7 @@ class CpuCustomNonbondedForce { ...@@ -91,7 +95,7 @@ class CpuCustomNonbondedForce {
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
CpuCustomNonbondedForce(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression, CpuCustomNonbondedForce(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression,
const std::vector<std::string>& parameterNames); const std::vector<std::string>& parameterNames, ThreadPool& threads);
/**--------------------------------------------------------------------------------------- /**---------------------------------------------------------------------------------------
...@@ -166,7 +170,7 @@ class CpuCustomNonbondedForce { ...@@ -166,7 +170,7 @@ class CpuCustomNonbondedForce {
void calculatePairIxn(int numberOfAtoms, float* posq, std::vector<OpenMM::RealVec>& atomCoordinates, void calculatePairIxn(int numberOfAtoms, float* posq, std::vector<OpenMM::RealVec>& atomCoordinates,
RealOpenMM** atomParameters, std::vector<std::set<int> >& exclusions, RealOpenMM** atomParameters, std::vector<std::set<int> >& exclusions,
RealOpenMM* fixedParameters, const std::map<std::string, double>& globalParameters, RealOpenMM* fixedParameters, const std::map<std::string, double>& globalParameters,
std::vector<AlignedArray<float> >& threadForce, double* totalEnergy, ThreadPool& threads); std::vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy);
/** /**
* Compute the displacement and squared distance between two points, optionally using * Compute the displacement and squared distance between two points, optionally using
...@@ -175,6 +179,17 @@ class CpuCustomNonbondedForce { ...@@ -175,6 +179,17 @@ class CpuCustomNonbondedForce {
void getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const; void getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const;
}; };
class CpuCustomNonbondedForce::ThreadData {
public:
ThreadData(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression, const std::vector<std::string>& parameterNames);
Lepton::CompiledExpression energyExpression;
Lepton::CompiledExpression forceExpression;
std::vector<double*> energyParticleParams;
std::vector<double*> forceParticleParams;
double* energyR;
double* forceR;
};
} // namespace OpenMM } // namespace OpenMM
#endif // OPENMM_CPU_CUSTOM_NONBONDED_FORCE_H__ #endif // OPENMM_CPU_CUSTOM_NONBONDED_FORCE_H__
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "CpuPlatform.h" #include "CpuPlatform.h"
#include "openmm/kernels.h" #include "openmm/kernels.h"
#include "openmm/System.h" #include "openmm/System.h"
#include "lepton/CompiledExpression.h"
namespace OpenMM { namespace OpenMM {
...@@ -224,9 +223,7 @@ private: ...@@ -224,9 +223,7 @@ private:
*/ */
class CpuCalcCustomNonbondedForceKernel : public CalcCustomNonbondedForceKernel { class CpuCalcCustomNonbondedForceKernel : public CalcCustomNonbondedForceKernel {
public: public:
CpuCalcCustomNonbondedForceKernel(std::string name, const Platform& platform, CpuPlatform::PlatformData& data) : CalcCustomNonbondedForceKernel(name, platform), CpuCalcCustomNonbondedForceKernel(std::string name, const Platform& platform, CpuPlatform::PlatformData& data);
data(data), forceCopy(NULL), neighborList(NULL) {
}
~CpuCalcCustomNonbondedForceKernel(); ~CpuCalcCustomNonbondedForceKernel();
/** /**
* Initialize the kernel. * Initialize the kernel.
...@@ -260,11 +257,11 @@ private: ...@@ -260,11 +257,11 @@ private:
CustomNonbondedForce* forceCopy; CustomNonbondedForce* forceCopy;
std::map<std::string, double> globalParamValues; std::map<std::string, double> globalParamValues;
std::vector<std::set<int> > exclusions; std::vector<std::set<int> > exclusions;
Lepton::CompiledExpression energyExpression, forceExpression;
std::vector<std::string> parameterNames, globalParameterNames; std::vector<std::string> parameterNames, globalParameterNames;
std::vector<std::pair<std::set<int>, std::set<int> > > interactionGroups; std::vector<std::pair<std::set<int>, std::set<int> > > interactionGroups;
NonbondedMethod nonbondedMethod; NonbondedMethod nonbondedMethod;
CpuNeighborList* neighborList; CpuNeighborList* neighborList;
CpuCustomNonbondedForce* nonbonded;
}; };
/** /**
......
...@@ -35,104 +35,58 @@ ...@@ -35,104 +35,58 @@
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
/**--------------------------------------------------------------------------------------- class CpuCustomNonbondedForce::ComputeForceTask : public ThreadPool::Task {
public:
CpuCustomNonbondedForce constructor ComputeForceTask(CpuCustomNonbondedForce& owner) : owner(owner) {
}
--------------------------------------------------------------------------------------- */ void execute(ThreadPool& threads, int threadIndex) {
owner.threadComputeForce(threads, threadIndex);
CpuCustomNonbondedForce::CpuCustomNonbondedForce(const Lepton::CompiledExpression& energyExpression, }
const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames) : CpuCustomNonbondedForce& owner;
cutoff(false), useSwitch(false), periodic(false), energyExpression(energyExpression), forceExpression(forceExpression), paramNames(parameterNames) { };
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nCpuCustomNonbondedForce::CpuCustomNonbondedForce";
// ---------------------------------------------------------------------------------------
CpuCustomNonbondedForce::ThreadData::ThreadData(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames) :
energyExpression(energyExpression), forceExpression(forceExpression) {
energyR = ReferenceForce::getVariablePointer(this->energyExpression, "r"); energyR = ReferenceForce::getVariablePointer(this->energyExpression, "r");
forceR = ReferenceForce::getVariablePointer(this->forceExpression, "r"); forceR = ReferenceForce::getVariablePointer(this->forceExpression, "r");
for (int i = 0; i < (int) paramNames.size(); i++) { for (int i = 0; i < (int) parameterNames.size(); i++) {
for (int j = 1; j < 3; j++) { for (int j = 1; j < 3; j++) {
stringstream name; stringstream name;
name << paramNames[i] << j; name << parameterNames[i] << j;
energyParticleParams.push_back(ReferenceForce::getVariablePointer(this->energyExpression, name.str())); energyParticleParams.push_back(ReferenceForce::getVariablePointer(this->energyExpression, name.str()));
forceParticleParams.push_back(ReferenceForce::getVariablePointer(this->forceExpression, name.str())); forceParticleParams.push_back(ReferenceForce::getVariablePointer(this->forceExpression, name.str()));
} }
} }
} }
/**--------------------------------------------------------------------------------------- CpuCustomNonbondedForce::CpuCustomNonbondedForce(const Lepton::CompiledExpression& energyExpression,
const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames, ThreadPool& threads) :
CpuCustomNonbondedForce destructor cutoff(false), useSwitch(false), periodic(false), paramNames(parameterNames), threads(threads) {
for (int i = 0; i < threads.getNumThreads(); i++)
--------------------------------------------------------------------------------------- */ threadData.push_back(new ThreadData(energyExpression, forceExpression, parameterNames));
CpuCustomNonbondedForce::~CpuCustomNonbondedForce( ){
// ---------------------------------------------------------------------------------------
// static const char* methodName = "\nCpuCustomNonbondedForce::~CpuCustomNonbondedForce";
// ---------------------------------------------------------------------------------------
} }
/**--------------------------------------------------------------------------------------- CpuCustomNonbondedForce::~CpuCustomNonbondedForce() {
for (int i = 0; i < (int) threadData.size(); i++)
Set the force to use a cutoff. delete threadData[i];
}
@param distance the cutoff distance
@param neighbors the neighbor list to use
--------------------------------------------------------------------------------------- */
void CpuCustomNonbondedForce::setUseCutoff( RealOpenMM distance, const CpuNeighborList& neighbors ) {
void CpuCustomNonbondedForce::setUseCutoff(RealOpenMM distance, const CpuNeighborList& neighbors) {
cutoff = true; cutoff = true;
cutoffDistance = distance; cutoffDistance = distance;
neighborList = &neighbors; neighborList = &neighbors;
} }
/**---------------------------------------------------------------------------------------
Restrict the force to a list of interaction groups.
@param distance the cutoff distance
@param neighbors the neighbor list to use
--------------------------------------------------------------------------------------- */
void CpuCustomNonbondedForce::setInteractionGroups(const vector<pair<set<int>, set<int> > >& groups) { void CpuCustomNonbondedForce::setInteractionGroups(const vector<pair<set<int>, set<int> > >& groups) {
interactionGroups = groups; interactionGroups = groups;
} }
/**--------------------------------------------------------------------------------------- void CpuCustomNonbondedForce::setUseSwitchingFunction(RealOpenMM distance) {
Set the force to use a switching function.
@param distance the switching distance
--------------------------------------------------------------------------------------- */
void CpuCustomNonbondedForce::setUseSwitchingFunction( RealOpenMM distance ) {
useSwitch = true; useSwitch = true;
switchingDistance = distance; switchingDistance = distance;
} }
/**--------------------------------------------------------------------------------------- void CpuCustomNonbondedForce::setPeriodic(RealVec& boxSize) {
Set the force to use periodic boundary conditions. This requires that a cutoff has
also been set, and the smallest side of the periodic box is at least twice the cutoff
distance.
@param boxSize the X, Y, and Z widths of the periodic box
--------------------------------------------------------------------------------------- */
void CpuCustomNonbondedForce::setPeriodic( RealVec& boxSize ) {
assert(cutoff); assert(cutoff);
assert(boxSize[0] >= 2.0*cutoffDistance); assert(boxSize[0] >= 2.0*cutoffDistance);
assert(boxSize[1] >= 2.0*cutoffDistance); assert(boxSize[1] >= 2.0*cutoffDistance);
...@@ -141,39 +95,61 @@ void CpuCustomNonbondedForce::setUseSwitchingFunction( RealOpenMM distance ) { ...@@ -141,39 +95,61 @@ void CpuCustomNonbondedForce::setUseSwitchingFunction( RealOpenMM distance ) {
periodicBoxSize[0] = boxSize[0]; periodicBoxSize[0] = boxSize[0];
periodicBoxSize[1] = boxSize[1]; periodicBoxSize[1] = boxSize[1];
periodicBoxSize[2] = boxSize[2]; periodicBoxSize[2] = boxSize[2];
}
}
void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, vector<RealVec>& atomCoordinates, void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, vector<RealVec>& atomCoordinates,
RealOpenMM** atomParameters, vector<set<int> >& exclusions, RealOpenMM** atomParameters, vector<set<int> >& exclusions,
RealOpenMM* fixedParameters, const map<string, double>& globalParameters, RealOpenMM* fixedParameters, const map<string, double>& globalParameters,
vector<AlignedArray<float> >& threadForce, double* totalEnergy, ThreadPool& threads) { vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy) {
// Record the parameters for the threads. // Record the parameters for the threads.
this->numberOfAtoms = numberOfAtoms; this->numberOfAtoms = numberOfAtoms;
this->posq = posq; this->posq = posq;
this->atomCoordinates = &atomCoordinates[0]; this->atomCoordinates = &atomCoordinates[0];
this->atomParameters = atomParameters; this->atomParameters = atomParameters;
this->globalParameters = &globalParameters;
this->exclusions = &exclusions[0]; this->exclusions = &exclusions[0];
this->threadForce = &threadForce; this->threadForce = &threadForce;
includeEnergy = (totalEnergy != NULL); this->includeForce = includeForce;
this->includeEnergy = includeEnergy;
threadEnergy.resize(threads.getNumThreads()); threadEnergy.resize(threads.getNumThreads());
gmx_atomic_t counter; gmx_atomic_t counter;
gmx_atomic_set(&counter, 0); gmx_atomic_set(&counter, 0);
this->atomicCounter = &counter; this->atomicCounter = &counter;
// Signal the threads to start running and wait for them to finish.
float* forces = &threadForce[0][0]; ComputeForceTask task(*this);
threads.execute(task);
threads.waitForThreads();
// Combine the energies from all the threads.
if (includeEnergy) {
int numThreads = threads.getNumThreads();
for (int i = 0; i < numThreads; i++)
totalEnergy += threadEnergy[i];
}
}
for (map<string, double>::const_iterator iter = globalParameters.begin(); iter != globalParameters.end(); ++iter) { void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int threadIndex) {
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(energyExpression, iter->first), iter->second); // Compute this thread's subset of interactions.
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(forceExpression, iter->first), iter->second);
int numThreads = threads.getNumThreads();
threadEnergy[threadIndex] = 0;
double& energy = threadEnergy[threadIndex];
float* forces = &(*threadForce)[threadIndex][0];
ThreadData& data = *threadData[threadIndex];
for (map<string, double>::const_iterator iter = globalParameters->begin(); iter != globalParameters->end(); ++iter) {
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(data.energyExpression, iter->first), iter->second);
ReferenceForce::setVariable(ReferenceForce::getVariablePointer(data.forceExpression, iter->first), iter->second);
} }
fvec4 boxSize(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2], 0); fvec4 boxSize(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2], 0);
fvec4 invBoxSize((1/periodicBoxSize[0]), (1/periodicBoxSize[1]), (1/periodicBoxSize[2]), 0); fvec4 invBoxSize((1/periodicBoxSize[0]), (1/periodicBoxSize[1]), (1/periodicBoxSize[2]), 0);
if (interactionGroups.size() > 0) { if (interactionGroups.size() > 0) {
if (threadIndex > 0)
return;
// The user has specified interaction groups, so compute only the requested interactions. // The user has specified interaction groups, so compute only the requested interactions.
for (int group = 0; group < (int) interactionGroups.size(); group++) { for (int group = 0; group < (int) interactionGroups.size(); group++) {
...@@ -186,12 +162,12 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v ...@@ -186,12 +162,12 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v
if (*atom1 > *atom2 && set1.find(*atom2) != set1.end() && set2.find(*atom1) != set2.end()) if (*atom1 > *atom2 && set1.find(*atom2) != set1.end() && set2.find(*atom1) != set2.end())
continue; // Both atoms are in both sets, so skip duplicate interactions. continue; // Both atoms are in both sets, so skip duplicate interactions.
for (int j = 0; j < (int) paramNames.size(); j++) { for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[*atom1][j]); ReferenceForce::setVariable(data.energyParticleParams[j*2], atomParameters[*atom1][j]);
ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[*atom2][j]); ReferenceForce::setVariable(data.energyParticleParams[j*2+1], atomParameters[*atom2][j]);
ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[*atom1][j]); ReferenceForce::setVariable(data.forceParticleParams[j*2], atomParameters[*atom1][j]);
ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[*atom2][j]); ReferenceForce::setVariable(data.forceParticleParams[j*2+1], atomParameters[*atom2][j]);
} }
calculateOneIxn(*atom1, *atom2, forces, totalEnergy, boxSize, invBoxSize); calculateOneIxn(*atom1, *atom2, data, forces, energy, boxSize, invBoxSize);
} }
} }
} }
...@@ -199,7 +175,10 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v ...@@ -199,7 +175,10 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v
else if (cutoff) { else if (cutoff) {
// We are using a cutoff, so get the interactions from the neighbor list. // We are using a cutoff, so get the interactions from the neighbor list.
for (int blockIndex = 0; blockIndex < neighborList->getNumBlocks(); blockIndex++) { while (true) {
int blockIndex = gmx_atomic_fetch_add(reinterpret_cast<gmx_atomic_t*>(atomicCounter), 1);
if (blockIndex >= neighborList->getNumBlocks())
break;
int blockAtom[4]; int blockAtom[4];
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
blockAtom[i] = neighborList->getSortedAtoms()[4*blockIndex+i]; blockAtom[i] = neighborList->getSortedAtoms()[4*blockIndex+i];
...@@ -208,84 +187,46 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v ...@@ -208,84 +187,46 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v
for (int i = 0; i < (int) neighbors.size(); i++) { for (int i = 0; i < (int) neighbors.size(); i++) {
int first = neighbors[i]; int first = neighbors[i];
for (int j = 0; j < (int) paramNames.size(); j++) { for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[first][j]); ReferenceForce::setVariable(data.energyParticleParams[j*2], atomParameters[first][j]);
ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[first][j]); ReferenceForce::setVariable(data.forceParticleParams[j*2], atomParameters[first][j]);
} }
for (int k = 0; k < 4; k++) { for (int k = 0; k < 4; k++) {
if ((exclusions[i] & (1<<k)) == 0) { if ((exclusions[i] & (1<<k)) == 0) {
int second = blockAtom[k]; int second = blockAtom[k];
for (int j = 0; j < (int) paramNames.size(); j++) { for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[second][j]); ReferenceForce::setVariable(data.energyParticleParams[j*2+1], atomParameters[second][j]);
ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[second][j]); ReferenceForce::setVariable(data.forceParticleParams[j*2+1], atomParameters[second][j]);
} }
calculateOneIxn(first, second, forces, totalEnergy, boxSize, invBoxSize); calculateOneIxn(first, second, data, forces, energy, boxSize, invBoxSize);
} }
} }
} }
} }
// for (int i = 0; i < (int) neighborList->size(); i++) {
// OpenMM::AtomPair pair = (*neighborList)[i];
// for (int j = 0; j < (int) paramNames.size(); j++) {
// ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[pair.first][j]);
// ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[pair.second][j]);
// ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[pair.first][j]);
// ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[pair.second][j]);
// }
// calculateOneIxn(pair.first, pair.second, atomCoordinates, forces, energyByAtom, totalEnergy);
// }
} }
else { else {
// Every particle interacts with every other one. // Every particle interacts with every other one.
if (threadIndex > 0)
return;
for (int ii = 0; ii < numberOfAtoms; ii++) { for (int ii = 0; ii < numberOfAtoms; ii++) {
for (int jj = ii+1; jj < numberOfAtoms; jj++) { for (int jj = ii+1; jj < numberOfAtoms; jj++) {
if (exclusions[jj].find(ii) == exclusions[jj].end()) { if (exclusions[jj].find(ii) == exclusions[jj].end()) {
for (int j = 0; j < (int) paramNames.size(); j++) { for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(energyParticleParams[j*2], atomParameters[ii][j]); ReferenceForce::setVariable(data.energyParticleParams[j*2], atomParameters[ii][j]);
ReferenceForce::setVariable(energyParticleParams[j*2+1], atomParameters[jj][j]); ReferenceForce::setVariable(data.energyParticleParams[j*2+1], atomParameters[jj][j]);
ReferenceForce::setVariable(forceParticleParams[j*2], atomParameters[ii][j]); ReferenceForce::setVariable(data.forceParticleParams[j*2], atomParameters[ii][j]);
ReferenceForce::setVariable(forceParticleParams[j*2+1], atomParameters[jj][j]); ReferenceForce::setVariable(data.forceParticleParams[j*2+1], atomParameters[jj][j]);
} }
calculateOneIxn(ii, jj, forces, totalEnergy, boxSize, invBoxSize); calculateOneIxn(ii, jj, data, forces, energy, boxSize, invBoxSize);
} }
} }
} }
} }
} }
/**--------------------------------------------------------------------------------------- void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, ThreadData& data,
float* forces, double& totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize) {
Calculate one pair ixn between two atoms // Get deltaR, R2, and R between 2 atoms
@param ii the index of the first atom
@param jj the index of the second atom
@param atomCoordinates atom coordinates
@param atomParameters atom parameters (charges, c6, c12, ...) atomParameters[atomIndex][paramterIndex]
@param forces force array (forces added)
@param totalEnergy total energy
--------------------------------------------------------------------------------------- */
void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, float* forces, RealOpenMM* totalEnergy, const fvec4& boxSize, const fvec4& invBoxSize) {
// ---------------------------------------------------------------------------------------
static const std::string methodName = "\nCpuCustomNonbondedForce::calculateOneIxn";
// ---------------------------------------------------------------------------------------
// constants -- reduce Visual Studio warnings regarding conversions between float & double
static const RealOpenMM zero = 0.0;
static const RealOpenMM one = 1.0;
static const RealOpenMM two = 2.0;
static const RealOpenMM three = 3.0;
static const RealOpenMM six = 6.0;
static const RealOpenMM twelve = 12.0;
static const RealOpenMM oneM = -1.0;
// get deltaR, R2, and R between 2 atoms
fvec4 deltaR; fvec4 deltaR;
fvec4 posI(posq+4*ii); fvec4 posI(posq+4*ii);
...@@ -298,10 +239,10 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, float* forces, Rea ...@@ -298,10 +239,10 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, float* forces, Rea
// accumulate forces // accumulate forces
ReferenceForce::setVariable(energyR, r); ReferenceForce::setVariable(data.energyR, r);
ReferenceForce::setVariable(forceR, r); ReferenceForce::setVariable(data.forceR, r);
double dEdR = forceExpression.evaluate()/r; double dEdR = (includeForce ? data.forceExpression.evaluate()/r : 0.0);
double energy = energyExpression.evaluate(); double energy = (includeEnergy ? data.energyExpression.evaluate() : 0.0);
if (useSwitch) { if (useSwitch) {
if (r > switchingDistance) { if (r > switchingDistance) {
RealOpenMM t = (r-switchingDistance)/(cutoffDistance-switchingDistance); RealOpenMM t = (r-switchingDistance)/(cutoffDistance-switchingDistance);
...@@ -317,8 +258,7 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, float* forces, Rea ...@@ -317,8 +258,7 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, float* forces, Rea
// accumulate energies // accumulate energies
if (totalEnergy) totalEnergy += energy;
*totalEnergy += energy;
} }
void CpuCustomNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const { void CpuCustomNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const {
......
...@@ -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 Stanford University and the Authors. * * Portions copyright (c) 2013-2014 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "openmm/internal/NonbondedForceImpl.h" #include "openmm/internal/NonbondedForceImpl.h"
#include "openmm/internal/vectorize.h" #include "openmm/internal/vectorize.h"
#include "RealVec.h" #include "RealVec.h"
#include "lepton/CompiledExpression.h"
#include "lepton/CustomFunction.h" #include "lepton/CustomFunction.h"
#include "lepton/Parser.h" #include "lepton/Parser.h"
#include "lepton/ParsedExpression.h" #include "lepton/ParsedExpression.h"
...@@ -623,6 +624,10 @@ void CpuCalcNonbondedForceKernel::copyParametersToContext(ContextImpl& context, ...@@ -623,6 +624,10 @@ void CpuCalcNonbondedForceKernel::copyParametersToContext(ContextImpl& context,
dispersionCoefficient = NonbondedForceImpl::calcDispersionCorrection(context.getSystem(), force); dispersionCoefficient = NonbondedForceImpl::calcDispersionCorrection(context.getSystem(), force);
} }
CpuCalcCustomNonbondedForceKernel::CpuCalcCustomNonbondedForceKernel(string name, const Platform& platform, CpuPlatform::PlatformData& data) :
CalcCustomNonbondedForceKernel(name, platform), data(data), forceCopy(NULL), neighborList(NULL), nonbonded(NULL) {
}
CpuCalcCustomNonbondedForceKernel::~CpuCalcCustomNonbondedForceKernel() { CpuCalcCustomNonbondedForceKernel::~CpuCalcCustomNonbondedForceKernel() {
if (particleParamArray != NULL) { if (particleParamArray != NULL) {
for (int i = 0; i < numParticles; i++) for (int i = 0; i < numParticles; i++)
...@@ -631,6 +636,8 @@ CpuCalcCustomNonbondedForceKernel::~CpuCalcCustomNonbondedForceKernel() { ...@@ -631,6 +636,8 @@ CpuCalcCustomNonbondedForceKernel::~CpuCalcCustomNonbondedForceKernel() {
} }
if (neighborList != NULL) if (neighborList != NULL)
delete neighborList; delete neighborList;
if (nonbonded != NULL)
delete nonbonded;
if (forceCopy != NULL) if (forceCopy != NULL)
delete forceCopy; delete forceCopy;
} }
...@@ -679,8 +686,8 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C ...@@ -679,8 +686,8 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C
// Parse the various expressions used to calculate the force. // Parse the various expressions used to calculate the force.
Lepton::ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).optimize(); Lepton::ParsedExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).optimize();
energyExpression = expression.createCompiledExpression(); Lepton::CompiledExpression energyExpression = expression.createCompiledExpression();
forceExpression = expression.differentiate("r").createCompiledExpression(); Lepton::CompiledExpression forceExpression = expression.differentiate("r").createCompiledExpression();
for (int i = 0; i < numParameters; i++) for (int i = 0; i < numParameters; i++)
parameterNames.push_back(force.getPerParticleParameterName(i)); parameterNames.push_back(force.getPerParticleParameterName(i));
for (int i = 0; i < force.getNumGlobalParameters(); i++) { for (int i = 0; i < force.getNumGlobalParameters(); i++) {
...@@ -712,6 +719,7 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C ...@@ -712,6 +719,7 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C
interactionGroups.push_back(make_pair(set1, set2)); interactionGroups.push_back(make_pair(set1, set2));
} }
data.isPeriodic = (nonbondedMethod == CutoffPeriodic); data.isPeriodic = (nonbondedMethod == CutoffPeriodic);
nonbonded = new CpuCustomNonbondedForce(energyExpression, forceExpression, parameterNames, data.threads);
} }
double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...@@ -720,20 +728,19 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc ...@@ -720,20 +728,19 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc
RealVec& box = extractBoxSize(context); RealVec& box = extractBoxSize(context);
float floatBoxSize[3] = {(float) box[0], (float) box[1], (float) box[2]}; float floatBoxSize[3] = {(float) box[0], (float) box[1], (float) box[2]};
double energy = 0; double energy = 0;
CpuCustomNonbondedForce ixn(energyExpression, forceExpression, parameterNames);
bool periodic = (nonbondedMethod == CutoffPeriodic); bool periodic = (nonbondedMethod == CutoffPeriodic);
if (nonbondedMethod != NoCutoff) { if (nonbondedMethod != NoCutoff) {
neighborList->computeNeighborList(numParticles, data.posq, exclusions, floatBoxSize, data.isPeriodic, nonbondedCutoff, data.threads); neighborList->computeNeighborList(numParticles, data.posq, exclusions, floatBoxSize, data.isPeriodic, nonbondedCutoff, data.threads);
ixn.setUseCutoff(nonbondedCutoff, *neighborList); nonbonded->setUseCutoff(nonbondedCutoff, *neighborList);
} }
if (periodic) { if (periodic) {
double minAllowedSize = 2*nonbondedCutoff; double minAllowedSize = 2*nonbondedCutoff;
if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize) if (box[0] < minAllowedSize || box[1] < minAllowedSize || box[2] < minAllowedSize)
throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff."); throw OpenMMException("The periodic box size has decreased to less than twice the nonbonded cutoff.");
ixn.setPeriodic(box); nonbonded->setPeriodic(box);
} }
if (interactionGroups.size() > 0) if (interactionGroups.size() > 0)
ixn.setInteractionGroups(interactionGroups); nonbonded->setInteractionGroups(interactionGroups);
bool globalParamsChanged = false; bool globalParamsChanged = false;
for (int i = 0; i < (int) globalParameterNames.size(); i++) { for (int i = 0; i < (int) globalParameterNames.size(); i++) {
double value = context.getParameter(globalParameterNames[i]); double value = context.getParameter(globalParameterNames[i]);
...@@ -742,8 +749,8 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc ...@@ -742,8 +749,8 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc
globalParamValues[globalParameterNames[i]] = value; globalParamValues[globalParameterNames[i]] = value;
} }
if (useSwitchingFunction) if (useSwitchingFunction)
ixn.setUseSwitchingFunction(switchingDistance); nonbonded->setUseSwitchingFunction(switchingDistance);
ixn.calculatePairIxn(numParticles, &data.posq[0], posData, particleParamArray, exclusions, 0, globalParamValues, data.threadForce, includeEnergy ? &energy : NULL, data.threads); nonbonded->calculatePairIxn(numParticles, &data.posq[0], posData, particleParamArray, exclusions, 0, globalParamValues, data.threadForce, includeForces, includeEnergy, energy);
// Add in the long range correction. // Add in the long range correction.
......
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