"csrc/pybind/rope_general_bwd_pybind.cu" did not exist on "ae0b35213cd4844e3e333121823744fe9e93c38d"
Commit 1f7866ad authored by peastman's avatar peastman Committed by GitHub
Browse files

Merge pull request #1547 from peastman/paramderivs

Energy derivatives with respect to global parameters
parents 37787af9 7851bad8
......@@ -104,6 +104,20 @@ void CustomCentroidBondForce::setGlobalParameterDefaultValue(int index, double d
globalParameters[index].defaultValue = defaultValue;
}
void CustomCentroidBondForce::addEnergyParameterDerivative(const string& name) {
for (int i = 0; i < globalParameters.size(); i++)
if (name == globalParameters[i].name) {
energyParameterDerivatives.push_back(i);
return;
}
throw OpenMMException(string("addEnergyParameterDerivative: Unknown global parameter '"+name+"'"));
}
const string& CustomCentroidBondForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomCentroidBondForce::addGroup(const vector<int>& particles, const vector<double>& weights) {
if (particles.size() != weights.size() && weights.size() > 0)
throw OpenMMException("CustomCentroidBondForce: wrong number of weights specified for a group.");
......
......@@ -105,6 +105,20 @@ void CustomCompoundBondForce::setGlobalParameterDefaultValue(int index, double d
globalParameters[index].defaultValue = defaultValue;
}
void CustomCompoundBondForce::addEnergyParameterDerivative(const string& name) {
for (int i = 0; i < globalParameters.size(); i++)
if (name == globalParameters[i].name) {
energyParameterDerivatives.push_back(i);
return;
}
throw OpenMMException(string("addEnergyParameterDerivative: Unknown global parameter '"+name+"'"));
}
const string& CustomCompoundBondForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomCompoundBondForce::addBond(const vector<int>& particles, const vector<double>& parameters) {
if (particles.size() != particlesPerBond)
throw OpenMMException("CustomCompoundBondForce: wrong number of particles specified for a bond.");
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2014 Stanford University and the Authors. *
* Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -111,6 +111,20 @@ void CustomGBForce::setGlobalParameterDefaultValue(int index, double defaultValu
globalParameters[index].defaultValue = defaultValue;
}
void CustomGBForce::addEnergyParameterDerivative(const string& name) {
for (int i = 0; i < globalParameters.size(); i++)
if (name == globalParameters[i].name) {
energyParameterDerivatives.push_back(i);
return;
}
throw OpenMMException(string("addEnergyParameterDerivative: Unknown global parameter '"+name+"'"));
}
const string& CustomGBForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomGBForce::addParticle(const vector<double>& parameters) {
particles.push_back(ParticleInfo(parameters));
return particles.size()-1;
......
......@@ -6,7 +6,7 @@
* 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. *
* Portions copyright (c) 2015-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -34,6 +34,7 @@
#include "openmm/internal/ForceImpl.h"
#include "lepton/Operation.h"
#include "lepton/Parser.h"
#include <algorithm>
#include <set>
#include <sstream>
......@@ -81,6 +82,9 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
forceGroup.resize(numSteps, -2);
vector<CustomIntegrator::ComputationType> stepType(numSteps);
vector<string> stepVariable(numSteps);
map<string, Lepton::CustomFunction*> customFunctions;
DerivFunction derivFunction;
customFunctions["deriv"] = &derivFunction;
// Parse the expressions.
......@@ -92,11 +96,11 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
string lhs, rhs;
parseCondition(expression, lhs, rhs, comparisons[step]);
expressions[step].push_back(Lepton::Parser::parse(lhs).optimize());
expressions[step].push_back(Lepton::Parser::parse(rhs).optimize());
expressions[step].push_back(Lepton::Parser::parse(lhs, customFunctions).optimize());
expressions[step].push_back(Lepton::Parser::parse(rhs, customFunctions).optimize());
}
else if (expression.size() > 0)
expressions[step].push_back(Lepton::Parser::parse(expression).optimize());
expressions[step].push_back(Lepton::Parser::parse(expression, customFunctions).optimize());
}
// Identify which steps invalidate the forces.
......@@ -191,6 +195,14 @@ void CustomIntegratorUtilities::analyzeComputations(const ContextImpl& context,
vector<int> jumps(numSteps, -1);
vector<int> stepsInPath;
enumeratePaths(0, stepsInPath, jumps, blockEnd, stepType, needsForces, needsEnergy, invalidatesForces, forceGroup, computeBoth);
// Make sure calls to deriv() all valid.
vector<string> derivNames = energyGroupName;
derivNames.push_back("energy");
for (int i = 0; i < expressions.size(); i++)
for (int j = 0; j < expressions[i].size(); j++)
validateDerivatives(expressions[i][j].getRootNode(), derivNames);
}
void CustomIntegratorUtilities::enumeratePaths(int firstStep, vector<int> steps, vector<int> jumps, const vector<int>& blockEnd,
......@@ -265,3 +277,18 @@ void CustomIntegratorUtilities::analyzeForceComputationsForPath(vector<int>& ste
}
}
}
void CustomIntegratorUtilities::validateDerivatives(const Lepton::ExpressionTreeNode& node, const vector<string>& derivNames) {
const Lepton::Operation& op = node.getOperation();
if (op.getId() == Lepton::Operation::CUSTOM && op.getName() == "deriv") {
const Lepton::Operation& child = node.getChildren()[0].getOperation();
if (child.getId() != Lepton::Operation::VARIABLE || find(derivNames.begin(), derivNames.end(), child.getName()) == derivNames.end())
throw OpenMMException("The first argument to deriv() must be an energy variable");
if (node.getChildren()[1].getOperation().getId() != Lepton::Operation::VARIABLE)
throw OpenMMException("The second argument to deriv() must be a context parameter");
}
else {
for (int i = 0; i < node.getChildren().size(); i++)
validateDerivatives(node.getChildren()[i], derivNames);
}
}
......@@ -61,6 +61,7 @@ CustomNonbondedForce::CustomNonbondedForce(const CustomNonbondedForce& rhs) {
useLongRangeCorrection = rhs.useLongRangeCorrection;
parameters = rhs.parameters;
globalParameters = rhs.globalParameters;
energyParameterDerivatives = rhs.energyParameterDerivatives;
particles = rhs.particles;
exclusions = rhs.exclusions;
interactionGroups = rhs.interactionGroups;
......@@ -161,6 +162,20 @@ void CustomNonbondedForce::setGlobalParameterDefaultValue(int index, double defa
globalParameters[index].defaultValue = defaultValue;
}
void CustomNonbondedForce::addEnergyParameterDerivative(const string& name) {
for (int i = 0; i < globalParameters.size(); i++)
if (name == globalParameters[i].name) {
energyParameterDerivatives.push_back(i);
return;
}
throw OpenMMException(string("addEnergyParameterDerivative: Unknown global parameter '"+name+"'"));
}
const string& CustomNonbondedForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomNonbondedForce::addParticle(const vector<double>& parameters) {
particles.push_back(ParticleInfo(parameters));
return particles.size()-1;
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2014 Stanford University and the Authors. *
* Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -157,16 +157,11 @@ void CustomNonbondedForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcCustomNonbondedForceKernel>().copyParametersToContext(context, owner);
}
double CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context) {
if (force.getNonbondedMethod() == CustomNonbondedForce::NoCutoff || force.getNonbondedMethod() == CustomNonbondedForce::CutoffNonPeriodic)
return 0.0;
// Parse the energy expression.
map<string, Lepton::CustomFunction*> functions;
for (int i = 0; i < force.getNumFunctions(); i++)
functions[force.getTabulatedFunctionName(i)] = createReferenceTabulatedFunction(force.getTabulatedFunction(i));
Lepton::CompiledExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).createCompiledExpression();
void CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context, double& coefficient, vector<double>& derivatives) {
if (force.getNonbondedMethod() == CustomNonbondedForce::NoCutoff || force.getNonbondedMethod() == CustomNonbondedForce::CutoffNonPeriodic) {
coefficient = 0.0;
return;
}
// Identify all particle classes (defined by parameters), and record the class of each particle.
......@@ -224,16 +219,34 @@ double CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedFo
}
}
// Loop over all pairs of classes to compute the coefficient.
// Compute the coefficient.
map<string, Lepton::CustomFunction*> functions;
for (int i = 0; i < force.getNumFunctions(); i++)
functions[force.getTabulatedFunctionName(i)] = createReferenceTabulatedFunction(force.getTabulatedFunction(i));
double nPart = (double) numParticles;
double numInteractions = (nPart*(nPart+1))/2;
Lepton::CompiledExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).createCompiledExpression();
double sum = 0;
for (int i = 0; i < numClasses; i++)
for (int j = i; j < numClasses; j++)
sum += interactionCount[make_pair(i, j)]*integrateInteraction(expression, classes[i], classes[j], force, context);
double nPart = (double) numParticles;
double numInteractions = (nPart*(nPart+1))/2;
sum /= numInteractions;
return 2*M_PI*nPart*nPart*sum;
coefficient = 2*M_PI*nPart*nPart*sum;
// Now do the same for parameter derivatives.
int numDerivs = force.getNumEnergyParameterDerivatives();
derivatives.resize(numDerivs);
for (int k = 0; k < numDerivs; k++) {
expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).differentiate(force.getEnergyParameterDerivativeName(k)).createCompiledExpression();
sum = 0;
for (int i = 0; i < numClasses; i++)
for (int j = i; j < numClasses; j++)
sum += interactionCount[make_pair(i, j)]*integrateInteraction(expression, classes[i], classes[j], force, context);
sum /= numInteractions;
derivatives[k] = 2*M_PI*nPart*nPart*sum;
}
}
double CustomNonbondedForceImpl::integrateInteraction(Lepton::CompiledExpression& expression, const vector<double>& params1, const vector<double>& params2,
......
......@@ -95,6 +95,20 @@ void CustomTorsionForce::setGlobalParameterDefaultValue(int index, double defaul
globalParameters[index].defaultValue = defaultValue;
}
void CustomTorsionForce::addEnergyParameterDerivative(const string& name) {
for (int i = 0; i < globalParameters.size(); i++)
if (name == globalParameters[i].name) {
energyParameterDerivatives.push_back(i);
return;
}
throw OpenMMException(string("addEnergyParameterDerivative: Unknown global parameter '"+name+"'"));
}
const string& CustomTorsionForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomTorsionForce::addTorsion(int particle1, int particle2, int particle3, int particle4, const vector<double>& parameters) {
torsions.push_back(TorsionInfo(particle1, particle2, particle3, particle4, parameters));
return torsions.size()-1;
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008 Stanford University and the Authors. *
* Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -76,6 +76,11 @@ const map<string, double>& State::getParameters() const {
throw OpenMMException("Invoked getParameters() on a State which does not contain parameters.");
return parameters;
}
const map<string, double>& State::getEnergyParameterDerivatives() const {
if ((types&ParameterDerivatives) == 0)
throw OpenMMException("Invoked getEnergyParameterDerivatives() on a State which does not contain parameter derivatives.");
return energyParameterDerivatives;
}
int State::getDataTypes() const {
return types;
}
......@@ -103,6 +108,11 @@ void State::setParameters(const std::map<std::string, double>& params) {
types |= Parameters;
}
void State::setEnergyParameterDerivatives(const std::map<std::string, double>& derivs) {
energyParameterDerivatives = derivs;
types |= ParameterDerivatives;
}
void State::setEnergy(double kinetic, double potential) {
ke = kinetic;
pe = potential;
......@@ -138,6 +148,10 @@ void State::StateBuilder::setParameters(const std::map<std::string, double>& par
state.setParameters(params);
}
void State::StateBuilder::setEnergyParameterDerivatives(const std::map<std::string, double>& derivs) {
state.setEnergyParameterDerivatives(derivs);
}
void State::StateBuilder::setEnergy(double ke, double pe) {
state.setEnergy(ke, pe);
}
......
......@@ -47,14 +47,14 @@ private:
const CpuNeighborList* neighborList;
float periodicBoxSize[3];
float cutoffDistance, cutoffDistance2;
int numValues, numParams;
const std::vector<std::set<int> > exclusions;
std::vector<std::string> valueNames;
std::vector<CustomGBForce::ComputationType> valueTypes;
std::vector<std::string> paramNames;
std::vector<CustomGBForce::ComputationType> energyTypes;
ThreadPool& threads;
std::vector<ThreadData*> threadData;
std::vector<double> threadEnergy;
std::vector<std::vector<std::vector<float> > > dValuedParam;
// Workspace vectors
std::vector<std::vector<float> > values, dEdV;
// The following variables are used to make information accessible to the individual threads.
......@@ -189,11 +189,13 @@ public:
const std::vector<Lepton::CompiledExpression>& valueExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& valueDerivExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& valueGradientExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& valueParamDerivExpressions,
const std::vector<std::string>& valueNames,
const std::vector<CustomGBForce::ComputationType>& valueTypes,
const std::vector<Lepton::CompiledExpression>& energyExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& energyDerivExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& energyGradientExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& energyParamDerivExpressions,
const std::vector<CustomGBForce::ComputationType>& energyTypes,
const std::vector<std::string>& parameterNames, ThreadPool& threads);
......@@ -227,10 +229,11 @@ public:
* @param globalParameters the values of global parameters
* @param forces force array (forces added)
* @param totalEnergy total energy
* @param energyParamDerivs derivatives of the energy with respect to global parameters
*/
void calculateIxn(int numberOfAtoms, float* posq, RealOpenMM** atomParameters,
std::map<std::string, double>& globalParameters, std::vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy);
void calculateIxn(int numberOfAtoms, float* posq, RealOpenMM** atomParameters, std::map<std::string, double>& globalParameters,
std::vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy, double* energyParamDerivs);
};
class CpuCustomGBForce::ThreadData {
......@@ -239,19 +242,23 @@ public:
const std::vector<Lepton::CompiledExpression>& valueExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& valueDerivExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& valueGradientExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& valueParamDerivExpressions,
const std::vector<std::string>& valueNames,
const std::vector<Lepton::CompiledExpression>& energyExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& energyDerivExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& energyGradientExpressions,
const std::vector<std::vector<Lepton::CompiledExpression> >& energyParamDerivExpressions,
const std::vector<std::string>& parameterNames);
CompiledExpressionSet expressionSet;
std::vector<Lepton::CompiledExpression> valueExpressions;
std::vector<std::vector<Lepton::CompiledExpression> > valueDerivExpressions;
std::vector<std::vector<Lepton::CompiledExpression> > valueGradientExpressions;
std::vector<std::vector<Lepton::CompiledExpression> > valueParamDerivExpressions;
std::vector<int> valueIndex;
std::vector<Lepton::CompiledExpression> energyExpressions;
std::vector<std::vector<Lepton::CompiledExpression> > energyDerivExpressions;
std::vector<std::vector<Lepton::CompiledExpression> > energyGradientExpressions;
std::vector<std::vector<Lepton::CompiledExpression> > energyParamDerivExpressions;
std::vector<int> paramIndex;
std::vector<int> particleParamIndex;
std::vector<int> particleValueIndex;
......@@ -260,6 +267,8 @@ public:
// Workspace vectors
std::vector<float> value0, dVdR1, dVdR2, dVdX, dVdY, dVdZ;
std::vector<std::vector<float> > dEdV;
std::vector<std::vector<float> > dValue0dParam;
std::vector<float> energyParamDerivs;
};
} // namespace OpenMM
......
/* Portions copyright (c) 2009-2014 Stanford University and Simbios.
/* Portions copyright (c) 2009-2016 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* Permission is hereby granted, free of charge, to any person obtaining
......@@ -27,9 +27,9 @@
#include "AlignedArray.h"
#include "CpuNeighborList.h"
#include "openmm/internal/CompiledExpressionSet.h"
#include "openmm/internal/ThreadPool.h"
#include "openmm/internal/vectorize.h"
#include "lepton/CompiledExpression.h"
#include <map>
#include <set>
#include <utility>
......@@ -47,7 +47,8 @@ class CpuCustomNonbondedForce {
--------------------------------------------------------------------------------------- */
CpuCustomNonbondedForce(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression,
const std::vector<std::string>& parameterNames, const std::vector<std::set<int> >& exclusions, ThreadPool& threads);
const std::vector<std::string>& parameterNames, const std::vector<std::set<int> >& exclusions,
const std::vector<Lepton::CompiledExpression> energyParamDerivExpressions, ThreadPool& threads);
/**---------------------------------------------------------------------------------------
......@@ -119,7 +120,7 @@ class CpuCustomNonbondedForce {
void calculatePairIxn(int numberOfAtoms, float* posq, std::vector<OpenMM::RealVec>& atomCoordinates, RealOpenMM** atomParameters,
RealOpenMM* fixedParameters, const std::map<std::string, double>& globalParameters,
std::vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy);
std::vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy, double* energyParamDerivs);
private:
class ComputeForceTask;
class ThreadData;
......@@ -176,13 +177,15 @@ private:
class CpuCustomNonbondedForce::ThreadData {
public:
ThreadData(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression, const std::vector<std::string>& parameterNames);
ThreadData(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression, const std::vector<std::string>& parameterNames,
const std::vector<Lepton::CompiledExpression> energyParamDerivExpressions);
Lepton::CompiledExpression energyExpression;
Lepton::CompiledExpression forceExpression;
std::vector<double*> energyParticleParams;
std::vector<double*> forceParticleParams;
double* energyR;
double* forceR;
std::vector<Lepton::CompiledExpression> energyParamDerivExpressions;
CompiledExpressionSet expressionSet;
std::vector<int> particleParamIndex;
int rIndex;
std::vector<RealOpenMM> energyParamDerivs;
};
} // namespace OpenMM
......
......@@ -313,8 +313,9 @@ private:
CustomNonbondedForce* forceCopy;
std::map<std::string, double> globalParamValues;
std::vector<std::set<int> > exclusions;
std::vector<std::string> parameterNames, globalParameterNames;
std::vector<std::string> parameterNames, globalParameterNames, energyParamDerivNames;
std::vector<std::pair<std::set<int>, std::set<int> > > interactionGroups;
std::vector<double> longRangeCoefficientDerivs;
NonbondedMethod nonbondedMethod;
CpuCustomNonbondedForce* nonbonded;
};
......@@ -397,7 +398,7 @@ private:
RealOpenMM nonbondedCutoff;
CpuCustomGBForce* ixn;
std::vector<std::set<int> > exclusions;
std::vector<std::string> particleParameterNames, globalParameterNames, valueNames;
std::vector<std::string> particleParameterNames, globalParameterNames, energyParamDerivNames, valueNames;
std::vector<OpenMM::CustomGBForce::ComputationType> valueTypes;
std::vector<OpenMM::CustomGBForce::ComputationType> energyTypes;
NonbondedMethod nonbondedMethod;
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2014 Stanford University and the Authors. *
* Portions copyright (c) 2014-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -196,7 +196,7 @@ void CpuBondForce::calculateForce(vector<RealVec>& atomCoordinates, RealOpenMM**
for (int i = 0; i < extraBonds.size(); i++) {
int bond = extraBonds[i];
referenceBondIxn.calculateBondIxn(bondAtoms[bond], atomCoordinates, parameters[bond], forces, totalEnergy);
referenceBondIxn.calculateBondIxn(bondAtoms[bond], atomCoordinates, parameters[bond], forces, totalEnergy, NULL);
}
// Compute the total energy.
......@@ -212,6 +212,6 @@ void CpuBondForce::threadComputeForce(ThreadPool& threads, int threadIndex, vect
int numBonds = bonds.size();
for (int i = 0; i < numBonds; i++) {
int bond = bonds[i];
referenceBondIxn.calculateBondIxn(bondAtoms[bond], atomCoordinates, parameters[bond], forces, totalEnergy);
referenceBondIxn.calculateBondIxn(bondAtoms[bond], atomCoordinates, parameters[bond], forces, totalEnergy, NULL);
}
}
\ No newline at end of file
......@@ -47,13 +47,16 @@ CpuCustomGBForce::ThreadData::ThreadData(int numAtoms, int numThreads, int threa
const vector<Lepton::CompiledExpression>& valueExpressions,
const vector<vector<Lepton::CompiledExpression> >& valueDerivExpressions,
const vector<vector<Lepton::CompiledExpression> >& valueGradientExpressions,
const vector<vector<Lepton::CompiledExpression> >& valueParamDerivExpressions,
const vector<string>& valueNames,
const vector<Lepton::CompiledExpression>& energyExpressions,
const vector<vector<Lepton::CompiledExpression> >& energyDerivExpressions,
const vector<vector<Lepton::CompiledExpression> >& energyGradientExpressions,
const vector<vector<Lepton::CompiledExpression> >& energyParamDerivExpressions,
const vector<string>& parameterNames) :
valueExpressions(valueExpressions), valueDerivExpressions(valueDerivExpressions), valueGradientExpressions(valueGradientExpressions),
energyExpressions(energyExpressions), energyDerivExpressions(energyDerivExpressions), energyGradientExpressions(energyGradientExpressions) {
valueParamDerivExpressions(valueParamDerivExpressions), energyExpressions(energyExpressions), energyDerivExpressions(energyDerivExpressions),
energyGradientExpressions(energyGradientExpressions), energyParamDerivExpressions(energyParamDerivExpressions) {
firstAtom = (threadIndex*(long long) numAtoms)/numThreads;
lastAtom = ((threadIndex+1)*(long long) numAtoms)/numThreads;
for (int i = 0; i < (int) valueExpressions.size(); i++)
......@@ -64,6 +67,9 @@ CpuCustomGBForce::ThreadData::ThreadData(int numAtoms, int numThreads, int threa
for (int i = 0; i < (int) valueGradientExpressions.size(); i++)
for (int j = 0; j < (int) valueGradientExpressions[i].size(); j++)
expressionSet.registerExpression(this->valueGradientExpressions[i][j]);
for (int i = 0; i < (int) valueParamDerivExpressions.size(); i++)
for (int j = 0; j < (int) valueParamDerivExpressions[i].size(); j++)
expressionSet.registerExpression(this->valueParamDerivExpressions[i][j]);
for (int i = 0; i < (int) energyExpressions.size(); i++)
expressionSet.registerExpression(this->energyExpressions[i]);
for (int i = 0; i < (int) energyDerivExpressions.size(); i++)
......@@ -72,6 +78,9 @@ CpuCustomGBForce::ThreadData::ThreadData(int numAtoms, int numThreads, int threa
for (int i = 0; i < (int) energyGradientExpressions.size(); i++)
for (int j = 0; j < (int) energyGradientExpressions[i].size(); j++)
expressionSet.registerExpression(this->energyGradientExpressions[i][j]);
for (int i = 0; i < (int) energyParamDerivExpressions.size(); i++)
for (int j = 0; j < (int) energyParamDerivExpressions[i].size(); j++)
expressionSet.registerExpression(this->energyParamDerivExpressions[i][j]);
xindex = expressionSet.getVariableIndex("x");
yindex = expressionSet.getVariableIndex("y");
zindex = expressionSet.getVariableIndex("z");
......@@ -101,30 +110,37 @@ CpuCustomGBForce::ThreadData::ThreadData(int numAtoms, int numThreads, int threa
dVdZ.resize(valueDerivExpressions.size());
dVdR1.resize(valueDerivExpressions.size());
dVdR2.resize(valueDerivExpressions.size());
dValue0dParam.resize(valueParamDerivExpressions[0].size(), vector<float>(numAtoms));
energyParamDerivs.resize(valueParamDerivExpressions[0].size());
}
CpuCustomGBForce::CpuCustomGBForce(int numAtoms, const std::vector<std::set<int> >& exclusions,
const vector<Lepton::CompiledExpression>& valueExpressions,
const vector<vector<Lepton::CompiledExpression> >& valueDerivExpressions,
const vector<vector<Lepton::CompiledExpression> >& valueGradientExpressions,
const vector<vector<Lepton::CompiledExpression> >& valueParamDerivExpressions,
const vector<string>& valueNames,
const vector<CustomGBForce::ComputationType>& valueTypes,
const vector<Lepton::CompiledExpression>& energyExpressions,
const vector<vector<Lepton::CompiledExpression> >& energyDerivExpressions,
const vector<vector<Lepton::CompiledExpression> >& energyGradientExpressions,
const vector<vector<Lepton::CompiledExpression> >& energyParamDerivExpressions,
const vector<CustomGBForce::ComputationType>& energyTypes,
const vector<string>& parameterNames, ThreadPool& threads) :
exclusions(exclusions), cutoff(false), periodic(false), valueNames(valueNames), valueTypes(valueTypes),
energyTypes(energyTypes), paramNames(parameterNames), threads(threads) {
exclusions(exclusions), cutoff(false), periodic(false), valueTypes(valueTypes), energyTypes(energyTypes), numValues(valueNames.size()),
numParams(parameterNames.size()), threads(threads) {
for (int i = 0; i < threads.getNumThreads(); i++)
threadData.push_back(new ThreadData(numAtoms, threads.getNumThreads(), i, valueExpressions, valueDerivExpressions, valueGradientExpressions, valueNames,
energyExpressions, energyDerivExpressions, energyGradientExpressions, parameterNames));
values.resize(valueNames.size());
dEdV.resize(valueNames.size());
threadData.push_back(new ThreadData(numAtoms, threads.getNumThreads(), i, valueExpressions, valueDerivExpressions, valueGradientExpressions,
valueParamDerivExpressions, valueNames, energyExpressions, energyDerivExpressions, energyGradientExpressions, energyParamDerivExpressions, parameterNames));
values.resize(numValues);
dEdV.resize(numValues);
for (int i = 0; i < (int) values.size(); i++) {
values[i].resize(numAtoms);
dEdV[i].resize(numAtoms);
}
dValuedParam.resize(numValues);
for (int i = 0; i < numValues; i++)
dValuedParam[i].resize(valueParamDerivExpressions[0].size(), vector<float>(numAtoms));
}
CpuCustomGBForce::~CpuCustomGBForce() {
......@@ -153,7 +169,7 @@ void CpuCustomGBForce::setPeriodic(RealVec& boxSize) {
void CpuCustomGBForce::calculateIxn(int numberOfAtoms, float* posq, RealOpenMM** atomParameters,
map<string, double>& globalParameters, vector<AlignedArray<float> >& threadForce,
bool includeForce, bool includeEnergy, double& totalEnergy) {
bool includeForce, bool includeEnergy, double& totalEnergy, double* energyParamDerivs) {
// Record the parameters for the threads.
this->numberOfAtoms = numberOfAtoms;
......@@ -174,6 +190,14 @@ void CpuCustomGBForce::calculateIxn(int numberOfAtoms, float* posq, RealOpenMM**
threads.execute(task);
threads.waitForThreads();
// Sum derivatives of the first computed value with respect to global parameters.
bool hasParamDerivs = (threadData[0]->dValue0dParam.size() > 0);
if (hasParamDerivs) {
threads.resumeThreads();
threads.waitForThreads();
}
// Calculate the remaining computed values.
threads.resumeThreads();
......@@ -205,6 +229,10 @@ void CpuCustomGBForce::calculateIxn(int numberOfAtoms, float* posq, RealOpenMM**
for (int i = 0; i < numThreads; i++)
totalEnergy += threadEnergy[i];
}
if (hasParamDerivs)
for (int i = 0; i < threads.getNumThreads(); i++)
for (int j = 0; j < threadData[i]->energyParamDerivs.size(); j++)
energyParamDerivs[j] += threadData[i]->energyParamDerivs[j];
}
void CpuCustomGBForce::threadComputeForce(ThreadPool& threads, int threadIndex) {
......@@ -224,12 +252,29 @@ void CpuCustomGBForce::threadComputeForce(ThreadPool& threads, int threadIndex)
for (int i = 0; i < (int) data.value0.size(); i++)
data.value0[i] = 0.0f;
for (int i = 0; i < (int) data.dValue0dParam.size(); i++)
for (int j = 0; j < (int) data.dValue0dParam[i].size(); j++)
data.dValue0dParam[i][j] = 0.0;
if (valueTypes[0] == CustomGBForce::ParticlePair)
calculateParticlePairValue(0, data, numberOfAtoms, posq, atomParameters, true, boxSize, invBoxSize);
else
calculateParticlePairValue(0, data, numberOfAtoms, posq, atomParameters, false, boxSize, invBoxSize);
threads.syncThreads();
// Sum derivatives of the first computed value with respect to global parameters.
bool hasParamDerivs = (data.dValue0dParam.size() > 0);
if (hasParamDerivs) {
for (int j = 0; j < data.dValue0dParam.size(); j++)
for (int k = data.firstAtom; k < data.lastAtom; k++) {
float sum = 0.0f;
for (int m = 0; m < threadData.size(); m++)
sum += threadData[m]->dValue0dParam[j][k];
dValuedParam[0][j][k] = sum;
}
threads.syncThreads();
}
// Sum the first computed value and calculate the remaining ones.
int numValues = valueTypes.size();
......@@ -241,11 +286,23 @@ void CpuCustomGBForce::threadComputeForce(ThreadPool& threads, int threadIndex)
data.expressionSet.setVariable(data.xindex, posq[4*atom]);
data.expressionSet.setVariable(data.yindex, posq[4*atom+1]);
data.expressionSet.setVariable(data.zindex, posq[4*atom+2]);
for (int j = 0; j < (int) paramNames.size(); j++)
for (int j = 0; j < numParams; j++)
data.expressionSet.setVariable(data.paramIndex[j], atomParameters[atom][j]);
for (int i = 1; i < numValues; i++) {
data.expressionSet.setVariable(data.valueIndex[i-1], values[i-1][atom]);
values[i][atom] = (float) data.valueExpressions[i].evaluate();
// Calculate derivatives with respect to parameters.
if (hasParamDerivs) {
for (int j = 0; j < data.valueParamDerivExpressions[i].size(); j++)
dValuedParam[i][j][atom] = data.valueParamDerivExpressions[i][j].evaluate();
for (int j = 0; j < i; j++) {
float dVdV = data.valueDerivExpressions[i][j].evaluate();
for (int k = 0; k < data.valueParamDerivExpressions[i].size(); k++)
dValuedParam[i][k][atom] += dVdV*dValuedParam[j][k][atom];
}
}
}
}
threads.syncThreads();
......@@ -254,7 +311,9 @@ void CpuCustomGBForce::threadComputeForce(ThreadPool& threads, int threadIndex)
for (int i = 0; i < (int) data.dEdV.size(); i++)
for (int j = 0; j < (int) data.dEdV[i].size(); j++)
data.dEdV[i][j] = 0.0;
data.dEdV[i][j] = 0.0f;
for (int i = 0; i < (int) data.energyParamDerivs.size(); i++)
data.energyParamDerivs[i] = 0.0f;
for (int termIndex = 0; termIndex < (int) data.energyExpressions.size(); termIndex++) {
if (energyTypes[termIndex] == CustomGBForce::SingleParticle)
calculateSingleParticleEnergyTerm(termIndex, data, numberOfAtoms, posq, atomParameters, forces, energy);
......@@ -339,7 +398,7 @@ void CpuCustomGBForce::calculateOnePairValue(int index, int atom1, int atom2, Th
if (cutoff && r2 >= cutoffDistance2)
return;
float r = sqrtf(r2);
for (int i = 0; i < (int) paramNames.size(); i++) {
for (int i = 0; i < numParams; i++) {
data.expressionSet.setVariable(data.particleParamIndex[i*2], atomParameters[atom1][i]);
data.expressionSet.setVariable(data.particleParamIndex[i*2+1], atomParameters[atom2][i]);
}
......@@ -349,6 +408,11 @@ void CpuCustomGBForce::calculateOnePairValue(int index, int atom1, int atom2, Th
data.expressionSet.setVariable(data.particleValueIndex[i*2+1], values[i][atom2]);
}
valueArray[atom1] += (float) data.valueExpressions[index].evaluate();
// Calculate derivatives with respect to parameters.
for (int i = 0; i < data.valueParamDerivExpressions[index].size(); i++)
data.dValue0dParam[i][atom1] += data.valueParamDerivExpressions[index][i].evaluate();
}
void CpuCustomGBForce::calculateSingleParticleEnergyTerm(int index, ThreadData& data, int numAtoms, float* posq,
......@@ -357,17 +421,22 @@ void CpuCustomGBForce::calculateSingleParticleEnergyTerm(int index, ThreadData&
data.expressionSet.setVariable(data.xindex, posq[4*i]);
data.expressionSet.setVariable(data.yindex, posq[4*i+1]);
data.expressionSet.setVariable(data.zindex, posq[4*i+2]);
for (int j = 0; j < (int) paramNames.size(); j++)
for (int j = 0; j < numParams; j++)
data.expressionSet.setVariable(data.paramIndex[j], atomParameters[i][j]);
for (int j = 0; j < (int) valueNames.size(); j++)
for (int j = 0; j < (int) values.size(); j++)
data.expressionSet.setVariable(data.valueIndex[j], values[j][i]);
if (includeEnergy)
totalEnergy += (float) data.energyExpressions[index].evaluate();
for (int j = 0; j < (int) valueNames.size(); j++)
for (int j = 0; j < (int) values.size(); j++)
data.dEdV[j][i] += (float) data.energyDerivExpressions[index][j].evaluate();
forces[4*i+0] -= (float) data.energyGradientExpressions[index][0].evaluate();
forces[4*i+1] -= (float) data.energyGradientExpressions[index][1].evaluate();
forces[4*i+2] -= (float) data.energyGradientExpressions[index][2].evaluate();
// Compute derivatives with respect to parameters.
for (int k = 0; k < data.energyParamDerivExpressions[index].size(); k++)
data.energyParamDerivs[k] += data.energyParamDerivExpressions[index][k].evaluate();
}
}
......@@ -428,12 +497,12 @@ void CpuCustomGBForce::calculateOnePairEnergyTerm(int index, int atom1, int atom
// Record variables for evaluating expressions.
for (int i = 0; i < (int) paramNames.size(); i++) {
for (int i = 0; i < numParams; i++) {
data.expressionSet.setVariable(data.particleParamIndex[i*2], atomParameters[atom1][i]);
data.expressionSet.setVariable(data.particleParamIndex[i*2+1], atomParameters[atom2][i]);
}
data.expressionSet.setVariable(data.rindex, r);
for (int i = 0; i < (int) valueNames.size(); i++) {
for (int i = 0; i < (int) values.size(); i++) {
data.expressionSet.setVariable(data.particleValueIndex[i*2], values[i][atom1]);
data.expressionSet.setVariable(data.particleValueIndex[i*2+1], values[i][atom2]);
}
......@@ -447,10 +516,15 @@ void CpuCustomGBForce::calculateOnePairEnergyTerm(int index, int atom1, int atom
fvec4 result = deltaR*dEdR;
(fvec4(forces+4*atom1)-result).store(forces+4*atom1);
(fvec4(forces+4*atom2)+result).store(forces+4*atom2);
for (int i = 0; i < (int) valueNames.size(); i++) {
for (int i = 0; i < (int) values.size(); i++) {
data.dEdV[i][atom1] += (float) data.energyDerivExpressions[index][2*i+1].evaluate();
data.dEdV[i][atom2] += (float) data.energyDerivExpressions[index][2*i+2].evaluate();
}
// Compute derivatives with respect to parameters.
for (int i = 0; i < data.energyParamDerivExpressions[index].size(); i++)
data.energyParamDerivs[i] += data.energyParamDerivExpressions[index][i].evaluate();
}
void CpuCustomGBForce::calculateChainRuleForces(ThreadData& data, int numAtoms, float* posq, RealOpenMM** atomParameters,
......@@ -500,9 +574,9 @@ void CpuCustomGBForce::calculateChainRuleForces(ThreadData& data, int numAtoms,
data.expressionSet.setVariable(data.xindex, posq[4*i]);
data.expressionSet.setVariable(data.yindex, posq[4*i+1]);
data.expressionSet.setVariable(data.zindex, posq[4*i+2]);
for (int j = 0; j < (int) paramNames.size(); j++)
for (int j = 0; j < numParams; j++)
data.expressionSet.setVariable(data.paramIndex[j], atomParameters[i][j]);
for (int j = 1; j < (int) valueNames.size(); j++) {
for (int j = 1; j < (int) values.size(); j++) {
data.expressionSet.setVariable(data.valueIndex[j-1], values[j-1][i]);
data.dVdX[j] = 0.0;
data.dVdY[j] = 0.0;
......@@ -521,6 +595,13 @@ void CpuCustomGBForce::calculateChainRuleForces(ThreadData& data, int numAtoms,
forces[4*i+2] -= dEdV[j][i]*data.dVdZ[j];
}
}
// Compute chain rule terms for derivatives with respect to parameters.
for (int i = data.firstAtom; i < data.lastAtom; i++)
for (int j = 0; j < data.valueIndex.size(); j++)
for (int k = 0; k < dValuedParam[j].size(); k++)
data.energyParamDerivs[k] += dEdV[j][i]*dValuedParam[j][k][i];
}
void CpuCustomGBForce::calculateOnePairChainRule(int atom1, int atom2, ThreadData& data, float* posq, RealOpenMM** atomParameters,
......@@ -538,7 +619,7 @@ void CpuCustomGBForce::calculateOnePairChainRule(int atom1, int atom2, ThreadDat
// Record variables for evaluating expressions.
for (int i = 0; i < (int) paramNames.size(); i++) {
for (int i = 0; i < numParams; i++) {
data.expressionSet.setVariable(data.particleParamIndex[i*2], atomParameters[atom1][i]);
data.expressionSet.setVariable(data.particleParamIndex[i*2+1], atomParameters[atom2][i]);
data.expressionSet.setVariable(data.paramIndex[i], atomParameters[atom1][i]);
......@@ -562,7 +643,7 @@ void CpuCustomGBForce::calculateOnePairChainRule(int atom1, int atom2, ThreadDat
f1 -= deltaR*(dEdV[0][atom1]*data.dVdR1[0]);
f2 -= deltaR*(dEdV[0][atom1]*data.dVdR2[0]);
}
for (int i = 1; i < (int) valueNames.size(); i++) {
for (int i = 1; i < (int) values.size(); i++) {
data.expressionSet.setVariable(data.valueIndex[i], values[i][atom1]);
data.dVdR1[i] = 0.0;
data.dVdR2[i] = 0.0;
......
......@@ -43,25 +43,30 @@ public:
CpuCustomNonbondedForce& owner;
};
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");
forceR = ReferenceForce::getVariablePointer(this->forceExpression, "r");
CpuCustomNonbondedForce::ThreadData::ThreadData(const Lepton::CompiledExpression& energyExpression, const Lepton::CompiledExpression& forceExpression,
const vector<string>& parameterNames, const std::vector<Lepton::CompiledExpression> energyParamDerivExpressions) :
energyExpression(energyExpression), forceExpression(forceExpression), energyParamDerivExpressions(energyParamDerivExpressions) {
expressionSet.registerExpression(this->energyExpression);
expressionSet.registerExpression(this->forceExpression);
for (int i = 0; i < this->energyParamDerivExpressions.size(); i++)
expressionSet.registerExpression(this->energyParamDerivExpressions[i]);
rIndex = expressionSet.getVariableIndex("r");
for (int i = 0; i < (int) parameterNames.size(); i++) {
for (int j = 1; j < 3; j++) {
stringstream name;
name << parameterNames[i] << j;
energyParticleParams.push_back(ReferenceForce::getVariablePointer(this->energyExpression, name.str()));
forceParticleParams.push_back(ReferenceForce::getVariablePointer(this->forceExpression, name.str()));
particleParamIndex.push_back(expressionSet.getVariableIndex(name.str()));
}
}
energyParamDerivs.resize(energyParamDerivExpressions.size());
}
CpuCustomNonbondedForce::CpuCustomNonbondedForce(const Lepton::CompiledExpression& energyExpression,
const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames, const vector<set<int> >& exclusions,ThreadPool& threads) :
const Lepton::CompiledExpression& forceExpression, const vector<string>& parameterNames, const vector<set<int> >& exclusions,
const std::vector<Lepton::CompiledExpression> energyParamDerivExpressions, ThreadPool& threads) :
cutoff(false), useSwitch(false), periodic(false), paramNames(parameterNames), exclusions(exclusions), threads(threads) {
for (int i = 0; i < threads.getNumThreads(); i++)
threadData.push_back(new ThreadData(energyExpression, forceExpression, parameterNames));
threadData.push_back(new ThreadData(energyExpression, forceExpression, parameterNames, energyParamDerivExpressions));
}
CpuCustomNonbondedForce::~CpuCustomNonbondedForce() {
......@@ -120,7 +125,7 @@ void CpuCustomNonbondedForce::setPeriodic(RealVec* periodicBoxVectors) {
void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, vector<RealVec>& atomCoordinates, RealOpenMM** atomParameters,
RealOpenMM* fixedParameters, const map<string, double>& globalParameters,
vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy) {
vector<AlignedArray<float> >& threadForce, bool includeForce, bool includeEnergy, double& totalEnergy, double* energyParamDerivs) {
// Record the parameters for the threads.
this->numberOfAtoms = numberOfAtoms;
......@@ -144,11 +149,18 @@ void CpuCustomNonbondedForce::calculatePairIxn(int numberOfAtoms, float* posq, v
// Combine the energies from all the threads.
if (includeEnergy) {
int numThreads = threads.getNumThreads();
if (includeEnergy) {
for (int i = 0; i < numThreads; i++)
totalEnergy += threadEnergy[i];
}
// Combine the energy derivatives from all threads.
int numDerivs = threadData[0]->energyParamDerivs.size();
for (int i = 0; i < numThreads; i++)
for (int j = 0; j < numDerivs; j++)
energyParamDerivs[j] += threadData[i]->energyParamDerivs[j];
}
void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int threadIndex) {
......@@ -159,10 +171,10 @@ void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int thread
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);
}
for (map<string, double>::const_iterator iter = globalParameters->begin(); iter != globalParameters->end(); ++iter)
data.expressionSet.setVariable(data.expressionSet.getVariableIndex(iter->first), iter->second);
for (int i = 0; i < data.energyParamDerivs.size(); i++)
data.energyParamDerivs[i] = 0.0;
fvec4 boxSize(periodicBoxVectors[0][0], periodicBoxVectors[1][1], periodicBoxVectors[2][2], 0);
fvec4 invBoxSize(recipBoxSize[0], recipBoxSize[1], recipBoxSize[2], 0);
if (groupInteractions.size() > 0) {
......@@ -175,10 +187,8 @@ void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int thread
int atom1 = groupInteractions[i].first;
int atom2 = groupInteractions[i].second;
for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(data.energyParticleParams[j*2], atomParameters[atom1][j]);
ReferenceForce::setVariable(data.energyParticleParams[j*2+1], atomParameters[atom2][j]);
ReferenceForce::setVariable(data.forceParticleParams[j*2], atomParameters[atom1][j]);
ReferenceForce::setVariable(data.forceParticleParams[j*2+1], atomParameters[atom2][j]);
data.expressionSet.setVariable(data.particleParamIndex[j*2], atomParameters[atom1][j]);
data.expressionSet.setVariable(data.particleParamIndex[j*2+1], atomParameters[atom2][j]);
}
calculateOneIxn(atom1, atom2, data, forces, energy, boxSize, invBoxSize);
}
......@@ -196,17 +206,13 @@ void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int thread
const vector<char>& exclusions = neighborList->getBlockExclusions(blockIndex);
for (int i = 0; i < (int) neighbors.size(); i++) {
int first = neighbors[i];
for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(data.energyParticleParams[j*2], atomParameters[first][j]);
ReferenceForce::setVariable(data.forceParticleParams[j*2], atomParameters[first][j]);
}
for (int j = 0; j < (int) paramNames.size(); j++)
data.expressionSet.setVariable(data.particleParamIndex[j*2], atomParameters[first][j]);
for (int k = 0; k < blockSize; k++) {
if ((exclusions[i] & (1<<k)) == 0) {
int second = blockAtom[k];
for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(data.energyParticleParams[j*2+1], atomParameters[second][j]);
ReferenceForce::setVariable(data.forceParticleParams[j*2+1], atomParameters[second][j]);
}
for (int j = 0; j < (int) paramNames.size(); j++)
data.expressionSet.setVariable(data.particleParamIndex[j*2+1], atomParameters[second][j]);
calculateOneIxn(first, second, data, forces, energy, boxSize, invBoxSize);
}
}
......@@ -223,10 +229,8 @@ void CpuCustomNonbondedForce::threadComputeForce(ThreadPool& threads, int thread
for (int jj = ii+1; jj < numberOfAtoms; jj++) {
if (exclusions[jj].find(ii) == exclusions[jj].end()) {
for (int j = 0; j < (int) paramNames.size(); j++) {
ReferenceForce::setVariable(data.energyParticleParams[j*2], atomParameters[ii][j]);
ReferenceForce::setVariable(data.energyParticleParams[j*2+1], atomParameters[jj][j]);
ReferenceForce::setVariable(data.forceParticleParams[j*2], atomParameters[ii][j]);
ReferenceForce::setVariable(data.forceParticleParams[j*2+1], atomParameters[jj][j]);
data.expressionSet.setVariable(data.particleParamIndex[j*2], atomParameters[ii][j]);
data.expressionSet.setVariable(data.particleParamIndex[j*2+1], atomParameters[jj][j]);
}
calculateOneIxn(ii, jj, data, forces, energy, boxSize, invBoxSize);
}
......@@ -250,15 +254,15 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, ThreadData& data,
// accumulate forces
ReferenceForce::setVariable(data.energyR, r);
ReferenceForce::setVariable(data.forceR, r);
data.expressionSet.setVariable(data.rIndex, r);
double dEdR = (includeForce ? data.forceExpression.evaluate()/r : 0.0);
double energy = (includeEnergy ? data.energyExpression.evaluate() : 0.0);
double switchValue = 1.0;
if (useSwitch) {
if (r > switchingDistance) {
RealOpenMM t = (r-switchingDistance)/(cutoffDistance-switchingDistance);
RealOpenMM switchValue = 1+t*t*t*(-10+t*(15-t*6));
RealOpenMM switchDeriv = t*t*(-30+t*(60-t*30))/(cutoffDistance-switchingDistance);
double t = (r-switchingDistance)/(cutoffDistance-switchingDistance);
switchValue = 1+t*t*t*(-10+t*(15-t*6));
double switchDeriv = t*t*(-30+t*(60-t*30))/(cutoffDistance-switchingDistance);
dEdR = switchValue*dEdR + energy*switchDeriv/r;
energy *= switchValue;
}
......@@ -270,6 +274,11 @@ void CpuCustomNonbondedForce::calculateOneIxn(int ii, int jj, ThreadData& data,
// accumulate energies
totalEnergy += energy;
// Accumulate energy derivatives.
for (int i = 0; i < data.energyParamDerivExpressions.size(); i++)
data.energyParamDerivs[i] += switchValue*data.energyParamDerivExpressions[i].evaluate();
}
void CpuCustomNonbondedForce::getDeltaR(const fvec4& posI, const fvec4& posJ, fvec4& deltaR, float& r2, const fvec4& boxSize, const fvec4& invBoxSize) const {
......
......@@ -85,6 +85,11 @@ static ReferenceConstraints& extractConstraints(ContextImpl& context) {
return *(ReferenceConstraints*) data->constraints;
}
static map<string, double>& extractEnergyParameterDerivatives(ContextImpl& context) {
ReferencePlatform::PlatformData* data = reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData());
return *((map<string, double>*) data->energyParameterDerivatives);
}
/**
* Make sure an expression doesn't use any undefined variables.
*/
......@@ -814,6 +819,12 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C
globalParameterNames.push_back(force.getGlobalParameterName(i));
globalParamValues[force.getGlobalParameterName(i)] = force.getGlobalParameterDefaultValue(i);
}
std::vector<Lepton::CompiledExpression> energyParamDerivExpressions;
for (int i = 0; i < force.getNumEnergyParameterDerivatives(); i++) {
string param = force.getEnergyParameterDerivativeName(i);
energyParamDerivNames.push_back(param);
energyParamDerivExpressions.push_back(expression.differentiate(param).createCompiledExpression());
}
set<string> variables;
variables.insert("r");
for (int i = 0; i < numParameters; i++) {
......@@ -847,7 +858,7 @@ void CpuCalcCustomNonbondedForceKernel::initialize(const System& system, const C
interactionGroups.push_back(make_pair(set1, set2));
}
data.isPeriodic = (nonbondedMethod == CutoffPeriodic);
nonbonded = new CpuCustomNonbondedForce(energyExpression, forceExpression, parameterNames, exclusions, data.threads);
nonbonded = new CpuCustomNonbondedForce(energyExpression, forceExpression, parameterNames, exclusions, energyParamDerivExpressions, data.threads);
if (interactionGroups.size() > 0)
nonbonded->setInteractionGroups(interactionGroups);
}
......@@ -875,15 +886,22 @@ double CpuCalcCustomNonbondedForceKernel::execute(ContextImpl& context, bool inc
}
if (useSwitchingFunction)
nonbonded->setUseSwitchingFunction(switchingDistance);
nonbonded->calculatePairIxn(numParticles, &data.posq[0], posData, particleParamArray, 0, globalParamValues, data.threadForce, includeForces, includeEnergy, energy);
vector<double> energyParamDerivValues(energyParamDerivNames.size()+1, 0.0);
nonbonded->calculatePairIxn(numParticles, &data.posq[0], posData, particleParamArray, 0, globalParamValues, data.threadForce, includeForces, includeEnergy, energy, &energyParamDerivValues[0]);
map<string, double>& energyParamDerivs = extractEnergyParameterDerivatives(context);
for (int i = 0; i < energyParamDerivNames.size(); i++)
energyParamDerivs[energyParamDerivNames[i]] += energyParamDerivValues[i];
// Add in the long range correction.
if (!hasInitializedLongRangeCorrection || (globalParamsChanged && forceCopy != NULL)) {
longRangeCoefficient = CustomNonbondedForceImpl::calcLongRangeCorrection(*forceCopy, context.getOwner());
CustomNonbondedForceImpl::calcLongRangeCorrection(*forceCopy, context.getOwner(), longRangeCoefficient, longRangeCoefficientDerivs);
hasInitializedLongRangeCorrection = true;
}
energy += longRangeCoefficient/(boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2]);
double volume = boxVectors[0][0]*boxVectors[1][1]*boxVectors[2][2];
energy += longRangeCoefficient/volume;
for (int i = 0; i < longRangeCoefficientDerivs.size(); i++)
energyParamDerivs[energyParamDerivNames[i]] += longRangeCoefficientDerivs[i]/volume;
return energy;
}
......@@ -905,7 +923,7 @@ void CpuCalcCustomNonbondedForceKernel::copyParametersToContext(ContextImpl& con
// If necessary, recompute the long range correction.
if (forceCopy != NULL) {
longRangeCoefficient = CustomNonbondedForceImpl::calcLongRangeCorrection(force, context.getOwner());
CustomNonbondedForceImpl::calcLongRangeCorrection(force, context.getOwner(), longRangeCoefficient, longRangeCoefficientDerivs);
hasInitializedLongRangeCorrection = true;
*forceCopy = force;
}
......@@ -1027,6 +1045,7 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
vector<vector<Lepton::CompiledExpression> > valueDerivExpressions(force.getNumComputedValues());
vector<vector<Lepton::CompiledExpression> > valueGradientExpressions(force.getNumComputedValues());
vector<vector<Lepton::CompiledExpression> > valueParamDerivExpressions(force.getNumComputedValues());
vector<Lepton::CompiledExpression> valueExpressions;
vector<Lepton::CompiledExpression> energyExpressions;
set<string> particleVariables, pairVariables;
......@@ -1061,6 +1080,11 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
valueDerivExpressions[i].push_back(ex.differentiate(valueNames[j]).createCompiledExpression());
validateVariables(ex.getRootNode(), particleVariables);
}
for (int j = 0; j < force.getNumEnergyParameterDerivatives(); j++) {
string param = force.getEnergyParameterDerivativeName(j);
energyParamDerivNames.push_back(param);
valueParamDerivExpressions[i].push_back(ex.differentiate(param).createCompiledExpression());
}
particleVariables.insert(name);
pairVariables.insert(name+"1");
pairVariables.insert(name+"2");
......@@ -1070,6 +1094,7 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
vector<vector<Lepton::CompiledExpression> > energyDerivExpressions(force.getNumEnergyTerms());
vector<vector<Lepton::CompiledExpression> > energyGradientExpressions(force.getNumEnergyTerms());
vector<vector<Lepton::CompiledExpression> > energyParamDerivExpressions(force.getNumEnergyTerms());
for (int i = 0; i < force.getNumEnergyTerms(); i++) {
string expression;
CustomGBForce::ComputationType type;
......@@ -1093,14 +1118,17 @@ void CpuCalcCustomGBForceKernel::initialize(const System& system, const CustomGB
validateVariables(ex.getRootNode(), pairVariables);
}
}
for (int j = 0; j < force.getNumEnergyParameterDerivatives(); j++)
energyParamDerivExpressions[i].push_back(ex.differentiate(force.getEnergyParameterDerivativeName(j)).createCompiledExpression());
}
// Delete the custom functions.
for (map<string, Lepton::CustomFunction*>::iterator iter = functions.begin(); iter != functions.end(); iter++)
delete iter->second;
ixn = new CpuCustomGBForce(numParticles, exclusions, valueExpressions, valueDerivExpressions, valueGradientExpressions, valueNames, valueTypes, energyExpressions,
energyDerivExpressions, energyGradientExpressions, energyTypes, particleParameterNames, data.threads);
ixn = new CpuCustomGBForce(numParticles, exclusions, valueExpressions, valueDerivExpressions, valueGradientExpressions, valueParamDerivExpressions,
valueNames, valueTypes, energyExpressions, energyDerivExpressions, energyGradientExpressions, energyParamDerivExpressions, energyTypes,
particleParameterNames, data.threads);
data.isPeriodic = (force.getNonbondedMethod() == CustomGBForce::CutoffPeriodic);
}
......@@ -1117,7 +1145,11 @@ double CpuCalcCustomGBForceKernel::execute(ContextImpl& context, bool includeFor
map<string, double> globalParameters;
for (int i = 0; i < (int) globalParameterNames.size(); i++)
globalParameters[globalParameterNames[i]] = context.getParameter(globalParameterNames[i]);
ixn->calculateIxn(numParticles, &data.posq[0], particleParamArray, globalParameters, data.threadForce, includeForces, includeEnergy, energy);
vector<double> energyParamDerivValues(energyParamDerivNames.size()+1, 0.0);
ixn->calculateIxn(numParticles, &data.posq[0], particleParamArray, globalParameters, data.threadForce, includeForces, includeEnergy, energy, &energyParamDerivValues[0]);
map<string, double>& energyParamDerivs = extractEnergyParameterDerivatives(context);
for (int i = 0; i < energyParamDerivNames.size(); i++)
energyParamDerivs[energyParamDerivNames[i]] += energyParamDerivValues[i];
return energy;
}
......
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2011-2015 Stanford University and the Authors. *
* Portions copyright (c) 2011-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -100,6 +100,15 @@ public:
* refer to it by this name.
*/
std::string addArgument(CUdeviceptr data, const std::string& type);
/**
* Register that the interaction kernel will be computing the derivative of the potential energy
* with respect to a parameter.
*
* @param param the name of the parameter
* @return the variable that will be used to accumulate the derivative. Any code you pass to addInteraction() should
* add its contributions to this variable.
*/
std::string addEnergyParameterDerivative(const std::string& param);
/**
* Add some Cuda code that should be included in the program, before the start of the kernel.
* This can be used, for example, to define functions that will be called by the kernel.
......@@ -129,6 +138,7 @@ private:
std::vector<std::string> argTypes;
std::vector<std::vector<CudaArray*> > atomIndices;
std::vector<std::string> prefixCode;
std::vector<std::string> energyParameterDerivatives;
std::vector<void*> kernelArgs;
int numForceBuffers, maxBonds, allGroups;
bool hasInitializedKernels, hasInteractions;
......
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009-2015 Stanford University and the Authors. *
* Portions copyright (c) 2009-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -177,6 +177,12 @@ public:
CudaArray& getEnergyBuffer() {
return *energyBuffer;
}
/**
* Get the array which contains the buffer in which derivatives of the energy with respect to parameters are computed.
*/
CudaArray& getEnergyParamDerivBuffer() {
return *energyParamDerivBuffer;
}
/**
* Get a pointer to a block of pinned memory that can be used for efficient transfers between host and device.
* This is guaranteed to be at least as large as any of the arrays returned by methods of this class.
......@@ -544,6 +550,27 @@ public:
std::vector<ForcePostComputation*>& getPostComputations() {
return postComputations;
}
/**
* Get the names of all parameters with respect to which energy derivatives are computed.
*/
const std::vector<std::string>& getEnergyParamDerivNames() const {
return energyParamDerivNames;
}
/**
* Get a workspace data structure used for accumulating the values of derivatives of the energy
* with respect to parameters.
*/
std::map<std::string, double>& getEnergyParamDerivWorkspace() {
return energyParamDerivWorkspace;
}
/**
* Register that the derivative of potential energy with respect to a context parameter
* will need to be calculated. If this is called multiple times for a single parameter,
* it is only added to the list once.
*
* @param param the name of the parameter to add
*/
void addEnergyParameterDerivative(const std::string& param);
/**
* Mark that the current molecule definitions (and hence the atom order) may be invalid.
* This should be called whenever force field parameters change. It will cause the definitions
......@@ -609,7 +636,10 @@ private:
CudaArray* velm;
CudaArray* force;
CudaArray* energyBuffer;
CudaArray* energyParamDerivBuffer;
CudaArray* atomIndexDevice;
std::vector<std::string> energyParamDerivNames;
std::map<std::string, double> energyParamDerivWorkspace;
std::vector<int> atomIndex;
std::vector<CUdeviceptr> autoclearBuffers;
std::vector<int> autoclearBufferSizes;
......
......@@ -163,6 +163,12 @@ public:
* @param forces on exit, this contains the forces
*/
void getForces(ContextImpl& context, std::vector<Vec3>& forces);
/**
* Get the current derivatives of the energy with respect to context parameters.
*
* @param derivs on exit, this contains the derivatives
*/
void getEnergyParameterDerivatives(ContextImpl& context, std::map<std::string, double>& derivs);
/**
* Get the current periodic box vectors.
*
......@@ -729,6 +735,7 @@ private:
std::vector<float> globalParamValues;
std::vector<CudaArray*> tabulatedFunctions;
double longRangeCoefficient;
std::vector<double> longRangeCoefficientDerivs;
bool hasInitializedLongRangeCorrection, hasInitializedKernel;
int numGroupThreadBlocks;
CustomNonbondedForce* forceCopy;
......@@ -819,13 +826,15 @@ public:
void copyParametersToContext(ContextImpl& context, const CustomGBForce& force);
private:
double cutoff;
bool hasInitializedKernels, needParameterGradient;
bool hasInitializedKernels, needParameterGradient, needEnergyParamDerivs;
int maxTiles, numComputedValues;
CudaContext& cu;
CudaParameterSet* params;
CudaParameterSet* computedValues;
CudaParameterSet* energyDerivs;
CudaParameterSet* energyDerivChain;
std::vector<CudaParameterSet*> dValuedParam;
std::vector<CudaArray*> dValue0dParam;
CudaArray* longEnergyDerivs;
CudaArray* globals;
CudaArray* valueBuffers;
......@@ -970,6 +979,7 @@ public:
private:
int numGroups, numBonds;
bool needEnergyParamDerivs;
CudaContext& cu;
CudaParameterSet* params;
CudaArray* globals;
......@@ -1284,7 +1294,7 @@ public:
enum GlobalTargetType {DT, VARIABLE, PARAMETER};
CudaIntegrateCustomStepKernel(std::string name, const Platform& platform, CudaContext& cu) : IntegrateCustomStepKernel(name, platform), cu(cu),
hasInitializedKernels(false), localValuesAreCurrent(false), globalValues(NULL), sumBuffer(NULL), summedValue(NULL), uniformRandoms(NULL),
randomSeed(NULL), perDofValues(NULL) {
randomSeed(NULL), perDofEnergyParamDerivs(NULL), perDofValues(NULL), needsEnergyParamDerivs(false) {
}
~CudaIntegrateCustomStepKernel();
/**
......@@ -1349,8 +1359,11 @@ public:
private:
class ReorderListener;
class GlobalTarget;
class DerivFunction;
std::string createPerDofComputation(const std::string& variable, const Lepton::ParsedExpression& expr, int component, CustomIntegrator& integrator, const std::string& forceName, const std::string& energyName);
void prepareForComputation(ContextImpl& context, CustomIntegrator& integrator, bool& forcesAreValid);
Lepton::ExpressionTreeNode replaceDerivFunctions(const Lepton::ExpressionTreeNode& node, OpenMM::ContextImpl& context);
void findExpressionsForDerivs(const Lepton::ExpressionTreeNode& node, std::vector<std::pair<Lepton::ExpressionTreeNode, std::string> >& variableNodes);
void recordGlobalValue(double value, GlobalTarget target);
void recordChangedParameters(ContextImpl& context);
bool evaluateCondition(int step);
......@@ -1358,18 +1371,23 @@ private:
double energy;
float energyFloat;
int numGlobalVariables;
bool hasInitializedKernels, deviceValuesAreCurrent, deviceGlobalsAreCurrent, modifiesParameters, keNeedsForce, hasAnyConstraints;
bool hasInitializedKernels, deviceValuesAreCurrent, deviceGlobalsAreCurrent, modifiesParameters, keNeedsForce, hasAnyConstraints, needsEnergyParamDerivs;
mutable bool localValuesAreCurrent;
CudaArray* globalValues;
CudaArray* sumBuffer;
CudaArray* summedValue;
CudaArray* uniformRandoms;
CudaArray* randomSeed;
CudaArray* perDofEnergyParamDerivs;
std::map<int, CudaArray*> savedForces;
std::set<int> validSavedForces;
CudaParameterSet* perDofValues;
mutable std::vector<std::vector<float> > localPerDofValuesFloat;
mutable std::vector<std::vector<double> > localPerDofValuesDouble;
std::map<std::string, double> energyParamDerivs;
std::vector<std::string> perDofEnergyParamDerivNames;
std::vector<float> localPerDofEnergyParamDerivsFloat;
std::vector<double> localPerDofEnergyParamDerivsDouble;
std::vector<float> globalValuesFloat;
std::vector<double> globalValuesDouble;
std::vector<double> initialGlobalVariables;
......
......@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009-2013 Stanford University and the Authors. *
* Portions copyright (c) 2009-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -88,6 +88,15 @@ public:
* Add an array (other than a per-atom parameter) that should be passed as an argument to the default interaction kernel.
*/
void addArgument(const ParameterInfo& parameter);
/**
* Register that the interaction kernel will be computing the derivative of the potential energy
* with respect to a parameter.
*
* @param param the name of the parameter
* @return the variable that will be used to accumulate the derivative. Any code you pass to addInteraction() should
* add its contributions to this variable.
*/
std::string addEnergyParameterDerivative(const std::string& param);
/**
* Specify the list of exclusions that an interaction outside the default kernel will depend on.
*
......@@ -275,6 +284,7 @@ private:
std::vector<std::vector<int> > atomExclusions;
std::vector<ParameterInfo> parameters;
std::vector<ParameterInfo> arguments;
std::vector<std::string> energyParameterDerivatives;
std::map<int, double> groupCutoff;
std::map<int, std::string> groupKernelSource;
double lastCutoff;
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2011-2015 Stanford University and the Authors. *
* Portions copyright (c) 2011-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -52,12 +52,25 @@ void CudaBondedUtilities::addInteraction(const vector<vector<int> >& atoms, cons
}
}
std::string CudaBondedUtilities::addArgument(CUdeviceptr data, const string& type) {
string CudaBondedUtilities::addArgument(CUdeviceptr data, const string& type) {
arguments.push_back(data);
argTypes.push_back(type);
return "customArg"+context.intToString(arguments.size());
}
string CudaBondedUtilities::addEnergyParameterDerivative(const string& param) {
// See if the parameter has already been added.
int index;
for (index = 0; index < energyParameterDerivatives.size(); index++)
if (param == energyParameterDerivatives[index])
break;
if (index == energyParameterDerivatives.size())
energyParameterDerivatives.push_back(param);
context.addEnergyParameterDerivative(param);
return string("energyParamDeriv")+context.intToString(index);
}
void CudaBondedUtilities::addPrefixCode(const string& source) {
for (int i = 0; i < (int) prefixCode.size(); i++)
if (prefixCode[i] == source)
......@@ -109,11 +122,21 @@ void CudaBondedUtilities::initialize(const System& system) {
}
for (int i = 0; i < (int) arguments.size(); i++)
s<<", "<<argTypes[i]<<"* customArg"<<(i+1);
if (energyParameterDerivatives.size() > 0)
s<<", mixed* __restrict__ energyParamDerivs";
s<<") {\n";
s<<"mixed energy = 0;\n";
for (int i = 0; i < energyParameterDerivatives.size(); i++)
s<<"mixed energyParamDeriv"<<i<<" = 0;\n";
for (int force = 0; force < numForces; force++)
s<<createForceSource(force, forceAtoms[force].size(), forceAtoms[force][0].size(), forceGroup[force], forceSource[force]);
s<<"energyBuffer[blockIdx.x*blockDim.x+threadIdx.x] += energy;\n";
const vector<string>& allParamDerivNames = context.getEnergyParamDerivNames();
int numDerivs = allParamDerivNames.size();
for (int i = 0; i < energyParameterDerivatives.size(); i++)
for (int index = 0; index < numDerivs; index++)
if (allParamDerivNames[index] == energyParameterDerivatives[i])
s<<"energyParamDerivs[(blockIdx.x*blockDim.x+threadIdx.x)*"<<numDerivs<<"+"<<index<<"] += energyParamDeriv"<<i<<";\n";
s<<"}\n";
map<string, string> defines;
defines["PADDED_NUM_ATOMS"] = context.intToString(context.getPaddedNumAtoms());
......@@ -171,6 +194,8 @@ void CudaBondedUtilities::computeInteractions(int groups) {
kernelArgs.push_back(&atomIndices[i][j]->getDevicePointer());
for (int i = 0; i < (int) arguments.size(); i++)
kernelArgs.push_back(&arguments[i]);
if (energyParameterDerivatives.size() > 0)
kernelArgs.push_back(&context.getEnergyParamDerivBuffer().getDevicePointer());
}
if (!hasInteractions)
return;
......
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