"...ssh:/git@developer.sourcefind.cn:2222/tsoc/openmm.git" did not exist on "c7f629aca4145ad2e337caf10cc544f7ff6f2550"
Unverified Commit ad7a55b8 authored by peastman's avatar peastman Committed by GitHub
Browse files

Merge pull request #2447 from peastman/energy

Avoid unnecessary force evaluation when computing kinetic energy
parents 466a826e 88209091
...@@ -140,6 +140,10 @@ protected: ...@@ -140,6 +140,10 @@ protected:
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
*/ */
double computeKineticEnergy(); double computeKineticEnergy();
/**
* Computing kinetic energy for this integrator does not require forces.
*/
bool kineticEnergyRequiresForce() const;
private: private:
double temperature, friction; double temperature, friction;
int randomNumberSeed; int randomNumberSeed;
......
...@@ -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-2012 Stanford University and the Authors. * * Portions copyright (c) 2008-2019 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -133,6 +133,10 @@ protected: ...@@ -133,6 +133,10 @@ protected:
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
*/ */
double computeKineticEnergy(); double computeKineticEnergy();
/**
* Computing kinetic energy for this integrator does not require forces.
*/
bool kineticEnergyRequiresForce() const;
private: private:
double temperature, friction; double temperature, friction;
int randomNumberSeed; int randomNumberSeed;
......
...@@ -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) 2011-2018 Stanford University and the Authors. * * Portions copyright (c) 2011-2019 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -627,6 +627,10 @@ protected: ...@@ -627,6 +627,10 @@ protected:
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
*/ */
double computeKineticEnergy(); double computeKineticEnergy();
/**
* Get whether computeKineticEnergy() expects forces to have been computed.
*/
bool kineticEnergyRequiresForce() const;
private: private:
class ComputationInfo; class ComputationInfo;
class FunctionInfo; class FunctionInfo;
...@@ -639,7 +643,7 @@ private: ...@@ -639,7 +643,7 @@ private:
std::string kineticEnergy; std::string kineticEnergy;
mutable bool globalsAreCurrent; mutable bool globalsAreCurrent;
int randomNumberSeed; int randomNumberSeed;
bool forcesAreValid; bool forcesAreValid, keNeedsForce;
Kernel kernel; Kernel kernel;
}; };
......
...@@ -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-2019 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -120,8 +120,19 @@ protected: ...@@ -120,8 +120,19 @@ protected:
* Compute the kinetic energy of the system at the current time. This may be different from simply * Compute the kinetic energy of the system at the current time. This may be different from simply
* mv<sup>2</sup>/2. For example, a leapfrog integrator will store velocities offset by half a step, * mv<sup>2</sup>/2. For example, a leapfrog integrator will store velocities offset by half a step,
* but the kinetic energy should be computed at the current time, not delayed by half a step. * but the kinetic energy should be computed at the current time, not delayed by half a step.
*
* If kineticEnergyRequiresForce() returns true, this method can assume that valid forces
* have already been computed.
*/ */
virtual double computeKineticEnergy() = 0; virtual double computeKineticEnergy() = 0;
/**
* Get whether computeKineticEnergy() expects forces to have been computed. The default
* implementation returns true to be safe. Non-leapfrog integrators can override this to
* return false, which makes calling getState() to query the energy less expensive.
*/
virtual bool kineticEnergyRequiresForce() const {
return true;
}
private: private:
double stepSize, constraintTol; double stepSize, constraintTol;
}; };
......
...@@ -76,6 +76,10 @@ double BAOABLangevinIntegrator::computeKineticEnergy() { ...@@ -76,6 +76,10 @@ double BAOABLangevinIntegrator::computeKineticEnergy() {
return kernel.getAs<IntegrateBAOABStepKernel>().computeKineticEnergy(*context, *this); return kernel.getAs<IntegrateBAOABStepKernel>().computeKineticEnergy(*context, *this);
} }
bool BAOABLangevinIntegrator::kineticEnergyRequiresForce() const {
return false;
}
void BAOABLangevinIntegrator::step(int steps) { void BAOABLangevinIntegrator::step(int steps) {
if (context == NULL) if (context == NULL)
throw OpenMMException("This Integrator is not bound to a context!"); throw OpenMMException("This Integrator is not bound to a 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-2012 Stanford University and the Authors. * * Portions copyright (c) 2008-2019 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -71,6 +71,10 @@ double BrownianIntegrator::computeKineticEnergy() { ...@@ -71,6 +71,10 @@ double BrownianIntegrator::computeKineticEnergy() {
return kernel.getAs<IntegrateBrownianStepKernel>().computeKineticEnergy(*context, *this); return kernel.getAs<IntegrateBrownianStepKernel>().computeKineticEnergy(*context, *this);
} }
bool BrownianIntegrator::kineticEnergyRequiresForce() const {
return false;
}
void BrownianIntegrator::step(int steps) { void BrownianIntegrator::step(int steps) {
if (context == NULL) if (context == NULL)
throw OpenMMException("This Integrator is not bound to a context!"); throw OpenMMException("This Integrator is not bound to a context!");
......
...@@ -96,8 +96,9 @@ State Context::getState(int types, bool enforcePeriodicBox, int groups) const { ...@@ -96,8 +96,9 @@ State Context::getState(int types, bool enforcePeriodicBox, int groups) const {
bool includeForces = types&State::Forces; bool includeForces = types&State::Forces;
bool includeEnergy = types&State::Energy; bool includeEnergy = types&State::Energy;
bool includeParameterDerivs = types&State::ParameterDerivatives; bool includeParameterDerivs = types&State::ParameterDerivatives;
bool needForcesForEnergy = (includeEnergy && getIntegrator().kineticEnergyRequiresForce());
if (includeForces || includeEnergy || includeParameterDerivs) { if (includeForces || includeEnergy || includeParameterDerivs) {
double energy = impl->calcForcesAndEnergy(includeForces || includeEnergy || includeParameterDerivs, includeEnergy, groups); double energy = impl->calcForcesAndEnergy(includeForces || needForcesForEnergy || includeParameterDerivs, includeEnergy, groups);
if (includeEnergy) if (includeEnergy)
builder.setEnergy(impl->calcKineticEnergy(), energy); builder.setEnergy(impl->calcKineticEnergy(), energy);
if (includeForces) { if (includeForces) {
......
...@@ -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) 2011-2017 Stanford University and the Authors. * * Portions copyright (c) 2011-2019 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
#include "openmm/internal/AssertionUtilities.h" #include "openmm/internal/AssertionUtilities.h"
#include "openmm/internal/ContextImpl.h" #include "openmm/internal/ContextImpl.h"
#include "openmm/kernels.h" #include "openmm/kernels.h"
#include "lepton/CompiledExpression.h"
#include "lepton/ParsedExpression.h"
#include "lepton/Parser.h"
#include <set> #include <set>
#include <string> #include <string>
...@@ -45,7 +48,7 @@ CustomIntegrator::CustomIntegrator(double stepSize) : globalsAreCurrent(true), f ...@@ -45,7 +48,7 @@ CustomIntegrator::CustomIntegrator(double stepSize) : globalsAreCurrent(true), f
setStepSize(stepSize); setStepSize(stepSize);
setConstraintTolerance(1e-5); setConstraintTolerance(1e-5);
setRandomNumberSeed(0); setRandomNumberSeed(0);
kineticEnergy = "m*v*v/2"; setKineticEnergyExpression("m*v*v/2");
} }
CustomIntegrator::~CustomIntegrator() { CustomIntegrator::~CustomIntegrator() {
...@@ -103,9 +106,14 @@ vector<string> CustomIntegrator::getKernelNames() { ...@@ -103,9 +106,14 @@ vector<string> CustomIntegrator::getKernelNames() {
} }
double CustomIntegrator::computeKineticEnergy() { double CustomIntegrator::computeKineticEnergy() {
forcesAreValid = keNeedsForce;
return kernel.getAs<IntegrateCustomStepKernel>().computeKineticEnergy(*context, *this, forcesAreValid); return kernel.getAs<IntegrateCustomStepKernel>().computeKineticEnergy(*context, *this, forcesAreValid);
} }
bool CustomIntegrator::kineticEnergyRequiresForce() const {
return keNeedsForce;
}
void CustomIntegrator::step(int steps) { void CustomIntegrator::step(int steps) {
if (context == NULL) if (context == NULL)
throw OpenMMException("This Integrator is not bound to a context!"); throw OpenMMException("This Integrator is not bound to a context!");
...@@ -312,4 +320,6 @@ const string& CustomIntegrator::getKineticEnergyExpression() const { ...@@ -312,4 +320,6 @@ const string& CustomIntegrator::getKineticEnergyExpression() const {
void CustomIntegrator::setKineticEnergyExpression(const string& expression) { void CustomIntegrator::setKineticEnergyExpression(const string& expression) {
kineticEnergy = expression; kineticEnergy = expression;
Lepton::CompiledExpression expr = Lepton::Parser::parse(kineticEnergy).createCompiledExpression();
keNeedsForce = (expr.getVariables().find("f") != expr.getVariables().end());
} }
...@@ -1633,7 +1633,7 @@ private: ...@@ -1633,7 +1633,7 @@ private:
double energy; double energy;
float energyFloat; float energyFloat;
int numGlobalVariables, sumWorkGroupSize; int numGlobalVariables, sumWorkGroupSize;
bool hasInitializedKernels, deviceGlobalsAreCurrent, modifiesParameters, keNeedsForce, hasAnyConstraints, needsEnergyParamDerivs; bool hasInitializedKernels, deviceGlobalsAreCurrent, modifiesParameters, hasAnyConstraints, needsEnergyParamDerivs;
std::vector<bool> deviceValuesAreCurrent; std::vector<bool> deviceValuesAreCurrent;
mutable std::vector<bool> localValuesAreCurrent; mutable std::vector<bool> localValuesAreCurrent;
CudaArray globalValues; CudaArray globalValues;
......
...@@ -7957,7 +7957,6 @@ void CudaIntegrateCustomStepKernel::prepareForComputation(ContextImpl& context, ...@@ -7957,7 +7957,6 @@ void CudaIntegrateCustomStepKernel::prepareForComputation(ContextImpl& context,
kineticEnergyArgs.push_back(&array.getDevicePointer()); kineticEnergyArgs.push_back(&array.getDevicePointer());
for (auto& array : tabulatedFunctions) for (auto& array : tabulatedFunctions)
kineticEnergyArgs.push_back(&array.getDevicePointer()); kineticEnergyArgs.push_back(&array.getDevicePointer());
keNeedsForce = usesVariable(keExpression, "f");
// Create a second kernel to sum the values. // Create a second kernel to sum the values.
...@@ -8213,17 +8212,6 @@ bool CudaIntegrateCustomStepKernel::evaluateCondition(int step) { ...@@ -8213,17 +8212,6 @@ bool CudaIntegrateCustomStepKernel::evaluateCondition(int step) {
double CudaIntegrateCustomStepKernel::computeKineticEnergy(ContextImpl& context, CustomIntegrator& integrator, bool& forcesAreValid) { double CudaIntegrateCustomStepKernel::computeKineticEnergy(ContextImpl& context, CustomIntegrator& integrator, bool& forcesAreValid) {
prepareForComputation(context, integrator, forcesAreValid); prepareForComputation(context, integrator, forcesAreValid);
if (keNeedsForce && !forcesAreValid) {
// Compute the force. We want to then mark that forces are valid, which means also computing
// potential energy if any steps will expect it to be valid too.
bool willNeedEnergy = false;
for (int i = 0; i < integrator.getNumComputations(); i++)
willNeedEnergy |= needsEnergy[i];
energy = context.calcForcesAndEnergy(true, willNeedEnergy, -1);
energyFloat = (float) energy;
forcesAreValid = true;
}
CUdeviceptr posCorrection = (cu.getUseMixedPrecision() ? cu.getPosqCorrection().getDevicePointer() : 0); CUdeviceptr posCorrection = (cu.getUseMixedPrecision() ? cu.getPosqCorrection().getDevicePointer() : 0);
int randomIndex = 0; int randomIndex = 0;
kineticEnergyArgs[1] = &posCorrection; kineticEnergyArgs[1] = &posCorrection;
......
...@@ -1625,7 +1625,7 @@ private: ...@@ -1625,7 +1625,7 @@ private:
double energy; double energy;
float energyFloat; float energyFloat;
int numGlobalVariables, sumWorkGroupSize; int numGlobalVariables, sumWorkGroupSize;
bool hasInitializedKernels, deviceGlobalsAreCurrent, modifiesParameters, keNeedsForce, hasAnyConstraints, needsEnergyParamDerivs; bool hasInitializedKernels, deviceGlobalsAreCurrent, modifiesParameters, hasAnyConstraints, needsEnergyParamDerivs;
std::vector<bool> deviceValuesAreCurrent; std::vector<bool> deviceValuesAreCurrent;
mutable std::vector<bool> localValuesAreCurrent; mutable std::vector<bool> localValuesAreCurrent;
OpenCLArray globalValues; OpenCLArray globalValues;
......
...@@ -8364,7 +8364,6 @@ void OpenCLIntegrateCustomStepKernel::prepareForComputation(ContextImpl& context ...@@ -8364,7 +8364,6 @@ void OpenCLIntegrateCustomStepKernel::prepareForComputation(ContextImpl& context
kineticEnergyKernel.setArg<cl::Buffer>(index++, array.getDeviceBuffer()); kineticEnergyKernel.setArg<cl::Buffer>(index++, array.getDeviceBuffer());
for (auto& array : tabulatedFunctions) for (auto& array : tabulatedFunctions)
kineticEnergyKernel.setArg<cl::Buffer>(index++, array.getDeviceBuffer()); kineticEnergyKernel.setArg<cl::Buffer>(index++, array.getDeviceBuffer());
keNeedsForce = usesVariable(keExpression, "f");
// Create a second kernel to sum the values. // Create a second kernel to sum the values.
...@@ -8627,16 +8626,6 @@ bool OpenCLIntegrateCustomStepKernel::evaluateCondition(int step) { ...@@ -8627,16 +8626,6 @@ bool OpenCLIntegrateCustomStepKernel::evaluateCondition(int step) {
double OpenCLIntegrateCustomStepKernel::computeKineticEnergy(ContextImpl& context, CustomIntegrator& integrator, bool& forcesAreValid) { double OpenCLIntegrateCustomStepKernel::computeKineticEnergy(ContextImpl& context, CustomIntegrator& integrator, bool& forcesAreValid) {
prepareForComputation(context, integrator, forcesAreValid); prepareForComputation(context, integrator, forcesAreValid);
if (keNeedsForce && !forcesAreValid) {
// Compute the force. We want to then mark that forces are valid, which means also computing
// potential energy if any steps will expect it to be valid too.
bool willNeedEnergy = false;
for (int i = 0; i < integrator.getNumComputations(); i++)
willNeedEnergy |= needsEnergy[i];
energy = context.calcForcesAndEnergy(true, willNeedEnergy, -1);
forcesAreValid = true;
}
cl.clearBuffer(sumBuffer); cl.clearBuffer(sumBuffer);
kineticEnergyKernel.setArg<cl::Buffer>(8, cl.getIntegrationUtilities().getRandom().getDeviceBuffer()); kineticEnergyKernel.setArg<cl::Buffer>(8, cl.getIntegrationUtilities().getRandom().getDeviceBuffer());
kineticEnergyKernel.setArg<cl_uint>(9, 0); kineticEnergyKernel.setArg<cl_uint>(9, 0);
......
...@@ -463,10 +463,6 @@ double ReferenceCustomDynamics::computeKineticEnergy(OpenMM::ContextImpl& contex ...@@ -463,10 +463,6 @@ double ReferenceCustomDynamics::computeKineticEnergy(OpenMM::ContextImpl& contex
globals.insert(context.getParameters().begin(), context.getParameters().end()); globals.insert(context.getParameters().begin(), context.getParameters().end());
for (auto& global : globals) for (auto& global : globals)
expressionSet.setVariable(expressionSet.getVariableIndex(global.first), global.second); expressionSet.setVariable(expressionSet.getVariableIndex(global.first), global.second);
if (kineticEnergyNeedsForce) {
energy = context.calcForcesAndEnergy(true, true, -1);
forcesAreValid = true;
}
computePerDof(numberOfAtoms, sumBuffer, atomCoordinates, velocities, forces, masses, perDof, kineticEnergyExpression); computePerDof(numberOfAtoms, sumBuffer, atomCoordinates, velocities, forces, masses, perDof, kineticEnergyExpression);
double sum = 0.0; double sum = 0.0;
for (int j = 0; j < numberOfAtoms; j++) for (int j = 0; j < numberOfAtoms; j++)
......
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