Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tsoc
openmm
Commits
4d823b0a
"LLaDA2.0/decoder/smart_img_process.py" did not exist on "a570aeea073012345d91a9b896d8228a6d40a72f"
Commit
4d823b0a
authored
Sep 02, 2015
by
peastman
Browse files
Began CUDA version of CustomCentroidBondForce
parent
56d95193
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
858 additions
and
4 deletions
+858
-4
platforms/cuda/include/CudaKernels.h
platforms/cuda/include/CudaKernels.h
+52
-0
platforms/cuda/src/CudaKernelFactory.cpp
platforms/cuda/src/CudaKernelFactory.cpp
+2
-0
platforms/cuda/src/CudaKernels.cpp
platforms/cuda/src/CudaKernels.cpp
+416
-4
platforms/cuda/src/CudaPlatform.cpp
platforms/cuda/src/CudaPlatform.cpp
+1
-0
platforms/cuda/src/kernels/customCentroidBond.cu
platforms/cuda/src/kernels/customCentroidBond.cu
+137
-0
platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp
platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp
+250
-0
No files found.
platforms/cuda/include/CudaKernels.h
View file @
4d823b0a
...
...
@@ -922,6 +922,58 @@ private:
CUfunction
donorKernel
,
acceptorKernel
;
};
/**
* This kernel is invoked by CustomCentroidBondForce to calculate the forces acting on the system.
*/
class
CudaCalcCustomCentroidBondForceKernel
:
public
CalcCustomCentroidBondForceKernel
{
public:
CudaCalcCustomCentroidBondForceKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CudaContext
&
cu
,
const
System
&
system
)
:
CalcCustomCentroidBondForceKernel
(
name
,
platform
),
cu
(
cu
),
params
(
NULL
),
globals
(
NULL
),
groupParticles
(
NULL
),
groupWeights
(
NULL
),
groupOffsets
(
NULL
),
groupForces
(
NULL
),
bondGroups
(
NULL
),
centerPositions
(
NULL
),
system
(
system
)
{
}
~
CudaCalcCustomCentroidBondForceKernel
();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the CustomCentroidBondForce this kernel will be used for
*/
void
initialize
(
const
System
&
system
,
const
CustomCentroidBondForce
&
force
);
/**
* Execute the kernel to calculate the forces and/or energy.
*
* @param context the context in which to execute this kernel
* @param includeForces true if forces should be calculated
* @param includeEnergy true if the energy should be calculated
* @return the potential energy due to the force
*/
double
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
);
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the CustomCentroidBondForce to copy the parameters from
*/
void
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomCentroidBondForce
&
force
);
private:
int
numGroups
,
numBonds
;
CudaContext
&
cu
;
CudaParameterSet
*
params
;
CudaArray
*
globals
;
CudaArray
*
groupParticles
;
CudaArray
*
groupWeights
;
CudaArray
*
groupOffsets
;
CudaArray
*
groupForces
;
CudaArray
*
bondGroups
;
CudaArray
*
centerPositions
;
std
::
vector
<
std
::
string
>
globalParamNames
;
std
::
vector
<
float
>
globalParamValues
;
std
::
vector
<
CudaArray
*>
tabulatedFunctions
;
std
::
vector
<
void
*>
groupForcesArgs
;
CUfunction
computeCentersKernel
,
groupForcesKernel
,
applyForcesKernel
;
const
System
&
system
;
};
/**
* This kernel is invoked by CustomCompoundBondForce to calculate the forces acting on the system.
*/
...
...
platforms/cuda/src/CudaKernelFactory.cpp
View file @
4d823b0a
...
...
@@ -104,6 +104,8 @@ KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform
return
new
CudaCalcCustomExternalForceKernel
(
name
,
platform
,
cu
,
context
.
getSystem
());
if
(
name
==
CalcCustomHbondForceKernel
::
Name
())
return
new
CudaCalcCustomHbondForceKernel
(
name
,
platform
,
cu
,
context
.
getSystem
());
if
(
name
==
CalcCustomCentroidBondForceKernel
::
Name
())
return
new
CudaCalcCustomCentroidBondForceKernel
(
name
,
platform
,
cu
,
context
.
getSystem
());
if
(
name
==
CalcCustomCompoundBondForceKernel
::
Name
())
return
new
CudaCalcCustomCompoundBondForceKernel
(
name
,
platform
,
cu
,
context
.
getSystem
());
if
(
name
==
CalcCustomManyParticleForceKernel
::
Name
())
...
...
platforms/cuda/src/CudaKernels.cpp
View file @
4d823b0a
...
...
@@ -31,6 +31,7 @@
#include "openmm/internal/AndersenThermostatImpl.h"
#include "openmm/internal/CMAPTorsionForceImpl.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/internal/CustomCentroidBondForceImpl.h"
#include "openmm/internal/CustomCompoundBondForceImpl.h"
#include "openmm/internal/CustomHbondForceImpl.h"
#include "openmm/internal/CustomManyParticleForceImpl.h"
...
...
@@ -2570,8 +2571,8 @@ void CudaCalcGBSAOBCForceKernel::initialize(const System& system, const GBSAOBCF
cutoff = force.getCutoffDistance();
string source = CudaKernelSources::gbsaObc2;
nb.addInteraction(useCutoff, usePeriodic, false, cutoff, vector<vector<int> >(), source, force.getForceGroup());
nb.addParameter(CudaNonbondedUtilities::ParameterInfo("obcParams", "float", 2, sizeof(float2), params->getDevicePointer()));
;
nb.addParameter(CudaNonbondedUtilities::ParameterInfo("bornForce", "long long", 1, sizeof(long long), bornForce->getDevicePointer()));
;
nb.addParameter(CudaNonbondedUtilities::ParameterInfo("obcParams", "float", 2, sizeof(float2), params->getDevicePointer()));
nb.addParameter(CudaNonbondedUtilities::ParameterInfo("bornForce", "long long", 1, sizeof(long long), bornForce->getDevicePointer()));
cu.addForce(new CudaGBSAOBCForceInfo(force));
}
...
...
@@ -4242,6 +4243,418 @@ void CudaCalcCustomHbondForceKernel::copyParametersToContext(ContextImpl& contex
cu.invalidateMolecules();
}
class CudaCustomCentroidBondForceInfo : public CudaForceInfo {
public:
CudaCustomCentroidBondForceInfo(const CustomCentroidBondForce& force) : force(force) {
}
int getNumParticleGroups() {
return force.getNumBonds();
}
void getParticlesInGroup(int index, vector<int>& particles) {
vector<double> parameters;
force.getBondParameters(index, particles, parameters);
}
bool areGroupsIdentical(int group1, int group2) {
vector<int> particles;
vector<double> parameters1, parameters2;
force.getBondParameters(group1, particles, parameters1);
force.getBondParameters(group2, particles, parameters2);
for (int i = 0; i < (int) parameters1.size(); i++)
if (parameters1[i] != parameters2[i])
return false;
return true;
}
private:
const CustomCentroidBondForce& force;
};
CudaCalcCustomCentroidBondForceKernel::~CudaCalcCustomCentroidBondForceKernel() {
cu.setAsCurrent();
if (params != NULL)
delete params;
if (globals != NULL)
delete globals;
if (groupParticles != NULL)
delete groupParticles;
if (groupWeights != NULL)
delete groupWeights;
if (groupOffsets != NULL)
delete groupOffsets;
if (groupForces != NULL)
delete groupForces;
if (bondGroups != NULL)
delete bondGroups;
if (centerPositions != NULL)
delete centerPositions;
for (int i = 0; i < (int) tabulatedFunctions.size(); i++)
delete tabulatedFunctions[i];
}
void CudaCalcCustomCentroidBondForceKernel::initialize(const System& system, const CustomCentroidBondForce& force) {
cu.setAsCurrent();
numBonds = force.getNumBonds();
if (numBonds == 0)
return;
cu.addForce(new CudaCustomCentroidBondForceInfo(force));
// Record the groups.
numGroups = force.getNumGroups();
vector<int> groupParticleVec;
vector<float> groupWeightVecFloat;
vector<double> groupWeightVecDouble;
vector<int> groupOffsetVec;
groupOffsetVec.push_back(0);
for (int i = 0; i < numGroups; i++) {
vector<int> particles;
vector<double> weights;
force.getGroupParameters(i, particles, weights);
groupParticleVec.insert(groupParticleVec.end(), particles.begin(), particles.end());
groupOffsetVec.push_back(groupParticleVec.size());
}
vector<vector<double> > normalizedWeights;
CustomCentroidBondForceImpl::computeNormalizedWeights(force, system, normalizedWeights);
if (cu.getUseDoublePrecision()) {
for (int i = 0; i < numGroups; i++)
groupWeightVecDouble.insert(groupWeightVecDouble.end(), normalizedWeights[i].begin(), normalizedWeights[i].end());
}
else {
for (int i = 0; i < numGroups; i++)
for (int j = 0; j < normalizedWeights[i].size(); j++)
groupWeightVecFloat.push_back((float) normalizedWeights[i][j]);
}
groupParticles = CudaArray::create<int>(cu, groupParticleVec.size(), "groupParticles");
groupParticles->upload(groupParticleVec);
if (cu.getUseDoublePrecision()) {
groupWeights = CudaArray::create<double>(cu, groupParticleVec.size(), "groupWeights");
groupWeights->upload(groupWeightVecDouble);
centerPositions = CudaArray::create<double4>(cu, numGroups, "centerPositions");
}
else {
groupWeights = CudaArray::create<float>(cu, groupParticleVec.size(), "groupWeights");
groupWeights->upload(groupWeightVecFloat);
centerPositions = CudaArray::create<float4>(cu, numGroups, "centerPositions");
}
groupOffsets = CudaArray::create<int>(cu, groupOffsetVec.size(), "groupOffsets");
groupOffsets->upload(groupOffsetVec);
groupForces = CudaArray::create<long long>(cu, numGroups*3, "groupForces");
cu.addAutoclearBuffer(*groupForces);
// Record the bonds.
int groupsPerBond = force.getNumGroupsPerBond();
vector<int> bondGroupVec(numBonds*groupsPerBond);
params = new CudaParameterSet(cu, force.getNumPerBondParameters(), numBonds, "customCentroidBondParams");
vector<vector<float> > paramVector(numBonds);
for (int i = 0; i < numBonds; i++) {
vector<int> groups;
vector<double> parameters;
force.getBondParameters(i, groups, parameters);
for (int j = 0; j < groups.size(); j++)
bondGroupVec[i+j*numBonds] = groups[j];
paramVector[i].resize(parameters.size());
for (int j = 0; j < (int) parameters.size(); j++)
paramVector[i][j] = (float) parameters[j];
}
params->setParameterValues(paramVector);
bondGroups = CudaArray::create<int>(cu, bondGroupVec.size(), "bondGroups");
bondGroups->upload(bondGroupVec);
// Record the arguments to the force kernel.
groupForcesArgs.push_back(&groupForces->getDevicePointer());
groupForcesArgs.push_back(NULL); // Energy buffer hasn't been created yet
groupForcesArgs.push_back(¢erPositions->getDevicePointer());
groupForcesArgs.push_back(&bondGroups->getDevicePointer());
// Record the tabulated functions.
map<string, Lepton::CustomFunction*> functions;
vector<pair<string, string> > functionDefinitions;
vector<const TabulatedFunction*> functionList;
stringstream extraArgs;
for (int i = 0; i < force.getNumTabulatedFunctions(); i++) {
functionList.push_back(&force.getTabulatedFunction(i));
string name = force.getTabulatedFunctionName(i);
string arrayName = "table"+cu.intToString(i);
functionDefinitions.push_back(make_pair(name, arrayName));
functions[name] = cu.getExpressionUtilities().getFunctionPlaceholder(force.getTabulatedFunction(i));
int width;
vector<float> f = cu.getExpressionUtilities().computeFunctionCoefficients(force.getTabulatedFunction(i), width);
tabulatedFunctions.push_back(CudaArray::create<float>(cu, f.size(), "TabulatedFunction"));
tabulatedFunctions.back()->upload(f);
extraArgs << ", const float";
if (width > 1)
extraArgs << width;
extraArgs << "* __restrict__ " << arrayName;
groupForcesArgs.push_back(&tabulatedFunctions.back()->getDevicePointer());
}
// Record information about parameters.
globalParamNames.resize(force.getNumGlobalParameters());
globalParamValues.resize(force.getNumGlobalParameters());
for (int i = 0; i < force.getNumGlobalParameters(); i++) {
globalParamNames[i] = force.getGlobalParameterName(i);
globalParamValues[i] = (float) force.getGlobalParameterDefaultValue(i);
}
map<string, string> variables;
for (int i = 0; i < groupsPerBond; i++) {
string index = cu.intToString(i+1);
variables["x"+index] = "pos"+index+".x";
variables["y"+index] = "pos"+index+".y";
variables["z"+index] = "pos"+index+".z";
}
for (int i = 0; i < force.getNumPerBondParameters(); i++) {
const string& name = force.getPerBondParameterName(i);
variables[name] = "bondParams"+params->getParameterSuffix(i);
}
if (force.getNumGlobalParameters() > 0) {
globals = CudaArray::create<float>(cu, force.getNumGlobalParameters(), "customCentroidBondGlobals");
globals->upload(globalParamValues);
extraArgs << ", const float* __restrict__ globals";
for (int i = 0; i < force.getNumGlobalParameters(); i++) {
const string& name = force.getGlobalParameterName(i);
string value = "globals["+cu.intToString(i)+"]";
variables[name] = value;
}
groupForcesArgs.push_back(&globals->getDevicePointer());
}
// Now to generate the kernel. First, it needs to calculate all distances, angles,
// and dihedrals the expression depends on.
map<string, vector<int> > distances;
map<string, vector<int> > angles;
map<string, vector<int> > dihedrals;
Lepton::ParsedExpression energyExpression = CustomCentroidBondForceImpl::prepareExpression(force, functions, distances, angles, dihedrals);
map<string, Lepton::ParsedExpression> forceExpressions;
set<string> computedDeltas;
vector<string> atomNames, posNames;
for (int i = 0; i < groupsPerBond; i++) {
string index = cu.intToString(i+1);
atomNames.push_back("P"+index);
posNames.push_back("pos"+index);
}
stringstream compute;
for (int i = 0; i < groupsPerBond; i++) {
compute<<"int group"<<(i+1)<<" = bondGroups[index+"<<(i*numBonds)<<"];\n";
compute<<"real4 pos"<<(i+1)<<" = centerPositions[group"<<(i+1)<<"];\n";
}
int index = 0;
for (map<string, vector<int> >::const_iterator iter = distances.begin(); iter != distances.end(); ++iter, ++index) {
const vector<int>& groups = iter->second;
string deltaName = atomNames[groups[0]]+atomNames[groups[1]];
if (computedDeltas.count(deltaName) == 0) {
compute<<"real4 delta"<<deltaName<<" = delta("<<posNames[groups[0]]<<", "<<posNames[groups[1]]<<");\n";
computedDeltas.insert(deltaName);
}
compute<<"real r_"<<deltaName<<" = sqrt(delta"<<deltaName<<".w);\n";
variables[iter->first] = "r_"+deltaName;
forceExpressions["real dEdDistance"+cu.intToString(index)+" = "] = energyExpression.differentiate(iter->first).optimize();
}
index = 0;
for (map<string, vector<int> >::const_iterator iter = angles.begin(); iter != angles.end(); ++iter, ++index) {
const vector<int>& groups = iter->second;
string deltaName1 = atomNames[groups[1]]+atomNames[groups[0]];
string deltaName2 = atomNames[groups[1]]+atomNames[groups[2]];
string angleName = "angle_"+atomNames[groups[0]]+atomNames[groups[1]]+atomNames[groups[2]];
if (computedDeltas.count(deltaName1) == 0) {
compute<<"real4 delta"<<deltaName1<<" = delta("<<posNames[groups[1]]<<", "<<posNames[groups[0]]<<");\n";
computedDeltas.insert(deltaName1);
}
if (computedDeltas.count(deltaName2) == 0) {
compute<<"real4 delta"<<deltaName2<<" = delta("<<posNames[groups[1]]<<", "<<posNames[groups[2]]<<");\n";
computedDeltas.insert(deltaName2);
}
compute<<"real "<<angleName<<" = computeAngle(delta"<<deltaName1<<", delta"<<deltaName2<<");\n";
variables[iter->first] = angleName;
forceExpressions["real dEdAngle"+cu.intToString(index)+" = "] = energyExpression.differentiate(iter->first).optimize();
}
index = 0;
for (map<string, vector<int> >::const_iterator iter = dihedrals.begin(); iter != dihedrals.end(); ++iter, ++index) {
const vector<int>& groups = iter->second;
string deltaName1 = atomNames[groups[0]]+atomNames[groups[1]];
string deltaName2 = atomNames[groups[2]]+atomNames[groups[1]];
string deltaName3 = atomNames[groups[2]]+atomNames[groups[3]];
string crossName1 = "cross_"+deltaName1+"_"+deltaName2;
string crossName2 = "cross_"+deltaName2+"_"+deltaName3;
string dihedralName = "dihedral_"+atomNames[groups[0]]+atomNames[groups[1]]+atomNames[groups[2]]+atomNames[groups[3]];
if (computedDeltas.count(deltaName1) == 0) {
compute<<"real4 delta"<<deltaName1<<" = delta("<<posNames[groups[0]]<<", "<<posNames[groups[1]]<<");\n";
computedDeltas.insert(deltaName1);
}
if (computedDeltas.count(deltaName2) == 0) {
compute<<"real4 delta"<<deltaName2<<" = delta("<<posNames[groups[2]]<<", "<<posNames[groups[1]]<<");\n";
computedDeltas.insert(deltaName2);
}
if (computedDeltas.count(deltaName3) == 0) {
compute<<"real4 delta"<<deltaName3<<" = delta("<<posNames[groups[2]]<<", "<<posNames[groups[3]]<<");\n";
computedDeltas.insert(deltaName3);
}
compute<<"real4 "<<crossName1<<" = computeCross(delta"<<deltaName1<<", delta"<<deltaName2<<");\n";
compute<<"real4 "<<crossName2<<" = computeCross(delta"<<deltaName2<<", delta"<<deltaName3<<");\n";
compute<<"real "<<dihedralName<<" = computeAngle("<<crossName1<<", "<<crossName2<<");\n";
compute<<dihedralName<<" *= (delta"<<deltaName1<<".x*"<<crossName2<<".x + delta"<<deltaName1<<".y*"<<crossName2<<".y + delta"<<deltaName1<<".z*"<<crossName2<<".z < 0 ? -1 : 1);\n";
variables[iter->first] = dihedralName;
forceExpressions["real dEdDihedral"+cu.intToString(index)+" = "] = energyExpression.differentiate(iter->first).optimize();
}
// Now evaluate the expressions.
for (int i = 0; i < (int) params->getBuffers().size(); i++) {
CudaNonbondedUtilities::ParameterInfo& buffer = params->getBuffers()[i];
extraArgs<<", const "<<buffer.getType()<<"* __restrict__ globalParams"<<i;
compute<<buffer.getType()<<" bondParams"<<(i+1)<<" = globalParams"<<i<<"[index];\n";
groupForcesArgs.push_back(&buffer.getMemory());
}
forceExpressions["energy += "] = energyExpression;
compute << cu.getExpressionUtilities().createExpressions(forceExpressions, variables, functionList, functionDefinitions, "temp");
// Finally, apply forces to groups.
vector<string> forceNames;
for (int i = 0; i < groupsPerBond; i++) {
string istr = cu.intToString(i+1);
string forceName = "force"+istr;
forceNames.push_back(forceName);
compute<<"real3 "<<forceName<<" = make_real3(0);\n";
compute<<"{\n";
Lepton::ParsedExpression forceExpressionX = energyExpression.differentiate("x"+istr).optimize();
Lepton::ParsedExpression forceExpressionY = energyExpression.differentiate("y"+istr).optimize();
Lepton::ParsedExpression forceExpressionZ = energyExpression.differentiate("z"+istr).optimize();
map<string, Lepton::ParsedExpression> expressions;
if (!isZeroExpression(forceExpressionX))
expressions[forceName+".x -= "] = forceExpressionX;
if (!isZeroExpression(forceExpressionY))
expressions[forceName+".y -= "] = forceExpressionY;
if (!isZeroExpression(forceExpressionZ))
expressions[forceName+".z -= "] = forceExpressionZ;
if (expressions.size() > 0)
compute<<cu.getExpressionUtilities().createExpressions(expressions, variables, functionList, functionDefinitions, "coordtemp");
compute<<"}\n";
}
index = 0;
for (map<string, vector<int> >::const_iterator iter = distances.begin(); iter != distances.end(); ++iter, ++index) {
const vector<int>& groups = iter->second;
string deltaName = atomNames[groups[0]]+atomNames[groups[1]];
string value = "(dEdDistance"+cu.intToString(index)+"/r_"+deltaName+")*trim(delta"+deltaName+")";
compute<<forceNames[groups[0]]<<" += "<<"-"<<value<<";\n";
compute<<forceNames[groups[1]]<<" += "<<value<<";\n";
}
index = 0;
for (map<string, vector<int> >::const_iterator iter = angles.begin(); iter != angles.end(); ++iter, ++index) {
const vector<int>& groups = iter->second;
string deltaName1 = atomNames[groups[1]]+atomNames[groups[0]];
string deltaName2 = atomNames[groups[1]]+atomNames[groups[2]];
compute<<"{\n";
compute<<"real3 crossProd = cross(delta"<<deltaName2<<", delta"<<deltaName1<<");\n";
compute<<"real lengthCross = max(SQRT(dot(crossProd, crossProd)), 1e-6f);\n";
compute<<"real3 deltaCross0 = -cross(trim(delta"<<deltaName1<<"), crossProd)*dEdAngle"<<cu.intToString(index)<<"/(delta"<<deltaName1<<".w*lengthCross);\n";
compute<<"real3 deltaCross2 = cross(trim(delta"<<deltaName2<<"), crossProd)*dEdAngle"<<cu.intToString(index)<<"/(delta"<<deltaName2<<".w*lengthCross);\n";
compute<<"real3 deltaCross1 = -(deltaCross0+deltaCross2);\n";
compute<<forceNames[groups[0]]<<" += deltaCross0;\n";
compute<<forceNames[groups[1]]<<" += deltaCross1;\n";
compute<<forceNames[groups[2]]<<" += deltaCross2;\n";
compute<<"}\n";
}
index = 0;
for (map<string, vector<int> >::const_iterator iter = dihedrals.begin(); iter != dihedrals.end(); ++iter, ++index) {
const vector<int>& groups = iter->second;
string deltaName1 = atomNames[groups[0]]+atomNames[groups[1]];
string deltaName2 = atomNames[groups[2]]+atomNames[groups[1]];
string deltaName3 = atomNames[groups[2]]+atomNames[groups[3]];
string crossName1 = "cross_"+deltaName1+"_"+deltaName2;
string crossName2 = "cross_"+deltaName2+"_"+deltaName3;
compute<<"{\n";
compute<<"real r = sqrt(delta"<<deltaName2<<".w);\n";
compute<<"real4 ff;\n";
compute<<"ff.x = (-dEdDihedral"<<cu.intToString(index)<<"*r)/"<<crossName1<<".w;\n";
compute<<"ff.y = (delta"<<deltaName1<<".x*delta"<<deltaName2<<".x + delta"<<deltaName1<<".y*delta"<<deltaName2<<".y + delta"<<deltaName1<<".z*delta"<<deltaName2<<".z)/delta"<<deltaName2<<".w;\n";
compute<<"ff.z = (delta"<<deltaName3<<".x*delta"<<deltaName2<<".x + delta"<<deltaName3<<".y*delta"<<deltaName2<<".y + delta"<<deltaName3<<".z*delta"<<deltaName2<<".z)/delta"<<deltaName2<<".w;\n";
compute<<"ff.w = (dEdDihedral"<<cu.intToString(index)<<"*r)/"<<crossName2<<".w;\n";
compute<<"real3 internalF0 = ff.x*trim("<<crossName1<<");\n";
compute<<"real3 internalF3 = ff.w*trim("<<crossName2<<");\n";
compute<<"real3 s = ff.y*internalF0 - ff.z*internalF3;\n";
compute<<forceNames[groups[0]]<<" += internalF0;\n";
compute<<forceNames[groups[1]]<<" += s-internalF0;\n";
compute<<forceNames[groups[2]]<<" += -s-internalF3;\n";
compute<<forceNames[groups[3]]<<" += internalF3;\n";
compute<<"}\n";
}
// Save the forces to global memory.
for (int i = 0; i < groupsPerBond; i++) {
compute<<"atomicAdd(&groupForce[group"<<(i+1)<<"], static_cast<unsigned long long>((long long) (force"<<(i+1)<<".x*0x100000000)));\n";
compute<<"atomicAdd(&groupForce[group"<<(i+1)<<"+NUM_GROUPS], static_cast<unsigned long long>((long long) (force"<<(i+1)<<".y*0x100000000)));\n";
compute<<"atomicAdd(&groupForce[group"<<(i+1)<<"+NUM_GROUPS*2], static_cast<unsigned long long>((long long) (force"<<(i+1)<<".z*0x100000000)));\n";
compute<<"__threadfence_block();\n";
}
map<string, string> replacements;
replacements["M_PI"] = cu.doubleToString(M_PI);
replacements["NUM_GROUPS"] = cu.intToString(numGroups);
replacements["NUM_BONDS"] = cu.intToString(numBonds);
replacements["PADDED_NUM_ATOMS"] = cu.intToString(cu.getPaddedNumAtoms());
replacements["EXTRA_ARGS"] = extraArgs.str();
replacements["COMPUTE_FORCE"] = compute.str();
CUmodule module = cu.createModule(CudaKernelSources::vectorOps+cu.replaceStrings(CudaKernelSources::customCentroidBond, replacements));
computeCentersKernel = cu.getKernel(module, "computeGroupCenters");
groupForcesKernel = cu.getKernel(module, "computeGroupForces");
applyForcesKernel = cu.getKernel(module, "applyForcesToAtoms");
}
double CudaCalcCustomCentroidBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
if (globals != NULL) {
bool changed = false;
for (int i = 0; i < (int) globalParamNames.size(); i++) {
float value = (float) context.getParameter(globalParamNames[i]);
if (value != globalParamValues[i])
changed = true;
globalParamValues[i] = value;
}
if (changed)
globals->upload(globalParamValues);
}
void* computeCentersArgs[] = {&cu.getPosq().getDevicePointer(), &groupParticles->getDevicePointer(), &groupWeights->getDevicePointer(),
&groupOffsets->getDevicePointer(), ¢erPositions->getDevicePointer()};
cu.executeKernel(computeCentersKernel, computeCentersArgs, CudaContext::TileSize*numGroups);
groupForcesArgs[1] = &cu.getEnergyBuffer().getDevicePointer();
cu.executeKernel(groupForcesKernel, &groupForcesArgs[0], numBonds);
void* applyForcesArgs[] = {&groupParticles->getDevicePointer(), &groupWeights->getDevicePointer(), &groupOffsets->getDevicePointer(),
&groupForces->getDevicePointer(), &cu.getForce().getDevicePointer()};
cu.executeKernel(applyForcesKernel, applyForcesArgs, CudaContext::TileSize*numGroups);
return 0.0;
}
void CudaCalcCustomCentroidBondForceKernel::copyParametersToContext(ContextImpl& context, const CustomCentroidBondForce& force) {
cu.setAsCurrent();
int numContexts = cu.getPlatformData().contexts.size();
int startIndex = cu.getContextIndex()*force.getNumBonds()/numContexts;
int endIndex = (cu.getContextIndex()+1)*force.getNumBonds()/numContexts;
if (numBonds != endIndex-startIndex)
throw OpenMMException("updateParametersInContext: The number of bonds has changed");
if (numBonds == 0)
return;
// Record the per-bond parameters.
vector<vector<float> > paramVector(numBonds);
vector<int> particles;
vector<double> parameters;
for (int i = 0; i < numBonds; i++) {
force.getBondParameters(startIndex+i, particles, parameters);
paramVector[i].resize(parameters.size());
for (int j = 0; j < (int) parameters.size(); j++)
paramVector[i][j] = (float) parameters[j];
}
params->setParameterValues(paramVector);
// Mark that the current reordering may be invalid.
cu.invalidateMolecules();
}
class CudaCustomCompoundBondForceInfo : public CudaForceInfo {
public:
CudaCustomCompoundBondForceInfo(const CustomCompoundBondForce& force) : force(force) {
...
...
@@ -4304,7 +4717,6 @@ void CudaCalcCustomCompoundBondForceKernel::initialize(const System& system, con
map<string, Lepton::CustomFunction*> functions;
vector<pair<string, string> > functionDefinitions;
vector<const TabulatedFunction*> functionList;
stringstream tableArgs;
for (int i = 0; i < force.getNumTabulatedFunctions(); i++) {
functionList.push_back(&force.getTabulatedFunction(i));
string name = force.getTabulatedFunctionName(i);
...
...
@@ -4507,7 +4919,7 @@ void CudaCalcCustomCompoundBondForceKernel::initialize(const System& system, con
cu.getBondedUtilities().addInteraction(atoms, compute.str(), force.getForceGroup());
map<string, string> replacements;
replacements["M_PI"] = cu.doubleToString(M_PI);
cu.getBondedUtilities().addPrefixCode(cu.replaceStrings(CudaKernelSources::customCompoundBond, replacements));
;
cu.getBondedUtilities().addPrefixCode(cu.replaceStrings(CudaKernelSources::customCompoundBond, replacements));
}
double CudaCalcCustomCompoundBondForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
...
...
platforms/cuda/src/CudaPlatform.cpp
View file @
4d823b0a
...
...
@@ -80,6 +80,7 @@ CudaPlatform::CudaPlatform() {
registerKernelFactory
(
CalcCustomGBForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomExternalForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomHbondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomCentroidBondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomCompoundBondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateVerletStepKernel
::
Name
(),
factory
);
...
...
platforms/cuda/src/kernels/customCentroidBond.cu
0 → 100644
View file @
4d823b0a
/**
* Compute the center of each group.
*/
extern
"C"
__global__
void
computeGroupCenters
(
const
real4
*
__restrict__
posq
,
const
int
*
__restrict__
groupParticles
,
const
real
*
__restrict__
groupWeights
,
const
int
*
__restrict__
groupOffsets
,
real4
*
__restrict__
centerPositions
)
{
__shared__
volatile
real3
temp
[
64
];
for
(
int
group
=
blockIdx
.
x
;
group
<
NUM_GROUPS
;
group
+=
gridDim
.
x
)
{
// The threads in this block work together to compute the center one group.
int
firstIndex
=
groupOffsets
[
group
];
int
lastIndex
=
groupOffsets
[
group
+
1
];
real3
center
=
make_real3
(
0
,
0
,
0
);
for
(
int
index
=
threadIdx
.
x
;
index
<
lastIndex
-
firstIndex
;
index
+=
blockDim
.
x
)
{
int
atom
=
groupParticles
[
firstIndex
+
index
];
real
weight
=
groupWeights
[
firstIndex
+
index
];
real4
pos
=
posq
[
atom
];
center
.
x
+=
weight
*
pos
.
x
;
center
.
y
+=
weight
*
pos
.
y
;
center
.
z
+=
weight
*
pos
.
z
;
}
// Sum the values.
int
thread
=
threadIdx
.
x
;
temp
[
thread
].
x
=
center
.
x
;
temp
[
thread
].
y
=
center
.
y
;
temp
[
thread
].
z
=
center
.
z
;
__syncthreads
();
if
(
thread
<
32
)
{
temp
[
thread
].
x
+=
temp
[
thread
+
32
].
x
;
temp
[
thread
].
y
+=
temp
[
thread
+
32
].
y
;
temp
[
thread
].
z
+=
temp
[
thread
+
32
].
z
;
if
(
thread
<
16
)
{
temp
[
thread
].
x
+=
temp
[
thread
+
16
].
x
;
temp
[
thread
].
y
+=
temp
[
thread
+
16
].
y
;
temp
[
thread
].
z
+=
temp
[
thread
+
16
].
z
;
}
if
(
thread
<
8
)
{
temp
[
thread
].
x
+=
temp
[
thread
+
8
].
x
;
temp
[
thread
].
y
+=
temp
[
thread
+
8
].
y
;
temp
[
thread
].
z
+=
temp
[
thread
+
8
].
z
;
}
if
(
thread
<
4
)
{
temp
[
thread
].
x
+=
temp
[
thread
+
4
].
x
;
temp
[
thread
].
y
+=
temp
[
thread
+
4
].
y
;
temp
[
thread
].
z
+=
temp
[
thread
+
4
].
z
;
}
if
(
thread
<
2
)
{
temp
[
thread
].
x
+=
temp
[
thread
+
2
].
x
;
temp
[
thread
].
y
+=
temp
[
thread
+
2
].
y
;
temp
[
thread
].
z
+=
temp
[
thread
+
2
].
z
;
}
}
if
(
thread
==
0
)
centerPositions
[
group
]
=
make_real4
(
temp
[
0
].
x
+
temp
[
1
].
x
,
temp
[
0
].
y
+
temp
[
1
].
y
,
temp
[
0
].
z
+
temp
[
1
].
z
,
0
);
}
}
/**
* Convert a real4 to a real3 by removing its last element.
*/
inline
__device__
real3
trim
(
real4
v
)
{
return
make_real3
(
v
.
x
,
v
.
y
,
v
.
z
);
}
/**
* Compute the difference between two vectors, setting the fourth component to the squared magnitude.
*/
inline
__device__
real4
delta
(
real4
vec1
,
real4
vec2
)
{
real4
result
=
make_real4
(
vec1
.
x
-
vec2
.
x
,
vec1
.
y
-
vec2
.
y
,
vec1
.
z
-
vec2
.
z
,
0
);
result
.
w
=
result
.
x
*
result
.
x
+
result
.
y
*
result
.
y
+
result
.
z
*
result
.
z
;
return
result
;
}
/**
* Compute the angle between two vectors. The w component of each vector should contain the squared magnitude.
*/
__device__
real
computeAngle
(
real4
vec1
,
real4
vec2
)
{
real
dotProduct
=
vec1
.
x
*
vec2
.
x
+
vec1
.
y
*
vec2
.
y
+
vec1
.
z
*
vec2
.
z
;
real
cosine
=
dotProduct
*
RSQRT
(
vec1
.
w
*
vec2
.
w
);
real
angle
;
if
(
cosine
>
0.99
f
||
cosine
<
-
0.99
f
)
{
// We're close to the singularity in acos(), so take the cross product and use asin() instead.
real3
crossProduct
=
cross
(
vec1
,
vec2
);
real
scale
=
vec1
.
w
*
vec2
.
w
;
angle
=
ASIN
(
SQRT
(
dot
(
crossProduct
,
crossProduct
)
/
scale
));
if
(
cosine
<
0.0
f
)
angle
=
M_PI
-
angle
;
}
else
angle
=
ACOS
(
cosine
);
return
angle
;
}
/**
* Compute the cross product of two vectors, setting the fourth component to the squared magnitude.
*/
inline
__device__
real4
computeCross
(
real4
vec1
,
real4
vec2
)
{
real3
cp
=
cross
(
vec1
,
vec2
);
return
make_real4
(
cp
.
x
,
cp
.
y
,
cp
.
z
,
cp
.
x
*
cp
.
x
+
cp
.
y
*
cp
.
y
+
cp
.
z
*
cp
.
z
);
}
/**
* Compute the forces on groups based on the bonds.
*/
extern
"C"
__global__
void
computeGroupForces
(
unsigned
long
long
*
__restrict__
groupForce
,
real
*
__restrict__
energyBuffer
,
const
real4
*
__restrict__
centerPositions
,
const
int
*
__restrict__
bondGroups
EXTRA_ARGS
)
{
extern
__shared__
real4
posBuffer
[];
real
energy
=
0
;
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
NUM_BONDS
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
COMPUTE_FORCE
}
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
]
+=
energy
;
}
/**
* Apply the forces from the group centers to the individual atoms.
*/
extern
"C"
__global__
void
applyForcesToAtoms
(
const
int
*
__restrict__
groupParticles
,
const
real
*
__restrict__
groupWeights
,
const
int
*
__restrict__
groupOffsets
,
const
long
long
*
__restrict__
groupForce
,
unsigned
long
long
*
__restrict__
atomForce
)
{
for
(
int
group
=
blockIdx
.
x
;
group
<
NUM_GROUPS
;
group
+=
gridDim
.
x
)
{
long
long
fx
=
groupForce
[
group
];
long
long
fy
=
groupForce
[
group
+
NUM_GROUPS
];
long
long
fz
=
groupForce
[
group
+
NUM_GROUPS
*
2
];
int
firstIndex
=
groupOffsets
[
group
];
int
lastIndex
=
groupOffsets
[
group
+
1
];
for
(
int
index
=
threadIdx
.
x
;
index
<
lastIndex
-
firstIndex
;
index
+=
blockDim
.
x
)
{
int
atom
=
groupParticles
[
firstIndex
+
index
];
real
weight
=
groupWeights
[
firstIndex
+
index
];
atomicAdd
(
&
atomForce
[
atom
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
fx
*
weight
)));
atomicAdd
(
&
atomForce
[
atom
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
fy
*
weight
)));
atomicAdd
(
&
atomForce
[
atom
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
fz
*
weight
)));
}
}
}
platforms/cuda/tests/TestCudaCustomCentroidBondForce.cpp
0 → 100644
View file @
4d823b0a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
/**
* This tests the reference implementation of CustomCompoundBondForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "CudaPlatform.h"
#include "openmm/CustomCentroidBondForce.h"
#include "openmm/CustomCompoundBondForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using
namespace
OpenMM
;
using
namespace
std
;
CudaPlatform
platform
;
const
double
TOL
=
1e-5
;
void
testHarmonicBond
()
{
System
system
;
system
.
addParticle
(
1.0
);
system
.
addParticle
(
2.0
);
system
.
addParticle
(
3.0
);
system
.
addParticle
(
4.0
);
system
.
addParticle
(
5.0
);
CustomCentroidBondForce
*
force
=
new
CustomCentroidBondForce
(
2
,
"k*distance(g1,g2)^2"
);
force
->
addPerBondParameter
(
"k"
);
vector
<
int
>
particles1
;
particles1
.
push_back
(
0
);
particles1
.
push_back
(
1
);
vector
<
int
>
particles2
;
particles2
.
push_back
(
2
);
particles2
.
push_back
(
3
);
particles2
.
push_back
(
4
);
force
->
addGroup
(
particles1
);
force
->
addGroup
(
particles2
);
vector
<
int
>
groups
;
groups
.
push_back
(
0
);
groups
.
push_back
(
1
);
vector
<
double
>
parameters
;
parameters
.
push_back
(
1.0
);
force
->
addBond
(
groups
,
parameters
);
system
.
addForce
(
force
);
ASSERT
(
!
system
.
usesPeriodicBoundaryConditions
());
// The center of mass of group 0 is (1.5, 0, 0).
vector
<
Vec3
>
positions
(
5
);
positions
[
0
]
=
Vec3
(
2.5
,
0
,
0
);
positions
[
1
]
=
Vec3
(
1
,
0
,
0
);
// The center of mass of group 1 is (-1, 0, 0).
positions
[
2
]
=
Vec3
(
-
6
,
0
,
0
);
positions
[
3
]
=
Vec3
(
-
1
,
0
,
0
);
positions
[
4
]
=
Vec3
(
2
,
0
,
0
);
// Check the forces and energy.
VerletIntegrator
integrator
(
0.01
);
Context
context
(
system
,
integrator
,
platform
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
2.5
*
2.5
,
state
.
getPotentialEnergy
(),
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
-
2
*
2.5
*
(
1.0
/
3.0
),
0
,
0
),
state
.
getForces
()[
0
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
-
2
*
2.5
*
(
2.0
/
3.0
),
0
,
0
),
state
.
getForces
()[
1
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
2
*
2.5
*
(
3.0
/
12.0
),
0
,
0
),
state
.
getForces
()[
2
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
2
*
2.5
*
(
4.0
/
12.0
),
0
,
0
),
state
.
getForces
()[
3
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
2
*
2.5
*
(
5.0
/
12.0
),
0
,
0
),
state
.
getForces
()[
4
],
TOL
);
// Update the per-bond parameter and see if the results change.
parameters
[
0
]
=
2.0
;
force
->
setBondParameters
(
0
,
groups
,
parameters
);
force
->
updateParametersInContext
(
context
);
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
2
*
2.5
*
2.5
,
state
.
getPotentialEnergy
(),
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
-
4
*
2.5
*
(
1.0
/
3.0
),
0
,
0
),
state
.
getForces
()[
0
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
-
4
*
2.5
*
(
2.0
/
3.0
),
0
,
0
),
state
.
getForces
()[
1
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
4
*
2.5
*
(
3.0
/
12.0
),
0
,
0
),
state
.
getForces
()[
2
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
4
*
2.5
*
(
4.0
/
12.0
),
0
,
0
),
state
.
getForces
()[
3
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
4
*
2.5
*
(
5.0
/
12.0
),
0
,
0
),
state
.
getForces
()[
4
],
TOL
);
}
void
testComplexFunction
()
{
int
numParticles
=
4
;
System
system
;
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
system
.
addParticle
(
2.0
);
// When every group contains only one particle, a CustomCentroidBondForce is identical to a
// CustomCompoundBondForce. Use that to test a complicated energy function with lots of terms.
CustomCompoundBondForce
*
compound
=
new
CustomCompoundBondForce
(
4
,
"x1+y2+z4+distance(p1,p2)*angle(p3,p2,p4)+0.5*dihedral(p2,p1,p4,p3)"
);
CustomCentroidBondForce
*
centroid
=
new
CustomCentroidBondForce
(
4
,
"x1+y2+z4+distance(g1,g2)*angle(g3,g2,g4)+0.5*dihedral(g2,g1,g4,g3)"
);
// Add a single bond to the CustomCompoundBondForce.
vector
<
int
>
particles
(
4
);
vector
<
double
>
parameters
;
particles
[
0
]
=
0
;
particles
[
1
]
=
1
;
particles
[
2
]
=
2
;
particles
[
3
]
=
3
;
compound
->
addBond
(
particles
,
parameters
);
// Add an identical bond to the CustomCentroidBondForce. As a stronger test, make sure that
// group number is different from particle number.
vector
<
int
>
groupMembers
(
1
);
groupMembers
[
0
]
=
3
;
centroid
->
addGroup
(
groupMembers
);
groupMembers
[
0
]
=
0
;
centroid
->
addGroup
(
groupMembers
);
groupMembers
[
0
]
=
1
;
centroid
->
addGroup
(
groupMembers
);
groupMembers
[
0
]
=
2
;
centroid
->
addGroup
(
groupMembers
);
vector
<
int
>
groups
(
4
);
groups
[
0
]
=
1
;
groups
[
1
]
=
2
;
groups
[
2
]
=
3
;
groups
[
3
]
=
0
;
centroid
->
addBond
(
groups
,
parameters
);
// Add both forces as different force groups, and create a context.
centroid
->
setForceGroup
(
1
);
system
.
addForce
(
compound
);
system
.
addForce
(
centroid
);
VerletIntegrator
integrator
(
0.01
);
Context
context
(
system
,
integrator
,
platform
);
// Evaluate the force and energy for various positions and see if they match.
OpenMM_SFMT
::
SFMT
sfmt
;
init_gen_rand
(
0
,
sfmt
);
vector
<
Vec3
>
positions
(
numParticles
);
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
for
(
int
j
=
0
;
j
<
numParticles
;
j
++
)
positions
[
j
]
=
Vec3
(
5.0
*
genrand_real2
(
sfmt
),
5.0
*
genrand_real2
(
sfmt
),
5.0
*
genrand_real2
(
sfmt
));
context
.
setPositions
(
positions
);
State
state1
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
,
false
,
1
<<
0
);
State
state2
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
,
false
,
1
<<
1
);
ASSERT_EQUAL_TOL
(
state1
.
getPotentialEnergy
(),
state2
.
getPotentialEnergy
(),
TOL
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
ASSERT_EQUAL_VEC
(
state1
.
getForces
()[
i
],
state2
.
getForces
()[
i
],
TOL
);
}
}
void
testCustomWeights
()
{
System
system
;
system
.
addParticle
(
1.0
);
system
.
addParticle
(
2.0
);
system
.
addParticle
(
3.0
);
system
.
addParticle
(
4.0
);
CustomCentroidBondForce
*
force
=
new
CustomCentroidBondForce
(
2
,
"distance(g1,g2)^2"
);
vector
<
int
>
particles
(
2
);
vector
<
double
>
weights
(
2
);
particles
[
0
]
=
0
;
particles
[
1
]
=
1
;
weights
[
0
]
=
0.5
;
weights
[
1
]
=
1.5
;
force
->
addGroup
(
particles
,
weights
);
particles
[
0
]
=
2
;
particles
[
1
]
=
3
;
weights
[
0
]
=
2.0
;
weights
[
1
]
=
1.0
;
force
->
addGroup
(
particles
,
weights
);
vector
<
int
>
groups
;
groups
.
push_back
(
0
);
groups
.
push_back
(
1
);
vector
<
double
>
parameters
;
force
->
addBond
(
groups
,
parameters
);
system
.
addForce
(
force
);
// The center of mass of group 0 is (0, 1, 0).
vector
<
Vec3
>
positions
(
4
);
positions
[
0
]
=
Vec3
(
0
,
4
,
0
);
positions
[
1
]
=
Vec3
(
0
,
0
,
0
);
// The center of mass of group 1 is (0, 10, 0).
positions
[
2
]
=
Vec3
(
0
,
9
,
0
);
positions
[
3
]
=
Vec3
(
0
,
12
,
0
);
// Check the forces and energy.
VerletIntegrator
integrator
(
0.01
);
Context
context
(
system
,
integrator
,
platform
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
9
*
9
,
state
.
getPotentialEnergy
(),
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
2
*
9
*
(
0.5
/
2.0
),
0
),
state
.
getForces
()[
0
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
2
*
9
*
(
1.5
/
2.0
),
0
),
state
.
getForces
()[
1
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
-
2
*
9
*
(
2.0
/
3.0
),
0
),
state
.
getForces
()[
2
],
TOL
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
-
2
*
9
*
(
1.0
/
3.0
),
0
),
state
.
getForces
()[
3
],
TOL
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
try
{
if
(
argc
>
1
)
platform
.
setPropertyDefaultValue
(
"CudaPrecision"
,
string
(
argv
[
1
]));
testHarmonicBond
();
testComplexFunction
();
testCustomWeights
();
}
catch
(
const
exception
&
e
)
{
cout
<<
"exception: "
<<
e
.
what
()
<<
endl
;
return
1
;
}
cout
<<
"Done"
<<
endl
;
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment