Commit 3a6d79b3 authored by Peter Eastman's avatar Peter Eastman
Browse files

Finished reference implementation of CustomGBForce

parent 4747b0f2
...@@ -52,12 +52,12 @@ namespace OpenMM { ...@@ -52,12 +52,12 @@ namespace OpenMM {
* The computation consists of calculating some number of per-particle <i>computed values</i>, followed by one or more * The computation consists of calculating some number of per-particle <i>computed values</i>, followed by one or more
* <i>energy terms</i>. A computed value is a scalar value that is computed for each particle in the system. It may * <i>energy terms</i>. A computed value is a scalar value that is computed for each particle in the system. It may
* depend on an arbitrary set of global and per-particle parameters, and well as on other computed values that have * depend on an arbitrary set of global and per-particle parameters, and well as on other computed values that have
* been calculating before it. Once all computed values have been calculated, the energy terms and their derivatives * been calculated before it. Once all computed values have been calculated, the energy terms and their derivatives
* are evaluated to determine the system energy and particle forces. The energy terms may depend on global parameters, * are evaluated to determine the system energy and particle forces. The energy terms may depend on global parameters,
* per-particle parameters, and per-particle computed values. * per-particle parameters, and per-particle computed values.
* *
* When specifying a computed value or energy term, you provide an algebraic expression to evaluate and a <i>computation type</i> * When specifying a computed value or energy term, you provide an algebraic expression to evaluate and a <i>computation type</i>
* describing how is the expression is to be evaluated. There are two main types of computations: * describing how the expression is to be evaluated. There are two main types of computations:
* *
* <ul> * <ul>
* <li><b>Single Particle</b>: The expression is evaluated once for each particle in the System. In the case of a computed * <li><b>Single Particle</b>: The expression is evaluated once for each particle in the System. In the case of a computed
...@@ -68,14 +68,14 @@ namespace OpenMM { ...@@ -68,14 +68,14 @@ namespace OpenMM {
* value, the value for a particular particle is calculated by pairing it with every other particle in the system, evaluating * value, the value for a particular particle is calculated by pairing it with every other particle in the system, evaluating
* the expression for each pair, and summing them. For an energy term, each particle pair makes an independent contribution to * the expression for each pair, and summing them. For an energy term, each particle pair makes an independent contribution to
* the System energy. (Note that energy terms are assumed to be symmetric with respect to the two interacting particles, and * the System energy. (Note that energy terms are assumed to be symmetric with respect to the two interacting particles, and
* therefore are evaluated only once per pair. In contrast, computed values need not be symmetric and therefore are calculated * therefore are evaluated only once per pair. In contrast, expressions for computed values need not be symmetric and therefore are calculated
* twice for each pair: once when calculating the value for the first particle, and again when calculating the value for the * twice for each pair: once when calculating the value for the first particle, and again when calculating the value for the
* second particle.)</li> * second particle.)</li>
* </ul> * </ul>
* *
* Be aware that, although this class is extremely general in the computations it can define, particular Platforms may only support * Be aware that, although this class is extremely general in the computations it can define, particular Platforms may only support
* more restricted types of computations. In particular, all currently existing Platforms require that the first computed value * more restricted types of computations. In particular, all currently existing Platforms require that the first computed value
* <i>must</i> be a particle pair computation, and all computed values that follow it <i>must</i> be single particle computations. * <i>must</i> be a particle pair computation, and all computed values after the first <i>must</i> be single particle computations.
* This is sufficient for most Generalized Born models, but might not permit some other types of calculations to be implemented. * This is sufficient for most Generalized Born models, but might not permit some other types of calculations to be implemented.
* *
* This is a complicated class to use, and an example may help to clarify it. The following code implements the OBC variant * This is a complicated class to use, and an example may help to clarify it. The following code implements the OBC variant
...@@ -107,7 +107,7 @@ namespace OpenMM { ...@@ -107,7 +107,7 @@ namespace OpenMM {
* (the dielectric constants for the solute and solvent). It then defines a computed value "I" of type ParticlePair. The * (the dielectric constants for the solute and solvent). It then defines a computed value "I" of type ParticlePair. The
* expression for evaluating it is a complicated function of the distance between each pair of particles (r), their atomic * expression for evaluating it is a complicated function of the distance between each pair of particles (r), their atomic
* radii (radius1 and radius2), and their scale factors (scale1 and scale2). Very roughly speaking, it is a measure of the * radii (radius1 and radius2), and their scale factors (scale1 and scale2). Very roughly speaking, it is a measure of the
* overlap between each particle and other nearby particles. * distance between each particle and other nearby particles.
* *
* Next a computation is defined for the Born Radius (B). It is computed independently for each particle, and is a function of * Next a computation is defined for the Born Radius (B). It is computed independently for each particle, and is a function of
* that particle's atomic radius and the intermediate value I defined above. * that particle's atomic radius and the intermediate value I defined above.
...@@ -128,12 +128,13 @@ namespace OpenMM { ...@@ -128,12 +128,13 @@ namespace OpenMM {
* *
* Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following * Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following
* functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, step. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, step. All trigonometric functions
* are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. The names of per-particle parameters * are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. In expressions for
* particle pair calculations, the names of per-particle parameters and computed values
* have the suffix "1" or "2" appended to them to indicate the values for the two interacting particles. As seen in the above example, * have the suffix "1" or "2" appended to them to indicate the values for the two interacting particles. As seen in the above example,
* the expression may also involve intermediate quantities that are defined following the main expression, using ";" as a separator. * an expression may also involve intermediate quantities that are defined following the main expression, using ";" as a separator.
* *
* In addition, you can call addFunction() to define a new function based on tabulated values. You specify a vector of * In addition, you can call addFunction() to define a new function based on tabulated values. You specify a vector of
* values, and an interpolating or approximating spline is created from them. That function can then appear in the expression. * values, and an interpolating or approximating spline is created from them. That function can then appear in expressions.
*/ */
class OPENMM_EXPORT CustomGBForce : public Force { class OPENMM_EXPORT CustomGBForce : public Force {
......
...@@ -607,9 +607,9 @@ double ReferenceCalcNonbondedForceKernel::executeEnergy(ContextImpl& context) { ...@@ -607,9 +607,9 @@ double ReferenceCalcNonbondedForceKernel::executeEnergy(ContextImpl& context) {
return energy; return energy;
} }
class ReferenceCalcCustomNonbondedForceKernel::TabulatedFunction : public Lepton::CustomFunction { class ReferenceTabulatedFunction : public Lepton::CustomFunction {
public: public:
TabulatedFunction(double min, double max, const vector<double>& values, bool interpolating) : ReferenceTabulatedFunction(double min, double max, const vector<double>& values, bool interpolating) :
min(min), max(max), values(values), interpolating(interpolating) { min(min), max(max), values(values), interpolating(interpolating) {
} }
int getNumArguments() const { int getNumArguments() const {
...@@ -659,7 +659,7 @@ public: ...@@ -659,7 +659,7 @@ public:
return scale*(coeff[1]+x*(2.0*coeff[2]+x*3.0*coeff[3])); // We assume a first derivative, because that's the only order ever used by CustomNonbondedForce. return scale*(coeff[1]+x*(2.0*coeff[2]+x*3.0*coeff[3])); // We assume a first derivative, because that's the only order ever used by CustomNonbondedForce.
} }
CustomFunction* clone() const { CustomFunction* clone() const {
return new TabulatedFunction(min, max, values, interpolating); return new ReferenceTabulatedFunction(min, max, values, interpolating);
} }
double min, max; double min, max;
vector<double> values; vector<double> values;
...@@ -725,7 +725,7 @@ void ReferenceCalcCustomNonbondedForceKernel::initialize(const System& system, c ...@@ -725,7 +725,7 @@ void ReferenceCalcCustomNonbondedForceKernel::initialize(const System& system, c
double min, max; double min, max;
bool interpolating; bool interpolating;
force.getFunctionParameters(i, name, values, min, max, interpolating); force.getFunctionParameters(i, name, values, min, max, interpolating);
functions[name] = new TabulatedFunction(min, max, values, interpolating); functions[name] = new ReferenceTabulatedFunction(min, max, values, interpolating);
} }
// Parse the various expressions used to calculate the force. // Parse the various expressions used to calculate the force.
...@@ -953,14 +953,14 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu ...@@ -953,14 +953,14 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu
// Create custom functions for the tabulated functions. // Create custom functions for the tabulated functions.
map<string, Lepton::CustomFunction*> functions; map<string, Lepton::CustomFunction*> functions;
// for (int i = 0; i < force.getNumFunctions(); i++) { for (int i = 0; i < force.getNumFunctions(); i++) {
// string name; string name;
// vector<double> values; vector<double> values;
// double min, max; double min, max;
// bool interpolating; bool interpolating;
// force.getFunctionParameters(i, name, values, min, max, interpolating); force.getFunctionParameters(i, name, values, min, max, interpolating);
// functions[name] = new TabulatedFunction(min, max, values, interpolating); functions[name] = new ReferenceTabulatedFunction(min, max, values, interpolating);
// } }
// Parse the expressions for computed values. // Parse the expressions for computed values.
...@@ -978,7 +978,7 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu ...@@ -978,7 +978,7 @@ void ReferenceCalcCustomGBForceKernel::initialize(const System& system, const Cu
valueDerivExpressions.push_back(ex.differentiate("r").optimize().createProgram()); valueDerivExpressions.push_back(ex.differentiate("r").optimize().createProgram());
} }
// Parse the various expressions used to calculate the force. // Parse the expressions for energy terms.
energyDerivExpressions.resize(force.getNumEnergyTerms()); energyDerivExpressions.resize(force.getNumEnergyTerms());
for (int i = 0; i < force.getNumEnergyTerms(); i++) { for (int i = 0; i < force.getNumEnergyTerms(); i++) {
......
...@@ -407,7 +407,6 @@ private: ...@@ -407,7 +407,6 @@ private:
std::vector<std::string> parameterNames, globalParameterNames; std::vector<std::string> parameterNames, globalParameterNames;
NonbondedMethod nonbondedMethod; NonbondedMethod nonbondedMethod;
NeighborList* neighborList; NeighborList* neighborList;
class TabulatedFunction;
}; };
/** /**
......
...@@ -139,11 +139,46 @@ void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMe ...@@ -139,11 +139,46 @@ void testOBC(GBSAOBCForce::NonbondedMethod obcMethod, CustomGBForce::NonbondedMe
} }
} }
void testTabulatedFunction(bool interpolating) {
ReferencePlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
CustomGBForce* force = new CustomGBForce();
force->addComputedValue("a", "0", CustomGBForce::ParticlePair);
force->addEnergyTerm("fn(r)+1", CustomGBForce::ParticlePair);
force->addParticle(vector<double>());
force->addParticle(vector<double>());
vector<double> table;
for (int i = 0; i < 21; i++)
table.push_back(std::sin(0.25*i));
force->addFunction("fn", table, 1.0, 6.0, interpolating);
system.addForce(force);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
for (int i = 1; i < 30; i++) {
double x = (7.0/30.0)*i;
positions[1] = Vec3(x, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double force = (x < 1.0 || x > 6.0 ? 0.0 : -std::cos(x-1.0));
double energy = (x < 1.0 || x > 6.0 ? 0.0 : std::sin(x-1.0))+1.0;
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], 0.1);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], 0.1);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), 0.02);
}
}
int main() { int main() {
try { try {
testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff); testOBC(GBSAOBCForce::NoCutoff, CustomGBForce::NoCutoff);
testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic); testOBC(GBSAOBCForce::CutoffNonPeriodic, CustomGBForce::CutoffNonPeriodic);
testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic); testOBC(GBSAOBCForce::CutoffPeriodic, CustomGBForce::CutoffPeriodic);
testTabulatedFunction(true);
testTabulatedFunction(false);
} }
catch(const exception& e) { catch(const exception& e) {
cout << "exception: " << e.what() << endl; cout << "exception: " << e.what() << endl;
......
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