"...ssh:/git@developer.sourcefind.cn:2222/tsoc/openmm.git" did not exist on "076f8d7b71e8ed6c47a67aed3aab9cdf2bd6edf0"
Commit 1e216bbc authored by Peter Eastman's avatar Peter Eastman
Browse files

Improved accuracy of torsions for small angles in CUDA and OpenCL platforms

parent 7d70c829
...@@ -76,7 +76,17 @@ static __constant__ cudaGmxSimulation cSim; ...@@ -76,7 +76,17 @@ static __constant__ cudaGmxSimulation cSim;
{ \ { \
float dp; \ float dp; \
GETNORMEDDOTPRODUCT(v1, v2, dp); \ GETNORMEDDOTPRODUCT(v1, v2, dp); \
angle = acos(dp); \ if (dp > 0.99f || dp < -0.99f) { \
float4 cross; \
CROSS_PRODUCT(v1, v2, cross); \
float scale = DOT3(v1, v1)*DOT3(v2, v2); \
angle = asin(sqrt(DOT3(cross, cross)/scale)); \
if (dp < 0.0f) \
angle = LOCAL_HACK_PI-angle; \
} \
else { \
angle = acos(dp); \
} \
} }
#define GETANGLECOSINEBETWEENTWOVECTORS(v1, v2, angle, cosine) \ #define GETANGLECOSINEBETWEENTWOVECTORS(v1, v2, angle, cosine) \
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
__kernel void calcPeriodicTorsionForce(int numAtoms, int numTorsions, __global float4* forceBuffers, __global float* energyBuffer, __global float4* posq, __global float4* params, __global int8* indices) { __kernel void calcPeriodicTorsionForce(int numAtoms, int numTorsions, __global float4* forceBuffers, __global float* energyBuffer, __global float4* posq, __global float4* params, __global int8* indices) {
int index = get_global_id(0); int index = get_global_id(0);
float energy = 0.0f; float energy = 0.0f;
const float PI = 3.14159265358979323846f;
while (index < numTorsions) { while (index < numTorsions) {
// Look up the data for this torsion. // Look up the data for this torsion.
...@@ -23,17 +24,28 @@ __kernel void calcPeriodicTorsionForce(int numAtoms, int numTorsions, __global f ...@@ -23,17 +24,28 @@ __kernel void calcPeriodicTorsionForce(int numAtoms, int numTorsions, __global f
float4 cp0 = cross(v0, v1); float4 cp0 = cross(v0, v1);
float4 cp1 = cross(v1, v2); float4 cp1 = cross(v1, v2);
float cosangle = dot(normalize(cp0), normalize(cp1)); float cosangle = dot(normalize(cp0), normalize(cp1));
cosangle = clamp(cosangle, -1.0f, 1.0f); float dihedralAngle;
float dihedralAngle = acos(cosangle); if (cosangle > 0.99f || cosangle < -0.99f) {
// We're close to the singularity in acos(), so take the cross product and use asin() instead.
float4 cross = cross(cp0, cp1);
float scale = dot(cp0, cp0)*dot(cp1, cp1);
dihedralAngle = asin(sqrt(dot(cross, cross)/scale));
if (cosangle < 0.0f)
dihedralAngle = PI-dihedralAngle;
}
else
dihedralAngle = acos(cosangle);
dihedralAngle = (dot(v0, cp1) >= 0 ? dihedralAngle : -dihedralAngle); dihedralAngle = (dot(v0, cp1) >= 0 ? dihedralAngle : -dihedralAngle);
float deltaAngle = torsionParams.z*dihedralAngle-torsionParams.y; float deltaAngle = torsionParams.z*dihedralAngle-torsionParams.y;
energy += torsionParams.x*(1.0f+cos(deltaAngle)); energy += torsionParams.x*(1.0f+cos(deltaAngle));
float sinDeltaAngle = sin(deltaAngle); float sinDeltaAngle = sin(deltaAngle);
float dEdAngle = -torsionParams.x*torsionParams.z*sinDeltaAngle; float dEdAngle = -torsionParams.x*torsionParams.z*sinDeltaAngle;
float normCross1 = dot(cp0, cp0); float normCross1 = dot(cp0, cp0);
float normBC = sqrt(dot(v1, v1)); float normSqrBC = dot(v1, v1);
float normBC = sqrt(normSqrBC);
float normCross2 = dot(cp1, cp1); float normCross2 = dot(cp1, cp1);
float dp = 1.0f/normBC; float dp = 1.0f/normSqrBC;
float4 ff = (float4) ((-dEdAngle*normBC)/normCross1, dot(v0, v1)*dp, dot(v2, v1)*dp, (dEdAngle*normBC)/normCross2); float4 ff = (float4) ((-dEdAngle*normBC)/normCross1, dot(v0, v1)*dp, dot(v2, v1)*dp, (dEdAngle*normBC)/normCross2);
float4 internalF0 = ff.x*cp0; float4 internalF0 = ff.x*cp0;
float4 internalF3 = ff.w*cp1; float4 internalF3 = ff.w*cp1;
......
...@@ -24,8 +24,18 @@ __kernel void calcRBTorsionForce(int numAtoms, int numTorsions, __global float4* ...@@ -24,8 +24,18 @@ __kernel void calcRBTorsionForce(int numAtoms, int numTorsions, __global float4*
float4 cp0 = cross(v0, v1); float4 cp0 = cross(v0, v1);
float4 cp1 = cross(v1, v2); float4 cp1 = cross(v1, v2);
float cosangle = dot(normalize(cp0), normalize(cp1)); float cosangle = dot(normalize(cp0), normalize(cp1));
cosangle = clamp(cosangle, -1.0f, 1.0f); float dihedralAngle;
float dihedralAngle = acos(cosangle); if (cosangle > 0.99f || cosangle < -0.99f) {
// We're close to the singularity in acos(), so take the cross product and use asin() instead.
float4 cross = cross(cp0, cp1);
float scale = dot(cp0, cp0)*dot(cp1, cp1);
dihedralAngle = asin(sqrt(dot(cross, cross)/scale));
if (cosangle < 0.0f)
dihedralAngle = PI-dihedralAngle;
}
else
dihedralAngle = acos(cosangle);
dihedralAngle = (dot(v0, cp1) >= 0 ? dihedralAngle : -dihedralAngle); dihedralAngle = (dot(v0, cp1) >= 0 ? dihedralAngle : -dihedralAngle);
if (dihedralAngle < 0.0f) if (dihedralAngle < 0.0f)
dihedralAngle += PI; dihedralAngle += PI;
...@@ -50,9 +60,10 @@ __kernel void calcRBTorsionForce(int numAtoms, int numTorsions, __global float4* ...@@ -50,9 +60,10 @@ __kernel void calcRBTorsionForce(int numAtoms, int numTorsions, __global float4*
energy += rbEnergy; energy += rbEnergy;
dEdAngle *= sin(dihedralAngle); dEdAngle *= sin(dihedralAngle);
float normCross1 = dot(cp0, cp0); float normCross1 = dot(cp0, cp0);
float normBC = sqrt(dot(v1, v1)); float normSqrBC = dot(v1, v1);
float normBC = sqrt(normSqrBC);
float normCross2 = dot(cp1, cp1); float normCross2 = dot(cp1, cp1);
float dp = 1.0f/normBC; float dp = 1.0f/normSqrBC;
float4 ff = (float4) ((-dEdAngle*normBC)/normCross1, dot(v0, v1)*dp, dot(v2, v1)*dp, (dEdAngle*normBC)/normCross2); float4 ff = (float4) ((-dEdAngle*normBC)/normCross1, dot(v0, v1)*dp, dot(v2, v1)*dp, (dEdAngle*normBC)/normCross2);
float4 internalF0 = ff.x*cp0; float4 internalF0 = ff.x*cp0;
float4 internalF3 = ff.w*cp1; float4 internalF3 = ff.w*cp1;
......
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