Commit 14d3c584 authored by peastman's avatar peastman
Browse files

Finished CPU implementation of CustomManyParticleForce

parent be0d5cbe
...@@ -250,8 +250,8 @@ static inline float dot4(const fvec4& v1, const fvec4& v2) { ...@@ -250,8 +250,8 @@ static inline float dot4(const fvec4& v1, const fvec4& v2) {
} }
static inline fvec4 cross(const fvec4& v1, const fvec4& v2) { static inline fvec4 cross(const fvec4& v1, const fvec4& v2) {
fvec4 temp = _mm_mul_ps(v2, _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1))) - fvec4 temp = _mm_mul_ps(v1, _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1))) -
_mm_mul_ps(v1, _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1))); _mm_mul_ps(v2, _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1)));
return _mm_shuffle_ps(temp, temp, _MM_SHUFFLE(3, 0, 2, 1)); return _mm_shuffle_ps(temp, temp, _MM_SHUFFLE(3, 0, 2, 1));
} }
......
...@@ -50,7 +50,7 @@ private: ...@@ -50,7 +50,7 @@ private:
class DihedralTermInfo; class DihedralTermInfo;
class ComputeForceTask; class ComputeForceTask;
class ThreadData; class ThreadData;
int numParticlesPerSet, numPerParticleParameters, numTypes; int numParticles, numParticlesPerSet, numPerParticleParameters, numTypes;
bool useCutoff, usePeriodic; bool useCutoff, usePeriodic;
RealOpenMM cutoffDistance; RealOpenMM cutoffDistance;
RealOpenMM periodicBoxSize[3]; RealOpenMM periodicBoxSize[3];
...@@ -62,9 +62,7 @@ private: ...@@ -62,9 +62,7 @@ private:
std::vector<std::vector<int> > particleOrder; std::vector<std::vector<int> > particleOrder;
std::vector<ThreadData*> threadData; std::vector<ThreadData*> threadData;
// 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.
int numParticles;
float* posq; float* posq;
RealVec const* atomCoordinates;
RealOpenMM** particleParameters; RealOpenMM** particleParameters;
const std::map<std::string, double>* globalParameters; const std::map<std::string, double>* globalParameters;
std::vector<AlignedArray<float> >* threadForce; std::vector<AlignedArray<float> >* threadForce;
...@@ -76,6 +74,10 @@ private: ...@@ -76,6 +74,10 @@ private:
*/ */
void threadComputeForce(ThreadPool& threads, int threadIndex); void threadComputeForce(ThreadPool& threads, int threadIndex);
/**
* This is called recursively to loop over all possible combination of a set of particles and evaluate the
* interaction for each one.
*/
void loopOverInteractions(std::vector<int>& availableParticles, std::vector<int>& particleSet, int loopIndex, int startIndex, void loopOverInteractions(std::vector<int>& availableParticles, std::vector<int>& particleSet, int loopIndex, int startIndex,
RealOpenMM** particleParameters, float* forces, ThreadData& data, const fvec4& boxSize, const fvec4& invBoxSize); RealOpenMM** particleParameters, float* forces, ThreadData& data, const fvec4& boxSize, const fvec4& invBoxSize);
...@@ -85,82 +87,72 @@ private: ...@@ -85,82 +87,72 @@ private:
@param particleSet the indices of the particles @param particleSet the indices of the particles
@param posq atom coordinates in float format @param posq atom coordinates in float format
@param atomCoordinates atom coordinates
@param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex]) @param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex])
@param forces force array (forces added) @param forces force array (forces added)
@param totalEnergy total energy @param totalEnergy total energy
--------------------------------------------------------------------------------------- */ --------------------------------------------------------------------------------------- */
void calculateOneIxn(std::vector<int>& particleSet, /**
RealOpenMM** particleParameters, float* forces, ThreadData& data, const fvec4& boxSize, const fvec4& invBoxSize); * Calculate the interaction for one set of particles
*
* @param particleSet the indices of the particles
* @param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex])
* @param data information and workspace for the current thread
* @param boxSize the size of the periodic box
* @param invBoxSize the inverse size of the periodic box
*/
void calculateOneIxn(std::vector<int>& particleSet, RealOpenMM** particleParameters, float* forces, ThreadData& data, const fvec4& boxSize, const fvec4& invBoxSize);
/** /**
* Compute the displacement and squared distance between two points, optionally using * Compute the displacement and squared distance between two points, optionally using
* periodic boundary conditions. * periodic boundary conditions.
*/ */
void getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const; void computeDelta(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const;
void computeDelta(int atom1, int atom2, RealOpenMM* delta, const OpenMM::RealVec* atomCoordinates) const; static float computeAngle(const fvec4& vi, const fvec4& vj, float v2i, float v2j, float sign);
static RealOpenMM computeAngle(RealOpenMM* vec1, RealOpenMM* vec2, float sign); static float getDihedralAngleBetweenThreeVectors(const fvec4& v1, const fvec4& v2, const fvec4& v3, fvec4& cross1, fvec4& cross2, const fvec4& signVector);
public: public:
/**
/**--------------------------------------------------------------------------------------- * Create a new CpuCustomManyParticleForce.
*
Constructor * @param force the CustomManyParticleForce to create it for
* @param threads the thread pool to use
--------------------------------------------------------------------------------------- */ */
CpuCustomManyParticleForce(const OpenMM::CustomManyParticleForce& force, ThreadPool& threads); CpuCustomManyParticleForce(const OpenMM::CustomManyParticleForce& force, ThreadPool& threads);
/**---------------------------------------------------------------------------------------
Destructor
--------------------------------------------------------------------------------------- */
~CpuCustomManyParticleForce(); ~CpuCustomManyParticleForce();
/**--------------------------------------------------------------------------------------- /**
* Set the force to use a cutoff.
Set the force to use a cutoff. *
* @param distance the cutoff distance
@param distance the cutoff distance */
--------------------------------------------------------------------------------------- */
void setUseCutoff(RealOpenMM distance); void setUseCutoff(RealOpenMM distance);
/**--------------------------------------------------------------------------------------- /**
* Set the force to use periodic boundary conditions. This requires that a cutoff has
Set the force to use periodic boundary conditions. This requires that a cutoff has * already been set, and the smallest side of the periodic box is at least twice the cutoff
already been set, and the smallest side of the periodic box is at least twice the cutoff * distance.
distance. *
* @param boxSize the X, Y, and Z widths of the periodic box
@param boxSize the X, Y, and Z widths of the periodic box */
--------------------------------------------------------------------------------------- */
void setPeriodic(OpenMM::RealVec& boxSize); void setPeriodic(OpenMM::RealVec& boxSize);
/**--------------------------------------------------------------------------------------- /**
* Calculate the interaction.
Calculate the interaction *
* @param posq atom coordinates in float format
@param posq atom coordinates in float format * @param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex])
@param atomCoordinates atom coordinates * @param globalParameters the values of global parameters
@param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex]) * @param threadForce the collection of arrays for each thread to add forces to
@param globalParameters the values of global parameters * @param includeForce whether to compute forces
@param forces force array (forces added) * @param includeEnergy whether to compute energy
@param totalEnergy total energy * @param energy the total energy is added to this
*/
--------------------------------------------------------------------------------------- */ void calculateIxn(AlignedArray<float>& posq, RealOpenMM** particleParameters, const std::map<std::string, double>& globalParameters,
void calculateIxn(AlignedArray<float>& posq, std::vector<OpenMM::RealVec>& atomCoordinates, RealOpenMM** particleParameters,
const std::map<std::string, double>& globalParameters,
std::vector<AlignedArray<float> >& threadForce, bool includeForces, bool includeEnergy, double& energy); std::vector<AlignedArray<float> >& threadForce, bool includeForces, bool includeEnergy, double& energy);
}; };
...@@ -198,8 +190,7 @@ public: ...@@ -198,8 +190,7 @@ public:
int p1, p2, p3, p4, variableIndex; int p1, p2, p3, p4, variableIndex;
Lepton::CompiledExpression forceExpression; Lepton::CompiledExpression forceExpression;
int delta1, delta2, delta3; int delta1, delta2, delta3;
mutable RealOpenMM cross1[3]; mutable fvec4 cross1, cross2;
mutable RealOpenMM cross2[3];
DihedralTermInfo(const std::string& name, const std::vector<int>& atoms, const Lepton::CompiledExpression& forceExpression, ThreadData& data); DihedralTermInfo(const std::string& name, const std::vector<int>& atoms, const Lepton::CompiledExpression& forceExpression, ThreadData& data);
}; };
...@@ -213,6 +204,9 @@ public: ...@@ -213,6 +204,9 @@ public:
std::vector<DistanceTermInfo> distanceTerms; std::vector<DistanceTermInfo> distanceTerms;
std::vector<AngleTermInfo> angleTerms; std::vector<AngleTermInfo> angleTerms;
std::vector<DihedralTermInfo> dihedralTerms; std::vector<DihedralTermInfo> dihedralTerms;
AlignedArray<fvec4> delta;
std::vector<float> normDelta;
std::vector<float> norm2Delta;
double energy; double energy;
ThreadData(const CustomManyParticleForce& force, Lepton::ParsedExpression& energyExpr, ThreadData(const CustomManyParticleForce& force, Lepton::ParsedExpression& energyExpr,
std::map<std::string, std::vector<int> >& distances, std::map<std::string, std::vector<int> >& angles, std::map<std::string, std::vector<int> >& dihedrals); std::map<std::string, std::vector<int> >& distances, std::map<std::string, std::vector<int> >& angles, std::map<std::string, std::vector<int> >& dihedrals);
......
...@@ -51,6 +51,7 @@ public: ...@@ -51,6 +51,7 @@ public:
CpuCustomManyParticleForce::CpuCustomManyParticleForce(const CustomManyParticleForce& force, ThreadPool& threads) : CpuCustomManyParticleForce::CpuCustomManyParticleForce(const CustomManyParticleForce& force, ThreadPool& threads) :
threads(threads), useCutoff(false), usePeriodic(false), neighborList(NULL) { threads(threads), useCutoff(false), usePeriodic(false), neighborList(NULL) {
numParticles = force.getNumParticles();
numParticlesPerSet = force.getNumParticlesPerSet(); numParticlesPerSet = force.getNumParticlesPerSet();
numPerParticleParameters = force.getNumPerParticleParameters(); numPerParticleParameters = force.getNumPerParticleParameters();
...@@ -98,14 +99,12 @@ CpuCustomManyParticleForce::~CpuCustomManyParticleForce() { ...@@ -98,14 +99,12 @@ CpuCustomManyParticleForce::~CpuCustomManyParticleForce() {
delete threadData[i]; delete threadData[i];
} }
void CpuCustomManyParticleForce::calculateIxn(AlignedArray<float>& posq, vector<RealVec>& atomCoordinates, RealOpenMM** particleParameters, void CpuCustomManyParticleForce::calculateIxn(AlignedArray<float>& posq, RealOpenMM** particleParameters,
const map<string, double>& globalParameters, vector<AlignedArray<float> >& threadForce, const map<string, double>& globalParameters, vector<AlignedArray<float> >& threadForce,
bool includeForces, bool includeEnergy, double& energy) { bool includeForces, bool includeEnergy, double& energy) {
// Record the parameters for the threads. // Record the parameters for the threads.
this->numParticles = atomCoordinates.size();
this->posq = &posq[0]; this->posq = &posq[0];
this->atomCoordinates = &atomCoordinates[0];
this->particleParameters = particleParameters; this->particleParameters = particleParameters;
this->globalParameters = &globalParameters; this->globalParameters = &globalParameters;
this->threadForce = &threadForce; this->threadForce = &threadForce;
...@@ -220,7 +219,7 @@ void CpuCustomManyParticleForce::loopOverInteractions(vector<int>& availablePart ...@@ -220,7 +219,7 @@ void CpuCustomManyParticleForce::loopOverInteractions(vector<int>& availablePart
float r2; float r2;
for (int j = 0; j < loopIndex && include; j++) { for (int j = 0; j < loopIndex && include; j++) {
fvec4 pos2(posq+4*particleSet[j]); fvec4 pos2(posq+4*particleSet[j]);
getDeltaR(pos1, pos2, deltaR, r2, boxSize, invBoxSize); computeDelta(pos1, pos2, deltaR, r2, boxSize, invBoxSize);
include &= (r2 < cutoff2); include &= (r2 < cutoff2);
} }
} }
...@@ -266,29 +265,33 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO ...@@ -266,29 +265,33 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO
// Compute inter-particle deltas. // Compute inter-particle deltas.
int numDeltas = data.deltaPairs.size(); int numDeltas = data.deltaPairs.size();
RealOpenMM delta[numDeltas][ReferenceForce::LastDeltaRIndex]; AlignedArray<fvec4>& delta = data.delta;
for (int i = 0; i < numDeltas; i++) vector<float>& normDelta = data.normDelta;
computeDelta(permutedParticles[data.deltaPairs[i].first], permutedParticles[data.deltaPairs[i].second], delta[i], atomCoordinates); vector<float>& norm2Delta = data.norm2Delta;
for (int i = 0; i < numDeltas; i++) {
int p1 = permutedParticles[data.deltaPairs[i].first];
int p2 = permutedParticles[data.deltaPairs[i].second];
computeDelta(fvec4(posq+4*p1), fvec4(posq+4*p2), delta[i], norm2Delta[i], boxSize, invBoxSize);
normDelta[i] = sqrtf(norm2Delta[i]);
}
// Compute all of the variables the energy can depend on. // Compute all of the variables the energy can depend on.
for (int i = 0; i < (int) data.particleTerms.size(); i++) { for (int i = 0; i < (int) data.particleTerms.size(); i++) {
const ParticleTermInfo& term = data.particleTerms[i]; const ParticleTermInfo& term = data.particleTerms[i];
expressionSet.setVariable(term.variableIndex, atomCoordinates[permutedParticles[term.atom]][term.component]); expressionSet.setVariable(term.variableIndex, posq[4*permutedParticles[term.atom]+term.component]);
} }
for (int i = 0; i < (int) data.distanceTerms.size(); i++) { for (int i = 0; i < (int) data.distanceTerms.size(); i++) {
const DistanceTermInfo& term = data.distanceTerms[i]; const DistanceTermInfo& term = data.distanceTerms[i];
expressionSet.setVariable(term.variableIndex, delta[term.delta][ReferenceForce::RIndex]); expressionSet.setVariable(term.variableIndex, normDelta[term.delta]);
} }
for (int i = 0; i < (int) data.angleTerms.size(); i++) { for (int i = 0; i < (int) data.angleTerms.size(); i++) {
const AngleTermInfo& term = data.angleTerms[i]; const AngleTermInfo& term = data.angleTerms[i];
expressionSet.setVariable(term.variableIndex, computeAngle(delta[term.delta1], delta[term.delta2], term.delta1Sign*term.delta2Sign)); expressionSet.setVariable(term.variableIndex, computeAngle(delta[term.delta1], delta[term.delta2], norm2Delta[term.delta1], norm2Delta[term.delta2], term.delta1Sign*term.delta2Sign));
} }
for (int i = 0; i < (int) data.dihedralTerms.size(); i++) { for (int i = 0; i < (int) data.dihedralTerms.size(); i++) {
const DihedralTermInfo& term = data.dihedralTerms[i]; const DihedralTermInfo& term = data.dihedralTerms[i];
RealOpenMM dotDihedral, signOfDihedral; expressionSet.setVariable(term.variableIndex, getDihedralAngleBetweenThreeVectors(delta[term.delta1], delta[term.delta2], delta[term.delta3], term.cross1, term.cross2, delta[term.delta1]));
RealOpenMM* crossProduct[] = {term.cross1, term.cross2};
expressionSet.setVariable(term.variableIndex, ReferenceBondIxn::getDihedralAngleBetweenThreeVectors(delta[term.delta1], delta[term.delta2], delta[term.delta3], crossProduct, &dotDihedral, delta[term.delta1], &signOfDihedral, 1));
} }
if (includeForces) { if (includeForces) {
...@@ -309,8 +312,8 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO ...@@ -309,8 +312,8 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO
for (int i = 0; i < (int) data.distanceTerms.size(); i++) { for (int i = 0; i < (int) data.distanceTerms.size(); i++) {
const DistanceTermInfo& term = data.distanceTerms[i]; const DistanceTermInfo& term = data.distanceTerms[i];
RealOpenMM dEdR = (RealOpenMM) (term.forceExpression.evaluate()*term.deltaSign/(delta[term.delta][ReferenceForce::RIndex])); float dEdR = (float) (term.forceExpression.evaluate()*term.deltaSign/(normDelta[term.delta]));
fvec4 force = -dEdR*fvec4((float) delta[term.delta][0], (float) delta[term.delta][1], (float) delta[term.delta][2], 0.0f); fvec4 force = -dEdR*delta[term.delta];
f[term.p1] -= force; f[term.p1] -= force;
f[term.p2] += force; f[term.p2] += force;
} }
...@@ -319,17 +322,15 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO ...@@ -319,17 +322,15 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO
for (int i = 0; i < (int) data.angleTerms.size(); i++) { for (int i = 0; i < (int) data.angleTerms.size(); i++) {
const AngleTermInfo& term = data.angleTerms[i]; const AngleTermInfo& term = data.angleTerms[i];
RealOpenMM dEdTheta = (RealOpenMM) term.forceExpression.evaluate(); float dEdTheta = (float) term.forceExpression.evaluate();
fvec4 delta1((float) delta[term.delta1][0], (float) delta[term.delta1][1], (float) delta[term.delta1][2], 0.0f); fvec4 thetaCross = cross(delta[term.delta1], delta[term.delta2]);
fvec4 delta2((float) delta[term.delta2][0], (float) delta[term.delta2][1], (float) delta[term.delta2][2], 0.0f);
fvec4 thetaCross = cross(delta1, delta2);
float lengthThetaCross = sqrtf(dot3(thetaCross, thetaCross)); float lengthThetaCross = sqrtf(dot3(thetaCross, thetaCross));
if (lengthThetaCross < 1.0e-6f) if (lengthThetaCross < 1.0e-6f)
lengthThetaCross = 1.0e-6f; lengthThetaCross = 1.0e-6f;
RealOpenMM termA = dEdTheta*term.delta2Sign/(delta[term.delta1][ReferenceForce::R2Index]*lengthThetaCross); float termA = dEdTheta*term.delta2Sign/(norm2Delta[term.delta1]*lengthThetaCross);
RealOpenMM termC = -dEdTheta*term.delta1Sign/(delta[term.delta2][ReferenceForce::R2Index]*lengthThetaCross); float termC = -dEdTheta*term.delta1Sign/(norm2Delta[term.delta2]*lengthThetaCross);
fvec4 deltaCross1 = cross(delta1, thetaCross); fvec4 deltaCross1 = cross(delta[term.delta1], thetaCross);
fvec4 deltaCross2 = cross(delta2, thetaCross); fvec4 deltaCross2 = cross(delta[term.delta2], thetaCross);
fvec4 force1 = termA*deltaCross1; fvec4 force1 = termA*deltaCross1;
fvec4 force3 = termC*deltaCross2; fvec4 force3 = termC*deltaCross2;
fvec4 force2 = -(force1+force3); fvec4 force2 = -(force1+force3);
...@@ -342,20 +343,19 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO ...@@ -342,20 +343,19 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO
for (int i = 0; i < (int) data.dihedralTerms.size(); i++) { for (int i = 0; i < (int) data.dihedralTerms.size(); i++) {
const DihedralTermInfo& term = data.dihedralTerms[i]; const DihedralTermInfo& term = data.dihedralTerms[i];
RealOpenMM dEdTheta = (RealOpenMM) term.forceExpression.evaluate(); float dEdTheta = (float) term.forceExpression.evaluate();
RealOpenMM internalF[4][3]; float normCross1 = dot3(term.cross1, term.cross1);
RealOpenMM forceFactors[4]; float normBC = normDelta[term.delta2];
RealOpenMM normCross1 = DOT3(term.cross1, term.cross1); float forceFactors[4];
RealOpenMM normBC = delta[term.delta2][ReferenceForce::RIndex];
forceFactors[0] = (-dEdTheta*normBC)/normCross1; forceFactors[0] = (-dEdTheta*normBC)/normCross1;
RealOpenMM normCross2 = DOT3(term.cross2, term.cross2); float normCross2 = dot3(term.cross2, term.cross2);
forceFactors[3] = (dEdTheta*normBC)/normCross2; forceFactors[3] = (dEdTheta*normBC)/normCross2;
forceFactors[1] = DOT3(delta[term.delta1], delta[term.delta2]); forceFactors[1] = dot3(delta[term.delta1], delta[term.delta2]);
forceFactors[1] /= delta[term.delta2][ReferenceForce::R2Index]; forceFactors[1] /= norm2Delta[term.delta2];
forceFactors[2] = DOT3(delta[term.delta3], delta[term.delta2]); forceFactors[2] = dot3(delta[term.delta3], delta[term.delta2]);
forceFactors[2] /= delta[term.delta2][ReferenceForce::R2Index]; forceFactors[2] /= norm2Delta[term.delta2];
fvec4 force1 = forceFactors[0]*fvec4((float) term.cross1[0], (float) term.cross1[1], (float) term.cross1[2], 0.0f); fvec4 force1 = forceFactors[0]*term.cross1;
fvec4 force4 = forceFactors[3]*fvec4((float) term.cross2[0], (float) term.cross2[1], (float) term.cross2[2], 0.0f); fvec4 force4 = forceFactors[3]*term.cross2;
fvec4 s = forceFactors[1]*force1 - forceFactors[2]*force4; fvec4 s = forceFactors[1]*force1 - forceFactors[2]*force4;
f[term.p1] += force1; f[term.p1] += force1;
f[term.p2] -= force1-s; f[term.p2] -= force1-s;
...@@ -377,27 +377,7 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO ...@@ -377,27 +377,7 @@ void CpuCustomManyParticleForce::calculateOneIxn(vector<int>& particleSet, RealO
data.energy += data.energyExpression.evaluate(); data.energy += data.energyExpression.evaluate();
} }
void CpuCustomManyParticleForce::computeDelta(int atom1, int atom2, RealOpenMM* delta, const OpenMM::RealVec* atomCoordinates) const { void CpuCustomManyParticleForce::computeDelta(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const {
if (usePeriodic)
ReferenceForce::getDeltaRPeriodic(atomCoordinates[atom1], atomCoordinates[atom2], periodicBoxSize, delta);
else
ReferenceForce::getDeltaR(atomCoordinates[atom1], atomCoordinates[atom2], delta);
}
RealOpenMM CpuCustomManyParticleForce::computeAngle(RealOpenMM* vec1, RealOpenMM* vec2, float sign) {
RealOpenMM dot = DOT3(vec1, vec2)*sign;
RealOpenMM cosine = dot/SQRT((vec1[ReferenceForce::R2Index]*vec2[ReferenceForce::R2Index]));
RealOpenMM angle;
if (cosine >= 1)
angle = 0;
else if (cosine <= -1)
angle = PI_M;
else
angle = ACOS(cosine);
return angle;
}
void CpuCustomManyParticleForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const {
deltaR = posJ-posI; deltaR = posJ-posI;
if (usePeriodic) { if (usePeriodic) {
fvec4 base = round(deltaR*invBoxSize)*boxSize; fvec4 base = round(deltaR*invBoxSize)*boxSize;
...@@ -406,6 +386,32 @@ void CpuCustomManyParticleForce::getDeltaR(const fvec4& posI, const fvec4& posJ, ...@@ -406,6 +386,32 @@ void CpuCustomManyParticleForce::getDeltaR(const fvec4& posI, const fvec4& posJ,
r2 = dot3(deltaR, deltaR); r2 = dot3(deltaR, deltaR);
} }
float CpuCustomManyParticleForce::computeAngle(const fvec4& vi, const fvec4& vj, float v2i, float v2j, float sign) {
float dot = dot3(vi, vj)*sign;
float cosine = dot/sqrtf(v2i*v2j);
if (cosine > 0.99f || cosine < -0.99f) {
// We're close to the singularity in acos(), so take the cross product and use asin() instead.
fvec4 cross12 = cross(vi, vj);
float scale = v2i*v2j;
float angle = asinf(sqrtf(dot3(cross12, cross12)/scale));
if (cosine < 0.0f)
angle = (float) (M_PI-angle);
return angle;
}
return acosf(cosine);
}
float CpuCustomManyParticleForce::getDihedralAngleBetweenThreeVectors(const fvec4& v1, const fvec4& v2, const fvec4& v3, fvec4& cross1, fvec4& cross2, const fvec4& signVector) {
cross1 = cross(v1, v2);
cross2 = cross(v2, v3);
float angle = computeAngle(cross1, cross2, dot3(cross1, cross1), dot3(cross2, cross2), 1.0f);
float dotProduct = dot3(signVector, cross2);
if (dotProduct < 0)
angle = -angle;
return angle;
}
CpuCustomManyParticleForce::ParticleTermInfo::ParticleTermInfo(const string& name, int atom, int component, const Lepton::CompiledExpression& forceExpression, ThreadData& data) : CpuCustomManyParticleForce::ParticleTermInfo::ParticleTermInfo(const string& name, int atom, int component, const Lepton::CompiledExpression& forceExpression, ThreadData& data) :
name(name), atom(atom), component(component), forceExpression(forceExpression) { name(name), atom(atom), component(component), forceExpression(forceExpression) {
variableIndex = data.expressionSet.getVariableIndex(name); variableIndex = data.expressionSet.getVariableIndex(name);
...@@ -471,6 +477,10 @@ CpuCustomManyParticleForce::ThreadData::ThreadData(const CustomManyParticleForce ...@@ -471,6 +477,10 @@ CpuCustomManyParticleForce::ThreadData::ThreadData(const CustomManyParticleForce
expressionSet.registerExpression(angleTerms[i].forceExpression); expressionSet.registerExpression(angleTerms[i].forceExpression);
for (int i = 0; i < dihedralTerms.size(); i++) for (int i = 0; i < dihedralTerms.size(); i++)
expressionSet.registerExpression(dihedralTerms[i].forceExpression); expressionSet.registerExpression(dihedralTerms[i].forceExpression);
int numDeltas = deltaPairs.size();
delta.resize(numDeltas);
normDelta.resize(numDeltas);
norm2Delta.resize(numDeltas);
} }
void CpuCustomManyParticleForce::ThreadData::requestDeltaPair(int p1, int p2, int& pairIndex, float& pairSign, bool allowReversed) { void CpuCustomManyParticleForce::ThreadData::requestDeltaPair(int p1, int p2, int& pairIndex, float& pairSign, bool allowReversed) {
......
...@@ -869,7 +869,6 @@ void CpuCalcCustomManyParticleForceKernel::initialize(const System& system, cons ...@@ -869,7 +869,6 @@ void CpuCalcCustomManyParticleForceKernel::initialize(const System& system, cons
} }
double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) { double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
vector<RealVec>& posData = extractPositions(context);
map<string, double> globalParameters; map<string, double> globalParameters;
for (int i = 0; i < (int) globalParameterNames.size(); i++) for (int i = 0; i < (int) globalParameterNames.size(); i++)
globalParameters[globalParameterNames[i]] = context.getParameter(globalParameterNames[i]); globalParameters[globalParameterNames[i]] = context.getParameter(globalParameterNames[i]);
...@@ -881,7 +880,7 @@ double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool ...@@ -881,7 +880,7 @@ double CpuCalcCustomManyParticleForceKernel::execute(ContextImpl& context, bool
ixn->setPeriodic(box); ixn->setPeriodic(box);
} }
double energy = 0; double energy = 0;
ixn->calculateIxn(data.posq, posData, particleParamArray, globalParameters, data.threadForce, includeForces, includeEnergy, energy); ixn->calculateIxn(data.posq, particleParamArray, globalParameters, data.threadForce, includeForces, includeEnergy, energy);
return energy; return energy;
} }
......
...@@ -464,40 +464,6 @@ void testTypeFilters() { ...@@ -464,40 +464,6 @@ void testTypeFilters() {
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5); ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-5);
} }
#include <sys/time.h>
void benchmark() {
int numParticles = 5000;
double boxSize = 5.0;
CustomManyParticleForce* force = new CustomManyParticleForce(3,
"C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;"
"theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);"
"r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)");
force->addGlobalParameter("C", 1.5);
force->setNonbondedMethod(CustomManyParticleForce::CutoffPeriodic);
force->setCutoffDistance(0.6);
vector<double> params;
vector<Vec3> positions;
System system;
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
force->addParticle(params);
positions.push_back(Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt))*boxSize);
system.addParticle(1.0);
}
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(force);
VerletIntegrator integrator(0.001);
CpuPlatform platform;
Context context(system, integrator, platform);
context.setPositions(positions);
timeval t1, t2;
gettimeofday(&t1, NULL);
State state = context.getState(State::Forces | State::Energy);
gettimeofday(&t2, NULL);
printf("%g %g\n", state.getPotentialEnergy(), (t2.tv_sec-t1.tv_sec)+1e-6*(t2.tv_usec-t1.tv_usec));
}
int main() { int main() {
try { try {
testNoCutoff(); testNoCutoff();
...@@ -508,7 +474,6 @@ int main() { ...@@ -508,7 +474,6 @@ int main() {
testParameters(); testParameters();
testTabulatedFunctions(); testTabulatedFunctions();
testTypeFilters(); testTypeFilters();
benchmark();
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
...@@ -153,6 +153,7 @@ void testMathFunctions() { ...@@ -153,6 +153,7 @@ void testMathFunctions() {
ASSERT(any(f1 > 0.5)); ASSERT(any(f1 > 0.5));
ASSERT(!any(f1 > 2.0)); ASSERT(!any(f1 > 2.0));
ASSERT_VEC4_EQUAL(blend(f1, f2, ivec4(-1, 0, -1, 0)), 1.1, 1.9, 1.3, -3.8); ASSERT_VEC4_EQUAL(blend(f1, f2, ivec4(-1, 0, -1, 0)), 1.1, 1.9, 1.3, -3.8);
ASSERT_VEC4_EQUAL(cross(f1, f2), 3.91, -1.84, -1.61, 0.0);
} }
void testTranspose() { void testTranspose() {
......
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