Commit 3b6925ae authored by Andy Simmonett's avatar Andy Simmonett Committed by GitHub
Browse files

Merge pull request #1 from peastman/ljpme

Cleanup to LJ PME code
parents 5a8a8aa9 f7a102fb
...@@ -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) 2013 Stanford University and the Authors. * * Portions copyright (c) 2013-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#ifdef LEPTON_USE_JIT #ifdef LEPTON_USE_JIT
#include "asmjit.h" #include "asmjit.h"
...@@ -73,6 +74,12 @@ public: ...@@ -73,6 +74,12 @@ public:
* to set the value of the variable before calling evaluate(). * to set the value of the variable before calling evaluate().
*/ */
double& getVariableReference(const std::string& name); double& getVariableReference(const std::string& name);
/**
* You can optionally specify the memory locations from which the values of variables should be read.
* This is useful, for example, when several expressions all use the same variable. You can then set
* the value of that variable in one place, and it will be seen by all of them.
*/
void setVariableLocations(std::map<std::string, double*>& variableLocations);
/** /**
* Evaluate the expression. The values of all variables should have been set before calling this. * Evaluate the expression. The values of all variables should have been set before calling this.
*/ */
...@@ -82,6 +89,8 @@ private: ...@@ -82,6 +89,8 @@ private:
CompiledExpression(const ParsedExpression& expression); CompiledExpression(const ParsedExpression& expression);
void compileExpression(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int> >& temps); void compileExpression(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int> >& temps);
int findTempIndex(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int> >& temps); int findTempIndex(const ExpressionTreeNode& node, std::vector<std::pair<ExpressionTreeNode, int> >& temps);
std::map<std::string, double*> variablePointers;
std::vector<std::pair<double*, double*> > variablesToCopy;
std::vector<std::vector<int> > arguments; std::vector<std::vector<int> > arguments;
std::vector<int> target; std::vector<int> target;
std::vector<Operation*> operation; std::vector<Operation*> operation;
......
...@@ -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) 2013 Stanford University and the Authors. * * Portions copyright (c) 2013-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -77,10 +77,7 @@ CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expr ...@@ -77,10 +77,7 @@ CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expr
operation.resize(expression.operation.size()); operation.resize(expression.operation.size());
for (int i = 0; i < (int) operation.size(); i++) for (int i = 0; i < (int) operation.size(); i++)
operation[i] = expression.operation[i]->clone(); operation[i] = expression.operation[i]->clone();
#ifdef LEPTON_USE_JIT setVariableLocations(variablePointers);
if (workspace.size() > 0)
generateJitCode();
#endif
return *this; return *this;
} }
...@@ -138,16 +135,41 @@ const set<string>& CompiledExpression::getVariables() const { ...@@ -138,16 +135,41 @@ const set<string>& CompiledExpression::getVariables() const {
} }
double& CompiledExpression::getVariableReference(const string& name) { double& CompiledExpression::getVariableReference(const string& name) {
map<string, double*>::iterator pointer = variablePointers.find(name);
if (pointer != variablePointers.end())
return *pointer->second;
map<string, int>::iterator index = variableIndices.find(name); map<string, int>::iterator index = variableIndices.find(name);
if (index == variableIndices.end()) if (index == variableIndices.end())
throw Exception("getVariableReference: Unknown variable '"+name+"'"); throw Exception("getVariableReference: Unknown variable '"+name+"'");
return workspace[index->second]; return workspace[index->second];
} }
void CompiledExpression::setVariableLocations(map<string, double*>& variableLocations) {
variablePointers = variableLocations;
#ifdef LEPTON_USE_JIT
// Rebuild the JIT code.
if (workspace.size() > 0)
generateJitCode();
#else
// Make a list of all variables we will need to copy before evaluating the expression.
variablesToCopy.clear();
for (map<string, int>::const_iterator iter = variableIndices.begin(); iter != variableIndices.end(); ++iter) {
map<string, double*>::iterator pointer = variablePointers.find(iter->first);
if (pointer != variablePointers.end())
variablesToCopy.push_back(make_pair(&workspace[iter->second], pointer->second));
}
#endif
}
double CompiledExpression::evaluate() const { double CompiledExpression::evaluate() const {
#ifdef LEPTON_USE_JIT #ifdef LEPTON_USE_JIT
return ((double (*)()) jitCode)(); return ((double (*)()) jitCode)();
#else #else
for (int i = 0; i < variablesToCopy.size(); i++)
*variablesToCopy[i].first = *variablesToCopy[i].second;
// Loop over the operations and evaluate each one. // Loop over the operations and evaluate each one.
for (int step = 0; step < operation.size(); step++) { for (int step = 0; step < operation.size(); step++) {
...@@ -176,16 +198,16 @@ void CompiledExpression::generateJitCode() { ...@@ -176,16 +198,16 @@ void CompiledExpression::generateJitCode() {
vector<X86XmmVar> workspaceVar(workspace.size()); vector<X86XmmVar> workspaceVar(workspace.size());
for (int i = 0; i < (int) workspaceVar.size(); i++) for (int i = 0; i < (int) workspaceVar.size(); i++)
workspaceVar[i] = c.newXmmVar(kX86VarTypeXmmSd); workspaceVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
X86GpVar workspacePointer(c);
X86GpVar argsPointer(c); X86GpVar argsPointer(c);
c.mov(workspacePointer, imm_ptr(&workspace[0]));
c.mov(argsPointer, imm_ptr(&argValues[0])); c.mov(argsPointer, imm_ptr(&argValues[0]));
// Load the arguments into variables. // Load the arguments into variables.
for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) { for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) {
map<string, int>::iterator index = variableIndices.find(*iter); map<string, int>::iterator index = variableIndices.find(*iter);
c.movsd(workspaceVar[index->second], x86::ptr(workspacePointer, 8*index->second, 0)); X86GpVar variablePointer(c);
c.mov(variablePointer, imm_ptr(&getVariableReference(index->first)));
c.movsd(workspaceVar[index->second], x86::ptr(variablePointer, 0, 0));
} }
// Make a list of all constants that will be needed for evaluation. // Make a list of all constants that will be needed for evaluation.
......
...@@ -555,7 +555,8 @@ public: ...@@ -555,7 +555,8 @@ public:
CutoffNonPeriodic = 1, CutoffNonPeriodic = 1,
CutoffPeriodic = 2, CutoffPeriodic = 2,
Ewald = 3, Ewald = 3,
PME = 4 PME = 4,
LJPME = 5
}; };
static std::string Name() { static std::string Name() {
return "CalcNonbondedForce"; return "CalcNonbondedForce";
...@@ -596,6 +597,15 @@ public: ...@@ -596,6 +597,15 @@ public:
* @param nz the number of grid points along the Z axis * @param nz the number of grid points along the Z axis
*/ */
virtual void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const = 0; virtual void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const = 0;
/**
* Get the parameters being used for the dispersion terms in LJPME.
*
* @param alpha the separation parameter
* @param nx the number of grid points along the X axis
* @param ny the number of grid points along the Y axis
* @param nz the number of grid points along the Z axis
*/
virtual void getLJPMEParameters(double& alpha, int& nx, int& ny, int& nz) const = 0;
}; };
/** /**
...@@ -1335,6 +1345,57 @@ public: ...@@ -1335,6 +1345,57 @@ public:
}; };
/**
* This kernel performs the dispersion reciprocal space calculation for LJPME. In most cases, this
* calculation is done directly by CalcNonbondedForceKernel so this kernel is unneeded.
* In some cases it may want to outsource the work to a different kernel. In particular,
* GPU based platforms sometimes use a CPU based implementation provided by a separate
* plugin.
*/
class CalcDispersionPmeReciprocalForceKernel : public KernelImpl {
public:
class IO;
static std::string Name() {
return "CalcDispersionPmeReciprocalForce";
}
CalcDispersionPmeReciprocalForceKernel(std::string name, const Platform& platform) : KernelImpl(name, platform) {
}
/**
* Initialize the kernel.
*
* @param gridx the x size of the PME grid
* @param gridy the y size of the PME grid
* @param gridz the z size of the PME grid
* @param numParticles the number of particles in the system
* @param alpha the Ewald blending parameter
*/
virtual void initialize(int gridx, int gridy, int gridz, int numParticles, double alpha) = 0;
/**
* Begin computing the force and energy.
*
* @param io an object that coordinates data transfer
* @param periodicBoxVectors the vectors defining the periodic box (measured in nm)
* @param includeEnergy true if potential energy should be computed
*/
virtual void beginComputation(IO& io, const Vec3* periodicBoxVectors, bool includeEnergy) = 0;
/**
* Finish computing the force and energy.
*
* @param io an object that coordinates data transfer
* @return the potential energy due to the PME reciprocal space interactions
*/
virtual double finishComputation(IO& io) = 0;
/**
* Get the parameters being used for PME.
*
* @param alpha the separation parameter
* @param nx the number of grid points along the X axis
* @param ny the number of grid points along the Y axis
* @param nz the number of grid points along the Z axis
*/
virtual void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const = 0;
};
} // namespace OpenMM } // namespace OpenMM
#endif /*OPENMM_KERNELS_H_*/ #endif /*OPENMM_KERNELS_H_*/
...@@ -104,7 +104,7 @@ void Platform::setPropertyDefaultValue(const string& property, const string& val ...@@ -104,7 +104,7 @@ void Platform::setPropertyDefaultValue(const string& property, const string& val
propertyName = deprecatedPropertyReplacements.find(property)->second; propertyName = deprecatedPropertyReplacements.find(property)->second;
for (int i = 0; i < (int) platformProperties.size(); i++) for (int i = 0; i < (int) platformProperties.size(); i++)
if (platformProperties[i] == propertyName) { if (platformProperties[i] == propertyName) {
defaultProperties[property] = value; defaultProperties[propertyName] = value;
return; return;
} }
throw OpenMMException("setPropertyDefaultValue: Illegal property name"); throw OpenMMException("setPropertyDefaultValue: Illegal property name");
......
...@@ -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: *
* * * *
...@@ -171,6 +171,16 @@ protected: ...@@ -171,6 +171,16 @@ protected:
* The implementation returns the union of all kernel names required by all Integrators that have been added. * The implementation returns the union of all kernel names required by all Integrators that have been added.
*/ */
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
/**
* This will be called by the Context when the user modifies aspects of the context state, such
* as positions, velocities, or parameters. This gives the Integrator a chance to discard cached
* information. This is <i>only</i> called when the user modifies information using methods of the Context
* object. It is <i>not</i> called when a ForceImpl object modifies state information in its updateContextState()
* method (unless the ForceImpl calls a Context method to perform the modification).
*
* @param changed this specifies what aspect of the Context was changed
*/
void stateChanged(State::DataType changed);
/** /**
* Compute the kinetic energy of the system at the current time. * Compute the kinetic energy of the system at the current time.
* *
......
...@@ -57,7 +57,7 @@ namespace OpenMM { ...@@ -57,7 +57,7 @@ namespace OpenMM {
* <li>distance(p1, p2): the distance between particles p1 and p2 (where "p1" and "p2" may be replaced by the names * <li>distance(p1, p2): the distance between particles p1 and p2 (where "p1" and "p2" may be replaced by the names
* of whichever particles you want to calculate the distance between).</li> * of whichever particles you want to calculate the distance between).</li>
* <li>angle(p1, p2, p3): the angle formed by the three specified particles.</li> * <li>angle(p1, p2, p3): the angle formed by the three specified particles.</li>
* <li>dihedral(p1, p2, p3, p4): the dihedral angle formed by the four specified particles.</li> * <li>dihedral(p1, p2, p3, p4): the dihedral angle formed by the four specified particles, guaranteed to be in the range [-pi,+pi].</li>
* </ul> * </ul>
* *
* The expression also may involve tabulated functions, and may depend on arbitrary * The expression also may involve tabulated functions, and may depend on arbitrary
......
...@@ -52,6 +52,7 @@ namespace OpenMM { ...@@ -52,6 +52,7 @@ namespace OpenMM {
* part of the system definition, while values of global parameters may be modified during a simulation by calling Context::setParameter(). * part of the system definition, while values of global parameters may be modified during a simulation by calling Context::setParameter().
* Finally, call addTorsion() once for each torsion. After an torsion has been added, you can modify its parameters by calling setTorsionParameters(). * Finally, call addTorsion() once for each torsion. After an torsion has been added, you can modify its parameters by calling setTorsionParameters().
* This will have no effect on Contexts that already exist unless you call updateParametersInContext(). * This will have no effect on Contexts that already exist unless you call updateParametersInContext().
* theta is guaranteed to be in the range [-pi,+pi]
* *
* As an example, the following code creates a CustomTorsionForce that implements a harmonic potential: * As an example, the following code creates a CustomTorsionForce that implements a harmonic potential:
* *
......
...@@ -191,7 +191,7 @@ public: ...@@ -191,7 +191,7 @@ public:
* @returns true if force uses PBC and false otherwise * @returns true if force uses PBC and false otherwise
*/ */
bool usesPeriodicBoundaryConditions() const { bool usesPeriodicBoundaryConditions() const {
return true; return false;
} }
protected: protected:
ForceImpl* createImpl() const; ForceImpl* createImpl() const;
......
...@@ -147,7 +147,7 @@ public: ...@@ -147,7 +147,7 @@ public:
* @returns true if force uses PBC and false otherwise * @returns true if force uses PBC and false otherwise
*/ */
bool usesPeriodicBoundaryConditions() const { bool usesPeriodicBoundaryConditions() const {
return true; return false;
} }
protected: protected:
ForceImpl* createImpl() const; ForceImpl* createImpl() const;
......
...@@ -244,7 +244,7 @@ public: ...@@ -244,7 +244,7 @@ public:
* @returns true if force uses PBC and false otherwise * @returns true if force uses PBC and false otherwise
*/ */
bool usesPeriodicBoundaryConditions() const { bool usesPeriodicBoundaryConditions() const {
return true; return false;
} }
protected: protected:
ForceImpl* createImpl() const; ForceImpl* createImpl() const;
......
...@@ -109,7 +109,12 @@ public: ...@@ -109,7 +109,12 @@ public:
* Periodic boundary conditions are used, and Particle-Mesh Ewald (PME) summation is used to compute the interaction of each particle * Periodic boundary conditions are used, and Particle-Mesh Ewald (PME) summation is used to compute the interaction of each particle
* with all periodic copies of every other particle. * with all periodic copies of every other particle.
*/ */
PME = 4 PME = 4,
/**
* Periodic boundary conditions are used, and Particle-Mesh Ewald (PME) summation is used to compute the interaction of each particle
* with all periodic copies of every other particle for both electrostatics and dispersion. No switching is used for either interaction.
*/
LJPME = 5
}; };
/** /**
* Create a NonbondedForce. * Create a NonbondedForce.
...@@ -207,6 +212,16 @@ public: ...@@ -207,6 +212,16 @@ public:
* @param[out] nz the number of grid points along the Z axis * @param[out] nz the number of grid points along the Z axis
*/ */
void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const; void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const;
/**
* Get the parameters to use for dispersion term in LJ-PME calculations. If alpha is 0 (the default),
* these parameters are ignored and instead their values are chosen based on the Ewald error tolerance.
*
* @param[out] alpha the separation parameter
* @param[out] nx the number of dispersion grid points along the X axis
* @param[out] ny the number of dispersion grid points along the Y axis
* @param[out] nz the number of dispersion grid points along the Z axis
*/
void getLJPMEParameters(double& alpha, int& nx, int& ny, int& nz) const;
/** /**
* Set the parameters to use for PME calculations. If alpha is 0 (the default), these parameters are * Set the parameters to use for PME calculations. If alpha is 0 (the default), these parameters are
* ignored and instead their values are chosen based on the Ewald error tolerance. * ignored and instead their values are chosen based on the Ewald error tolerance.
...@@ -217,6 +232,16 @@ public: ...@@ -217,6 +232,16 @@ public:
* @param nz the number of grid points along the Z axis * @param nz the number of grid points along the Z axis
*/ */
void setPMEParameters(double alpha, int nx, int ny, int nz); void setPMEParameters(double alpha, int nx, int ny, int nz);
/**
* Set the parameters to use for the dispersion term in LJPME calculations. If alpha is 0 (the default),
* these parameters are ignored and instead their values are chosen based on the Ewald error tolerance.
*
* @param alpha the separation parameter
* @param nx the number of grid points along the X axis
* @param ny the number of grid points along the Y axis
* @param nz the number of grid points along the Z axis
*/
void setLJPMEParameters(double alpha, int nx, int ny, int nz);
/** /**
* Get the parameters being used for PME in a particular Context. Because some platforms have restrictions * Get the parameters being used for PME in a particular Context. Because some platforms have restrictions
* on the allowed grid sizes, the values that are actually used may be slightly different from those * on the allowed grid sizes, the values that are actually used may be slightly different from those
...@@ -230,6 +255,19 @@ public: ...@@ -230,6 +255,19 @@ public:
* @param[out] nz the number of grid points along the Z axis * @param[out] nz the number of grid points along the Z axis
*/ */
void getPMEParametersInContext(const Context& context, double& alpha, int& nx, int& ny, int& nz) const; void getPMEParametersInContext(const Context& context, double& alpha, int& nx, int& ny, int& nz) const;
/**
* Get the PME parameters being used for the dispersion term for LJPME in a particular Context. Because some
* platforms have restrictions on the allowed grid sizes, the values that are actually used may be slightly different
* from those specified with setPMEParameters(), or the standard values calculated based on the Ewald error tolerance.
* See the manual for details.
*
* @param context the Context for which to get the parameters
* @param[out] alpha the separation parameter
* @param[out] nx the number of grid points along the X axis
* @param[out] ny the number of grid points along the Y axis
* @param[out] nz the number of grid points along the Z axis
*/
void getLJPMEParametersInContext(const Context& context, double& alpha, int& nx, int& ny, int& nz) 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.
...@@ -382,9 +420,9 @@ private: ...@@ -382,9 +420,9 @@ private:
class ParticleInfo; class ParticleInfo;
class ExceptionInfo; class ExceptionInfo;
NonbondedMethod nonbondedMethod; NonbondedMethod nonbondedMethod;
double cutoffDistance, switchingDistance, rfDielectric, ewaldErrorTol, alpha; double cutoffDistance, switchingDistance, rfDielectric, ewaldErrorTol, alpha, dalpha;
bool useSwitchingFunction, useDispersionCorrection; bool useSwitchingFunction, useDispersionCorrection;
int recipForceGroup, nx, ny, nz; int recipForceGroup, nx, ny, nz, dnx, dny, dnz;
void addExclusionsToSet(const std::vector<std::set<int> >& bonded12, std::set<int>& exclusions, int baseParticle, int fromParticle, int currentLevel) const; void addExclusionsToSet(const std::vector<std::set<int> >& bonded12, std::set<int>& exclusions, int baseParticle, int fromParticle, int currentLevel) const;
std::vector<ParticleInfo> particles; std::vector<ParticleInfo> particles;
std::vector<ExceptionInfo> exceptions; std::vector<ExceptionInfo> exceptions;
......
...@@ -59,6 +59,9 @@ class OPENMM_EXPORT TabulatedFunction { ...@@ -59,6 +59,9 @@ class OPENMM_EXPORT TabulatedFunction {
public: public:
virtual ~TabulatedFunction() { virtual ~TabulatedFunction() {
} }
/**
* @deprecated This will be removed in a future release.
*/
virtual TabulatedFunction* Copy() const = 0; virtual TabulatedFunction* Copy() const = 0;
}; };
...@@ -99,6 +102,8 @@ public: ...@@ -99,6 +102,8 @@ public:
void setFunctionParameters(const std::vector<double>& values, double min, double max); void setFunctionParameters(const std::vector<double>& values, double min, double max);
/** /**
* Create a deep copy of the tabulated function. * Create a deep copy of the tabulated function.
*
* @deprecated This will be removed in a future release.
*/ */
Continuous1DFunction* Copy() const; Continuous1DFunction* Copy() const;
private: private:
...@@ -158,6 +163,8 @@ public: ...@@ -158,6 +163,8 @@ public:
void setFunctionParameters(int xsize, int ysize, const std::vector<double>& values, double xmin, double xmax, double ymin, double ymax); void setFunctionParameters(int xsize, int ysize, const std::vector<double>& values, double xmin, double xmax, double ymin, double ymax);
/** /**
* Create a deep copy of the tabulated function * Create a deep copy of the tabulated function
*
* @deprecated This will be removed in a future release.
*/ */
Continuous2DFunction* Copy() const; Continuous2DFunction* Copy() const;
private: private:
...@@ -233,6 +240,8 @@ public: ...@@ -233,6 +240,8 @@ public:
void setFunctionParameters(int xsize, int ysize, int zsize, const std::vector<double>& values, double xmin, double xmax, double ymin, double ymax, double zmin, double zmax); void setFunctionParameters(int xsize, int ysize, int zsize, const std::vector<double>& values, double xmin, double xmax, double ymin, double ymax, double zmin, double zmax);
/** /**
* Create a deep copy of the tabulated function * Create a deep copy of the tabulated function
*
* @deprecated This will be removed in a future release.
*/ */
Continuous3DFunction* Copy() const; Continuous3DFunction* Copy() const;
private: private:
...@@ -268,6 +277,8 @@ public: ...@@ -268,6 +277,8 @@ public:
void setFunctionParameters(const std::vector<double>& values); void setFunctionParameters(const std::vector<double>& values);
/** /**
* Create a deep copy of the tabulated function * Create a deep copy of the tabulated function
*
* @deprecated This will be removed in a future release.
*/ */
Discrete1DFunction* Copy() const; Discrete1DFunction* Copy() const;
private: private:
...@@ -310,6 +321,8 @@ public: ...@@ -310,6 +321,8 @@ public:
void setFunctionParameters(int xsize, int ysize, const std::vector<double>& values); void setFunctionParameters(int xsize, int ysize, const std::vector<double>& values);
/** /**
* Create a deep copy of the tabulated function * Create a deep copy of the tabulated function
*
* @deprecated This will be removed in a future release.
*/ */
Discrete2DFunction* Copy() const; Discrete2DFunction* Copy() const;
private: private:
...@@ -356,6 +369,8 @@ public: ...@@ -356,6 +369,8 @@ public:
void setFunctionParameters(int xsize, int ysize, int zsize, const std::vector<double>& values); void setFunctionParameters(int xsize, int ysize, int zsize, const std::vector<double>& values);
/** /**
* Create a deep copy of the tabulated function * Create a deep copy of the tabulated function
*
* @deprecated This will be removed in a future release.
*/ */
Discrete3DFunction* Copy() const; Discrete3DFunction* Copy() const;
private: private:
......
...@@ -252,6 +252,10 @@ public: ...@@ -252,6 +252,10 @@ public:
void integratorDeleted() { void integratorDeleted() {
integratorIsDeleted = true; integratorIsDeleted = true;
} }
/**
* Notify the integrator that some aspect of the system has changed, and cached information should be discarded.
*/
void systemChanged();
/** /**
* This is the routine that actually computes the list of molecules returned by getMolecules(). Normally * This is the routine that actually computes the list of molecules returned by getMolecules(). Normally
* you should never call it. It is exposed here because the same logic is useful to other classes too. * you should never call it. It is exposed here because the same logic is useful to other classes too.
......
...@@ -65,6 +65,7 @@ public: ...@@ -65,6 +65,7 @@ public:
std::vector<std::string> getKernelNames(); std::vector<std::string> getKernelNames();
void updateParametersInContext(ContextImpl& context); void updateParametersInContext(ContextImpl& context);
void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const; void getPMEParameters(double& alpha, int& nx, int& ny, int& nz) const;
void getLJPMEParameters(double& alpha, int& nx, int& ny, int& nz) const;
/** /**
* This is a utility routine that calculates the values to use for alpha and kmax when using * This is a utility routine that calculates the values to use for alpha and kmax when using
* Ewald summation. * Ewald summation.
...@@ -74,7 +75,7 @@ public: ...@@ -74,7 +75,7 @@ public:
* This is a utility routine that calculates the values to use for alpha and grid size when using * This is a utility routine that calculates the values to use for alpha and grid size when using
* Particle Mesh Ewald. * Particle Mesh Ewald.
*/ */
static void calcPMEParameters(const System& system, const NonbondedForce& force, double& alpha, int& xsize, int& ysize, int& zsize); static void calcPMEParameters(const System& system, const NonbondedForce& force, double& alpha, int& xsize, int& ysize, int& zsize, bool lj);
/** /**
* 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 dispersion correction to the energy. * long range dispersion correction to the energy.
......
...@@ -158,4 +158,5 @@ void CMAPTorsionForceImpl::calcMapDerivatives(int size, const vector<double>& en ...@@ -158,4 +158,5 @@ void CMAPTorsionForceImpl::calcMapDerivatives(int size, const vector<double>& en
void CMAPTorsionForceImpl::updateParametersInContext(ContextImpl& context) { void CMAPTorsionForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcCMAPTorsionForceKernel>().copyParametersToContext(context, owner); kernel.getAs<CalcCMAPTorsionForceKernel>().copyParametersToContext(context, owner);
context.systemChanged();
} }
...@@ -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) 2015 Stanford University and the Authors. * * Portions copyright (c) 2015-2016 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -120,6 +120,11 @@ vector<string> CompoundIntegrator::getKernelNames() { ...@@ -120,6 +120,11 @@ vector<string> CompoundIntegrator::getKernelNames() {
return kernels; return kernels;
} }
void CompoundIntegrator::stateChanged(State::DataType changed) {
for (int i = 0; i < integrators.size(); i++)
integrators[i]->stateChanged(changed);
}
double CompoundIntegrator::computeKineticEnergy() { double CompoundIntegrator::computeKineticEnergy() {
return integrators[currentIntegrator]->computeKineticEnergy(); return integrators[currentIntegrator]->computeKineticEnergy();
} }
...@@ -56,12 +56,13 @@ const static char CHECKPOINT_MAGIC_BYTES[] = "OpenMM Binary Checkpoint\n"; ...@@ -56,12 +56,13 @@ const static char CHECKPOINT_MAGIC_BYTES[] = "OpenMM Binary Checkpoint\n";
ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integrator, Platform* platform, const map<string, string>& properties) : ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integrator, Platform* platform, const map<string, string>& properties) :
owner(owner), system(system), integrator(integrator), hasInitializedForces(false), hasSetPositions(false), integratorIsDeleted(false), owner(owner), system(system), integrator(integrator), hasInitializedForces(false), hasSetPositions(false), integratorIsDeleted(false),
lastForceGroups(-1), platform(platform), platformData(NULL) { lastForceGroups(-1), platform(platform), platformData(NULL) {
if (system.getNumParticles() == 0) int numParticles = system.getNumParticles();
if (numParticles == 0)
throw OpenMMException("Cannot create a Context for a System with no particles"); throw OpenMMException("Cannot create a Context for a System with no particles");
// Check for errors in virtual sites and massless particles. // Check for errors in virtual sites and massless particles.
for (int i = 0; i < system.getNumParticles(); i++) { for (int i = 0; i < numParticles; i++) {
if (system.isVirtualSite(i)) { if (system.isVirtualSite(i)) {
if (system.getParticleMass(i) != 0.0) if (system.getParticleMass(i) != 0.0)
throw OpenMMException("Virtual site has nonzero mass"); throw OpenMMException("Virtual site has nonzero mass");
...@@ -71,14 +72,23 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ ...@@ -71,14 +72,23 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
throw OpenMMException("A virtual site cannot depend on another virtual site"); throw OpenMMException("A virtual site cannot depend on another virtual site");
} }
} }
set<pair<int, int> > constraintAtoms;
for (int i = 0; i < system.getNumConstraints(); i++) { for (int i = 0; i < system.getNumConstraints(); i++) {
int particle1, particle2; int particle1, particle2;
double distance; double distance;
system.getConstraintParameters(i, particle1, particle2, distance); system.getConstraintParameters(i, particle1, particle2, distance);
if (particle1 == particle2)
throw OpenMMException("A constraint cannot connect a particle to itself");
if (particle1 < 0 || particle2 < 0 || particle1 >= numParticles || particle2 >= numParticles)
throw OpenMMException("Illegal particle index in constraint");
double mass1 = system.getParticleMass(particle1); double mass1 = system.getParticleMass(particle1);
double mass2 = system.getParticleMass(particle2); double mass2 = system.getParticleMass(particle2);
if ((mass1 == 0.0 && mass2 != 0.0) || (mass2 == 0.0 && mass1 != 0.0)) if ((mass1 == 0.0 && mass2 != 0.0) || (mass2 == 0.0 && mass1 != 0.0))
throw OpenMMException("A constraint cannot involve a massless particle"); throw OpenMMException("A constraint cannot involve a massless particle");
pair<int, int> atoms = make_pair(min(particle1, particle2), max(particle1, particle2));
if (constraintAtoms.find(atoms) != constraintAtoms.end())
throw OpenMMException("The System has two constraints between the same atoms. This will produce a singular constraint matrix.");
constraintAtoms.insert(atoms);
} }
// Validate the list of properties. // Validate the list of properties.
...@@ -170,7 +180,7 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ ...@@ -170,7 +180,7 @@ ContextImpl::ContextImpl(Context& owner, const System& system, Integrator& integ
for (size_t i = 0; i < forceImpls.size(); ++i) for (size_t i = 0; i < forceImpls.size(); ++i)
forceImpls[i]->initialize(*this); forceImpls[i]->initialize(*this);
integrator.initialize(*this); integrator.initialize(*this);
updateStateDataKernel.getAs<UpdateStateDataKernel>().setVelocities(*this, vector<Vec3>(system.getNumParticles())); updateStateDataKernel.getAs<UpdateStateDataKernel>().setVelocities(*this, vector<Vec3>(numParticles));
} }
ContextImpl::~ContextImpl() { ContextImpl::~ContextImpl() {
...@@ -259,10 +269,14 @@ void ContextImpl::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3 ...@@ -259,10 +269,14 @@ void ContextImpl::setPeriodicBoxVectors(const Vec3& a, const Vec3& b, const Vec3
} }
void ContextImpl::applyConstraints(double tol) { void ContextImpl::applyConstraints(double tol) {
if (!hasSetPositions)
throw OpenMMException("Particle positions have not been set");
applyConstraintsKernel.getAs<ApplyConstraintsKernel>().apply(*this, tol); applyConstraintsKernel.getAs<ApplyConstraintsKernel>().apply(*this, tol);
} }
void ContextImpl::applyVelocityConstraints(double tol) { void ContextImpl::applyVelocityConstraints(double tol) {
if (!hasSetPositions)
throw OpenMMException("Particle positions have not been set");
applyConstraintsKernel.getAs<ApplyConstraintsKernel>().applyToVelocities(*this, tol); applyConstraintsKernel.getAs<ApplyConstraintsKernel>().applyToVelocities(*this, tol);
} }
...@@ -460,3 +474,7 @@ void ContextImpl::loadCheckpoint(istream& stream) { ...@@ -460,3 +474,7 @@ void ContextImpl::loadCheckpoint(istream& stream) {
updateStateDataKernel.getAs<UpdateStateDataKernel>().loadCheckpoint(*this, stream); updateStateDataKernel.getAs<UpdateStateDataKernel>().loadCheckpoint(*this, stream);
hasSetPositions = true; hasSetPositions = true;
} }
void ContextImpl::systemChanged() {
integrator.stateChanged(State::Energy);
}
...@@ -108,4 +108,5 @@ map<string, double> CustomAngleForceImpl::getDefaultParameters() { ...@@ -108,4 +108,5 @@ map<string, double> CustomAngleForceImpl::getDefaultParameters() {
void CustomAngleForceImpl::updateParametersInContext(ContextImpl& context) { void CustomAngleForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcCustomAngleForceKernel>().copyParametersToContext(context, owner); kernel.getAs<CalcCustomAngleForceKernel>().copyParametersToContext(context, owner);
context.systemChanged();
} }
...@@ -113,4 +113,5 @@ vector<pair<int, int> > CustomBondForceImpl::getBondedParticles() const { ...@@ -113,4 +113,5 @@ vector<pair<int, int> > CustomBondForceImpl::getBondedParticles() const {
void CustomBondForceImpl::updateParametersInContext(ContextImpl& context) { void CustomBondForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcCustomBondForceKernel>().copyParametersToContext(context, owner); kernel.getAs<CalcCustomBondForceKernel>().copyParametersToContext(context, owner);
context.systemChanged();
} }
...@@ -246,6 +246,7 @@ void CustomCentroidBondForceImpl::addBondsBetweenGroups(int group1, int group2, ...@@ -246,6 +246,7 @@ void CustomCentroidBondForceImpl::addBondsBetweenGroups(int group1, int group2,
void CustomCentroidBondForceImpl::updateParametersInContext(ContextImpl& context) { void CustomCentroidBondForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcCustomCentroidBondForceKernel>().copyParametersToContext(context, owner); kernel.getAs<CalcCustomCentroidBondForceKernel>().copyParametersToContext(context, owner);
context.systemChanged();
} }
void CustomCentroidBondForceImpl::computeNormalizedWeights(const CustomCentroidBondForce& force, const System& system, vector<vector<double> >& weights) { void CustomCentroidBondForceImpl::computeNormalizedWeights(const CustomCentroidBondForce& force, const System& system, vector<vector<double> >& weights) {
......
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