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
...@@ -1086,6 +1086,24 @@ is exactly equivalent to ...@@ -1086,6 +1086,24 @@ is exactly equivalent to
The definition of an intermediate value may itself involve other intermediate The definition of an intermediate value may itself involve other intermediate
values. All uses of a value must appear *before* that value’s definition. values. All uses of a value must appear *before* that value’s definition.
Parameter Derivatives
*********************
Many custom forces have the ability to compute derivatives of the potential energy
with respect to global parameters. To use this feature, first define a global
parameter that the energy depends on. Then instruct the custom force to compute
the derivative with respect to that parameter by calling :meth:`addEnergyParameterDerivative()`
on it. Whenever forces and energies are computed, the specified derivative will
then also be computed at the same time. You can query it by calling :meth:`getState()`
on a :class:`Context`, just as you would query forces or energies.
An important application of this feature is to use it in combination with a
:class:`CustomIntegrator` (described in section :ref:`custom-integrator`\ ). The
derivative can appear directly in expressions that define the integration
algorithm. This can be used to implement algorithms such as lambda-dynamics,
where a global parameter is integrated as a dynamic variable.
Integrators Integrators
########### ###########
...@@ -1235,6 +1253,8 @@ Furthermore, because Langevin dynamics involves a random force, it can never be ...@@ -1235,6 +1253,8 @@ Furthermore, because Langevin dynamics involves a random force, it can never be
symplectic and therefore the fixed step size Verlet integrator’s advantages do symplectic and therefore the fixed step size Verlet integrator’s advantages do
not apply to the Langevin integrator. not apply to the Langevin integrator.
.. _custom-integrator:
CustomIntegrator CustomIntegrator
**************** ****************
......
...@@ -48,7 +48,7 @@ public: ...@@ -48,7 +48,7 @@ public:
virtual ~CustomFunction() { virtual ~CustomFunction() {
} }
/** /**
* Get the number of arguments this function exprects. * Get the number of arguments this function expects.
*/ */
virtual int getNumArguments() const = 0; virtual int getNumArguments() const = 0;
/** /**
......
...@@ -109,7 +109,7 @@ ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const Ex ...@@ -109,7 +109,7 @@ ExpressionTreeNode ParsedExpression::precalculateConstantSubexpressions(const Ex
for (int i = 0; i < (int) children.size(); i++) for (int i = 0; i < (int) children.size(); i++)
children[i] = precalculateConstantSubexpressions(node.getChildren()[i]); children[i] = precalculateConstantSubexpressions(node.getChildren()[i]);
ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children); ExpressionTreeNode result = ExpressionTreeNode(node.getOperation().clone(), children);
if (node.getOperation().getId() == Operation::VARIABLE) if (node.getOperation().getId() == Operation::VARIABLE || node.getOperation().getId() == Operation::CUSTOM)
return result; return result;
for (int i = 0; i < (int) children.size(); i++) for (int i = 0; i < (int) children.size(); i++)
if (children[i].getOperation().getId() != Operation::CONSTANT) if (children[i].getOperation().getId() != Operation::CONSTANT)
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -172,6 +172,12 @@ public: ...@@ -172,6 +172,12 @@ public:
* @param forces on exit, this contains the forces * @param forces on exit, this contains the forces
*/ */
virtual void getForces(ContextImpl& context, std::vector<Vec3>& forces) = 0; virtual void getForces(ContextImpl& context, std::vector<Vec3>& forces) = 0;
/**
* Get the current derivatives of the energy with respect to context parameters.
*
* @param derivs on exit, this contains the derivatives
*/
virtual void getEnergyParameterDerivatives(ContextImpl& context, std::map<std::string, double>& derivs) = 0;
/** /**
* Get the current periodic box vectors. * Get the current periodic box vectors.
* *
......
...@@ -63,6 +63,10 @@ namespace OpenMM { ...@@ -63,6 +63,10 @@ namespace OpenMM {
* force->addPerAngleParameter("k"); * force->addPerAngleParameter("k");
* force->addPerAngleParameter("theta0"); * force->addPerAngleParameter("theta0");
* </pre></tt> * </pre></tt>
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -97,6 +101,13 @@ public: ...@@ -97,6 +101,13 @@ public:
int getNumGlobalParameters() const { int getNumGlobalParameters() const {
return globalParameters.size(); return globalParameters.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the algebraic expression that gives the interaction energy for each angle * Get the algebraic expression that gives the interaction energy for each angle
*/ */
...@@ -162,6 +173,21 @@ public: ...@@ -162,6 +173,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add an angle term to the force field. * Add an angle term to the force field.
* *
...@@ -225,6 +251,7 @@ private: ...@@ -225,6 +251,7 @@ private:
std::vector<AngleParameterInfo> parameters; std::vector<AngleParameterInfo> parameters;
std::vector<GlobalParameterInfo> globalParameters; std::vector<GlobalParameterInfo> globalParameters;
std::vector<AngleInfo> angles; std::vector<AngleInfo> angles;
std::vector<int> energyParameterDerivatives;
bool usePeriodic; bool usePeriodic;
}; };
......
...@@ -63,6 +63,10 @@ namespace OpenMM { ...@@ -63,6 +63,10 @@ namespace OpenMM {
* force->addPerBondParameter("k"); * force->addPerBondParameter("k");
* force->addPerBondParameter("r0"); * force->addPerBondParameter("r0");
* </pre></tt> * </pre></tt>
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -97,6 +101,13 @@ public: ...@@ -97,6 +101,13 @@ public:
int getNumGlobalParameters() const { int getNumGlobalParameters() const {
return globalParameters.size(); return globalParameters.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the algebraic expression that gives the interaction energy for each bond * Get the algebraic expression that gives the interaction energy for each bond
*/ */
...@@ -162,6 +173,21 @@ public: ...@@ -162,6 +173,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add a bond term to the force field. * Add a bond term to the force field.
* *
...@@ -222,6 +248,7 @@ private: ...@@ -222,6 +248,7 @@ private:
std::vector<BondParameterInfo> parameters; std::vector<BondParameterInfo> parameters;
std::vector<GlobalParameterInfo> globalParameters; std::vector<GlobalParameterInfo> globalParameters;
std::vector<BondInfo> bonds; std::vector<BondInfo> bonds;
std::vector<int> energyParameterDerivatives;
bool usePeriodic; bool usePeriodic;
}; };
......
...@@ -98,6 +98,10 @@ namespace OpenMM { ...@@ -98,6 +98,10 @@ namespace OpenMM {
* bondParameters.push_back(k); * bondParameters.push_back(k);
* force->addBond(bondGroups, bondParameters); * force->addBond(bondGroups, bondParameters);
* </pre></tt> * </pre></tt>
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -150,6 +154,13 @@ public: ...@@ -150,6 +154,13 @@ public:
int getNumGlobalParameters() const { int getNumGlobalParameters() const {
return globalParameters.size(); return globalParameters.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the number of tabulated functions that have been defined. * Get the number of tabulated functions that have been defined.
*/ */
...@@ -229,6 +240,21 @@ public: ...@@ -229,6 +240,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add a particle group. * Add a particle group.
* *
...@@ -351,6 +377,7 @@ private: ...@@ -351,6 +377,7 @@ private:
std::vector<GroupInfo> groups; std::vector<GroupInfo> groups;
std::vector<BondInfo> bonds; std::vector<BondInfo> bonds;
std::vector<FunctionInfo> functions; std::vector<FunctionInfo> functions;
std::vector<int> energyParameterDerivatives;
bool usePeriodic; bool usePeriodic;
}; };
......
...@@ -87,6 +87,10 @@ namespace OpenMM { ...@@ -87,6 +87,10 @@ namespace OpenMM {
* force->addPerBondParameter("theta0"); * force->addPerBondParameter("theta0");
* force->addPerBondParameter("r0"); * force->addPerBondParameter("r0");
* </pre></tt> * </pre></tt>
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -133,6 +137,13 @@ public: ...@@ -133,6 +137,13 @@ public:
int getNumGlobalParameters() const { int getNumGlobalParameters() const {
return globalParameters.size(); return globalParameters.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the number of tabulated functions that have been defined. * Get the number of tabulated functions that have been defined.
*/ */
...@@ -212,6 +223,21 @@ public: ...@@ -212,6 +223,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add a bond to the force * Add a bond to the force
* *
...@@ -323,6 +349,7 @@ private: ...@@ -323,6 +349,7 @@ private:
std::vector<GlobalParameterInfo> globalParameters; std::vector<GlobalParameterInfo> globalParameters;
std::vector<BondInfo> bonds; std::vector<BondInfo> bonds;
std::vector<FunctionInfo> functions; std::vector<FunctionInfo> functions;
std::vector<int> energyParameterDerivatives;
bool usePeriodic; bool usePeriodic;
}; };
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * 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 * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -127,6 +127,10 @@ namespace OpenMM { ...@@ -127,6 +127,10 @@ namespace OpenMM {
* omitted from calculations. This is most often used for particles that are bonded to each other. Even if you specify exclusions, * omitted from calculations. This is most often used for particles that are bonded to each other. Even if you specify exclusions,
* however, you can use the computation type ParticlePairNoExclusions to indicate that exclusions should not be applied to a * however, you can use the computation type ParticlePairNoExclusions to indicate that exclusions should not be applied to a
* particular piece of the computation. * particular piece of the computation.
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -207,6 +211,13 @@ public: ...@@ -207,6 +211,13 @@ public:
int getNumGlobalParameters() const { int getNumGlobalParameters() const {
return globalParameters.size(); return globalParameters.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the number of tabulated functions that have been defined. * Get the number of tabulated functions that have been defined.
*/ */
...@@ -312,6 +323,21 @@ public: ...@@ -312,6 +323,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add the nonbonded force parameters for a particle. This should be called once for each particle * Add the nonbonded force parameters for a particle. This should be called once for each particle
* in the System. When it is called for the i'th time, it specifies the parameters for the i'th particle. * in the System. When it is called for the i'th time, it specifies the parameters for the i'th particle.
...@@ -550,6 +576,7 @@ private: ...@@ -550,6 +576,7 @@ private:
std::vector<FunctionInfo> functions; std::vector<FunctionInfo> functions;
std::vector<ComputationInfo> computedValues; std::vector<ComputationInfo> computedValues;
std::vector<ComputationInfo> energyTerms; std::vector<ComputationInfo> energyTerms;
std::vector<int> energyParameterDerivatives;
}; };
/** /**
......
...@@ -201,6 +201,16 @@ namespace OpenMM { ...@@ -201,6 +201,16 @@ namespace OpenMM {
* only involve global variables, not per-DOF ones. It may use any of the * only involve global variables, not per-DOF ones. It may use any of the
* following comparison operators: =, <. >, !=, <=, >=. Blocks may be nested * following comparison operators: =, <. >, !=, <=, >=. Blocks may be nested
* inside each other. * inside each other.
*
* Another feature of CustomIntegrator is that it can use derivatives of the
* potential energy with respect to context parameters. These derivatives are
* typically computed by custom forces, and are only computed if a Force object
* has been specifically told to compute them by calling addEnergyParameterDerivative()
* on it. CustomIntegrator provides a deriv() function for accessing these
* derivatives in global or per-DOF expressions. For example, "deriv(energy, lambda)"
* is the derivative of the total potentially energy with respect to the parameter
* lambda. You can also restrict it to a single force group by specifying a different
* variable for the first argument, such as "deriv(energy1, lambda)".
* *
* An Integrator has one other job in addition to evolving the equations of motion: * An Integrator has one other job in addition to evolving the equations of motion:
* it defines how to compute the kinetic energy of the system. Depending on the * it defines how to compute the kinetic energy of the system. Depending on the
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * 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 * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -118,6 +118,10 @@ namespace OpenMM { ...@@ -118,6 +118,10 @@ namespace OpenMM {
* at the start of the simulation. Furthermore, that precomputation must be repeated every time a global parameter changes * at the start of the simulation. Furthermore, that precomputation must be repeated every time a global parameter changes
* (or when you modify per-particle parameters by calling updateParametersInContext()). This means that if parameters change * (or when you modify per-particle parameters by calling updateParametersInContext()). This means that if parameters change
* frequently, the long range correction can be very slow. For this reason, it is disabled by default. * frequently, the long range correction can be very slow. For this reason, it is disabled by default.
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -204,6 +208,13 @@ public: ...@@ -204,6 +208,13 @@ public:
int getNumInteractionGroups() const { int getNumInteractionGroups() const {
return interactionGroups.size(); return interactionGroups.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the algebraic expression that gives the interaction energy between two particles * Get the algebraic expression that gives the interaction energy between two particles
*/ */
...@@ -321,6 +332,21 @@ public: ...@@ -321,6 +332,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add the nonbonded force parameters for a particle. This should be called once for each particle * Add the nonbonded force parameters for a particle. This should be called once for each particle
* in the System. When it is called for the i'th time, it specifies the parameters for the i'th particle. * in the System. When it is called for the i'th time, it specifies the parameters for the i'th particle.
...@@ -494,6 +520,7 @@ private: ...@@ -494,6 +520,7 @@ private:
std::vector<ExclusionInfo> exclusions; std::vector<ExclusionInfo> exclusions;
std::vector<FunctionInfo> functions; std::vector<FunctionInfo> functions;
std::vector<InteractionGroupInfo> interactionGroups; std::vector<InteractionGroupInfo> interactionGroups;
std::vector<int> energyParameterDerivatives;
}; };
/** /**
......
...@@ -63,6 +63,10 @@ namespace OpenMM { ...@@ -63,6 +63,10 @@ namespace OpenMM {
* force->addPerTorsionParameter("k"); * force->addPerTorsionParameter("k");
* force->addPerTorsionParameter("theta0"); * force->addPerTorsionParameter("theta0");
* </pre></tt> * </pre></tt>
*
* This class also has the ability to compute derivatives of the potential energy with respect to global parameters.
* Call addEnergyParameterDerivative() to request that the derivative with respect to a particular parameter be
* computed. You can then query its value in a Context by calling getState() on it.
* *
* 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, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions * functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, floor, ceil, step, delta, select. All trigonometric functions
...@@ -97,6 +101,13 @@ public: ...@@ -97,6 +101,13 @@ public:
int getNumGlobalParameters() const { int getNumGlobalParameters() const {
return globalParameters.size(); return globalParameters.size();
} }
/**
* Get the number of global parameters with respect to which the derivative of the energy
* should be computed.
*/
int getNumEnergyParameterDerivatives() const {
return energyParameterDerivatives.size();
}
/** /**
* Get the algebraic expression that gives the interaction energy for each torsion * Get the algebraic expression that gives the interaction energy for each torsion
*/ */
...@@ -162,6 +173,21 @@ public: ...@@ -162,6 +173,21 @@ public:
* @param defaultValue the default value of the parameter * @param defaultValue the default value of the parameter
*/ */
void setGlobalParameterDefaultValue(int index, double defaultValue); void setGlobalParameterDefaultValue(int index, double defaultValue);
/**
* Request that this Force compute the derivative of its energy with respect to a global parameter.
* The parameter must have already been added with addGlobalParameter().
*
* @param name the name of the parameter
*/
void addEnergyParameterDerivative(const std::string& name);
/**
* Get the name of a global parameter with respect to which this Force should compute the
* derivative of the energy.
*
* @param index the index of the parameter derivative, between 0 and getNumEnergyParameterDerivatives()
* @return the parameter name
*/
const std::string& getEnergyParameterDerivativeName(int index) const;
/** /**
* Add a torsion term to the force field. * Add a torsion term to the force field.
* *
...@@ -228,6 +254,7 @@ private: ...@@ -228,6 +254,7 @@ private:
std::vector<TorsionParameterInfo> parameters; std::vector<TorsionParameterInfo> parameters;
std::vector<GlobalParameterInfo> globalParameters; std::vector<GlobalParameterInfo> globalParameters;
std::vector<TorsionInfo> torsions; std::vector<TorsionInfo> torsions;
std::vector<int> energyParameterDerivatives;
bool usePeriodic; bool usePeriodic;
}; };
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * 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 * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -58,7 +58,7 @@ public: ...@@ -58,7 +58,7 @@ public:
* This is an enumeration of the types of data which may be stored in a State. When you create * This is an enumeration of the types of data which may be stored in a State. When you create
* a State, use these values to specify which data types it should contain. * a State, use these values to specify which data types it should contain.
*/ */
enum DataType {Positions=1, Velocities=2, Forces=4, Energy=8, Parameters=16}; enum DataType {Positions=1, Velocities=2, Forces=4, Energy=8, Parameters=16, ParameterDerivatives=32};
/** /**
* Construct an empty State containing no data. This exists so State objects can be used in STL containers. * Construct an empty State containing no data. This exists so State objects can be used in STL containers.
*/ */
...@@ -108,6 +108,17 @@ public: ...@@ -108,6 +108,17 @@ public:
* Get a map containing the values of all parameters. If this State does not contain parameters, this will throw an exception. * Get a map containing the values of all parameters. If this State does not contain parameters, this will throw an exception.
*/ */
const std::map<std::string, double>& getParameters() const; const std::map<std::string, double>& getParameters() const;
/**
* Get a map containing derivatives of the potential energy with respect to context parameters.
* In most cases derivatives are only calculated if the corresponding Force objects have been
* specifically told to compute them. Otherwise, the values in the map will be zero. Likewise,
* if multiple Forces depend on the same parameter but only some have been told to compute
* derivatives with respect to it, the returned value will include only the contributions from
* the Forces that were told to compute it.
*
* If this State does not contain parameter derivatives, this will throw an exception.
*/
const std::map<std::string, double>& getEnergyParameterDerivatives() const;
/** /**
* Get which data types are stored in this State. The return value is a sum of DataType flags. * Get which data types are stored in this State. The return value is a sum of DataType flags.
*/ */
...@@ -118,6 +129,7 @@ private: ...@@ -118,6 +129,7 @@ private:
void setVelocities(const std::vector<Vec3>& vel); void setVelocities(const std::vector<Vec3>& vel);
void setForces(const std::vector<Vec3>& force); void setForces(const std::vector<Vec3>& force);
void setParameters(const std::map<std::string, double>& params); void setParameters(const std::map<std::string, double>& params);
void setEnergyParameterDerivatives(const std::map<std::string, double>& derivs);
void setEnergy(double ke, double pe); void setEnergy(double ke, double pe);
void setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c); void setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c);
int types; int types;
...@@ -126,7 +138,7 @@ private: ...@@ -126,7 +138,7 @@ private:
std::vector<Vec3> velocities; std::vector<Vec3> velocities;
std::vector<Vec3> forces; std::vector<Vec3> forces;
Vec3 periodicBoxVectors[3]; Vec3 periodicBoxVectors[3];
std::map<std::string, double> parameters; std::map<std::string, double> parameters, energyParameterDerivatives;
}; };
/** /**
...@@ -142,6 +154,7 @@ public: ...@@ -142,6 +154,7 @@ public:
void setVelocities(const std::vector<Vec3>& vel); void setVelocities(const std::vector<Vec3>& vel);
void setForces(const std::vector<Vec3>& force); void setForces(const std::vector<Vec3>& force);
void setParameters(const std::map<std::string, double>& params); void setParameters(const std::map<std::string, double>& params);
void setEnergyParameterDerivatives(const std::map<std::string, double>& params);
void setEnergy(double ke, double pe); void setEnergy(double ke, double pe);
void setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c); void setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3& c);
private: private:
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008-2013 Stanford University and the Authors. * * Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -138,6 +138,10 @@ public: ...@@ -138,6 +138,10 @@ public:
* @param value the value of the parameter * @param value the value of the parameter
*/ */
void setParameter(std::string name, double value); void setParameter(std::string name, double value);
/**
* Get the derivatives of the energy with respect to parameters.
*/
void getEnergyParameterDerivatives(std::map<std::string, double>& derivs);
/** /**
* Get the vectors defining the axes of the periodic box (measured in nm). They will affect * Get the vectors defining the axes of the periodic box (measured in nm). They will affect
* any Force that uses periodic boundary conditions. * any Force that uses periodic boundary conditions.
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * 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 * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -34,8 +34,10 @@ ...@@ -34,8 +34,10 @@
#include "openmm/CustomIntegrator.h" #include "openmm/CustomIntegrator.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "lepton/CustomFunction.h"
#include "lepton/ParsedExpression.h" #include "lepton/ParsedExpression.h"
#include <map> #include <map>
#include <string>
#include <vector> #include <vector>
namespace OpenMM { namespace OpenMM {
...@@ -48,6 +50,7 @@ class System; ...@@ -48,6 +50,7 @@ class System;
class OPENMM_EXPORT CustomIntegratorUtilities { class OPENMM_EXPORT CustomIntegratorUtilities {
public: public:
class DerivFunction;
enum Comparison { enum Comparison {
EQUAL = 0, LESS_THAN = 1, GREATER_THAN = 2, NOT_EQUAL = 3, LESS_THAN_OR_EQUAL = 4, GREATER_THAN_OR_EQUAL = 5 EQUAL = 0, LESS_THAN = 1, GREATER_THAN = 2, NOT_EQUAL = 3, LESS_THAN_OR_EQUAL = 4, GREATER_THAN_OR_EQUAL = 5
}; };
...@@ -82,6 +85,28 @@ private: ...@@ -82,6 +85,28 @@ private:
const std::vector<bool>& invalidatesForces, const std::vector<int>& forceGroup, std::vector<bool>& computeBoth); const std::vector<bool>& invalidatesForces, const std::vector<int>& forceGroup, std::vector<bool>& computeBoth);
static void analyzeForceComputationsForPath(std::vector<int>& steps, const std::vector<bool>& needsForces, const std::vector<bool>& needsEnergy, static void analyzeForceComputationsForPath(std::vector<int>& steps, const std::vector<bool>& needsForces, const std::vector<bool>& needsEnergy,
const std::vector<bool>& invalidatesForces, const std::vector<int>& forceGroup, std::vector<bool>& computeBoth); const std::vector<bool>& invalidatesForces, const std::vector<int>& forceGroup, std::vector<bool>& computeBoth);
static void validateDerivatives(const Lepton::ExpressionTreeNode& node, const std::vector<std::string>& derivNames);
};
/**
* This class is used to implement the deriv() function when it appears in expressions.
*/
class CustomIntegratorUtilities::DerivFunction : public Lepton::CustomFunction {
public:
DerivFunction() {
}
int getNumArguments() const {
return 2;
}
double evaluate(const double* arguments) const {
return 0.0;
}
double evaluateDerivative(const double* arguments, const int* derivOrder) const {
return 0.0;
}
CustomFunction* clone() const {
return new DerivFunction();
}
}; };
} // namespace OpenMM } // namespace OpenMM
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * 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 * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -63,9 +63,10 @@ public: ...@@ -63,9 +63,10 @@ public:
void updateParametersInContext(ContextImpl& context); void updateParametersInContext(ContextImpl& context);
/** /**
* Compute the coefficient which, when divided by the periodic box volume, gives the * Compute the coefficient which, when divided by the periodic box volume, gives the
* long range correction to the energy. * long range correction to the energy. If the Force computes parameter derivatives,
* also compute the corresponding derivatives of the correction.
*/ */
static double calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context); static void calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context, double& coefficient, std::vector<double>& derivatives);
private: private:
static double integrateInteraction(Lepton::CompiledExpression& expression, const std::vector<double>& params1, const std::vector<double>& params2, static double integrateInteraction(Lepton::CompiledExpression& expression, const std::vector<double>& params1, const std::vector<double>& params2,
const CustomNonbondedForce& force, const Context& context); const CustomNonbondedForce& force, const Context& context);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for * * Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. * * Medical Research, grant U54 GM072970. See https://simtk.org. *
* * * *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. * * Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -84,8 +84,9 @@ State Context::getState(int types, bool enforcePeriodicBox, int groups) const { ...@@ -84,8 +84,9 @@ State Context::getState(int types, bool enforcePeriodicBox, int groups) const {
builder.setPeriodicBoxVectors(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2]); builder.setPeriodicBoxVectors(periodicBoxSize[0], periodicBoxSize[1], periodicBoxSize[2]);
bool includeForces = types&State::Forces; bool includeForces = types&State::Forces;
bool includeEnergy = types&State::Energy; bool includeEnergy = types&State::Energy;
if (includeForces || includeEnergy) { bool includeParameterDerivs = types&State::ParameterDerivatives;
double energy = impl->calcForcesAndEnergy(includeForces || includeEnergy, includeEnergy, groups); if (includeForces || includeEnergy || includeParameterDerivs) {
double energy = impl->calcForcesAndEnergy(includeForces || includeEnergy || includeParameterDerivs, includeEnergy, groups);
if (includeEnergy) if (includeEnergy)
builder.setEnergy(impl->calcKineticEnergy(), energy); builder.setEnergy(impl->calcKineticEnergy(), energy);
if (includeForces) { if (includeForces) {
...@@ -100,6 +101,11 @@ State Context::getState(int types, bool enforcePeriodicBox, int groups) const { ...@@ -100,6 +101,11 @@ State Context::getState(int types, bool enforcePeriodicBox, int groups) const {
params[iter->first] = iter->second; params[iter->first] = iter->second;
builder.setParameters(params); builder.setParameters(params);
} }
if (types&State::ParameterDerivatives) {
map<string, double> derivs;
impl->getEnergyParameterDerivatives(derivs);
builder.setEnergyParameterDerivatives(derivs);
}
if (types&State::Positions) { if (types&State::Positions) {
vector<Vec3> positions; vector<Vec3> positions;
impl->getPositions(positions); impl->getPositions(positions);
......
...@@ -240,6 +240,10 @@ void ContextImpl::setParameter(std::string name, double value) { ...@@ -240,6 +240,10 @@ void ContextImpl::setParameter(std::string name, double value) {
integrator.stateChanged(State::Parameters); integrator.stateChanged(State::Parameters);
} }
void ContextImpl::getEnergyParameterDerivatives(std::map<std::string, double>& derivs) {
updateStateDataKernel.getAs<UpdateStateDataKernel>().getEnergyParameterDerivatives(*this, derivs);
}
void ContextImpl::getPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) { void ContextImpl::getPeriodicBoxVectors(Vec3& a, Vec3& b, Vec3& c) {
updateStateDataKernel.getAs<UpdateStateDataKernel>().getPeriodicBoxVectors(*this, a, b, c); updateStateDataKernel.getAs<UpdateStateDataKernel>().getPeriodicBoxVectors(*this, a, b, c);
} }
......
...@@ -95,6 +95,20 @@ void CustomAngleForce::setGlobalParameterDefaultValue(int index, double defaultV ...@@ -95,6 +95,20 @@ void CustomAngleForce::setGlobalParameterDefaultValue(int index, double defaultV
globalParameters[index].defaultValue = defaultValue; globalParameters[index].defaultValue = defaultValue;
} }
void CustomAngleForce::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& CustomAngleForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomAngleForce::addAngle(int particle1, int particle2, int particle3, const vector<double>& parameters) { int CustomAngleForce::addAngle(int particle1, int particle2, int particle3, const vector<double>& parameters) {
angles.push_back(AngleInfo(particle1, particle2, particle3, parameters)); angles.push_back(AngleInfo(particle1, particle2, particle3, parameters));
return angles.size()-1; return angles.size()-1;
......
...@@ -95,6 +95,20 @@ void CustomBondForce::setGlobalParameterDefaultValue(int index, double defaultVa ...@@ -95,6 +95,20 @@ void CustomBondForce::setGlobalParameterDefaultValue(int index, double defaultVa
globalParameters[index].defaultValue = defaultValue; globalParameters[index].defaultValue = defaultValue;
} }
void CustomBondForce::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& CustomBondForce::getEnergyParameterDerivativeName(int index) const {
ASSERT_VALID_INDEX(index, energyParameterDerivatives);
return globalParameters[energyParameterDerivatives[index]].name;
}
int CustomBondForce::addBond(int particle1, int particle2, const vector<double>& parameters) { int CustomBondForce::addBond(int particle1, int particle2, const vector<double>& parameters) {
bonds.push_back(BondInfo(particle1, particle2, parameters)); bonds.push_back(BondInfo(particle1, particle2, parameters));
return bonds.size()-1; return bonds.size()-1;
......
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