"ssh:/git@developer.sourcefind.cn:2222/tsoc/openmm.git" did not exist on "dfba24ea66d4f8ee7e5abac7baca62c9acc031dc"
Commit 37457b25 authored by peastman's avatar peastman
Browse files

Merge branch 'master' of https://github.com/peastman/openmm

parents debe1662 24d0b3b3
language: c language: cpp
compiler:
- clang
install: before_install:
- source tools/ci/install.sh - sudo apt-get update -qq
- export PYTHONUNBUFFERED=true - sudo apt-get install -qq libpcre3 libpcre3-dev gromacs
- sudo apt-get install -qq swig doxygen llvm-3.3
- sudo apt-get install -qq python-numpy python-scipy python-pip
- sudo pip install nose
- export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.3
script: script:
- export CC="clang++" - cmake -DCMAKE_INSTALL_PREFIX=$HOME/OpenMM .
- source deactivate - make -j2
- conda install --yes conda-build - make -j2 install
- # Build the conda package, testing build before packaging. - sudo make PythonInstall
- conda build tools/conda-recipe - # run all of the tests
- # Install the conda package locally. - ctest -j2 -V
- source activate $python - # get a list of all of the failed tests into this stupid ctest format
- conda install $HOME/miniconda/conda-bld/linux-64/openmm-dev-* - python -c 'fn = "Testing/Temporary/LastTestsFailed.log"; import os; os.path.exists(fn) or exit(0); l = [line.split(":")[0] for line in open(fn)]; triplets = zip(l, l, [","]*len(l)); print "".join(",".join(t) for t in triplets)' > FailedTests.log
- conda list -e - # rerun all of the failed tests
- # Run the Python tests. - if [ -s FailedTests.log ]; then ctest -V -I FailedTests.log; fi;
- pushd . - # run the python tests too
- cd wrappers/python/tests - cd python/tests
- nosetests -vv --processes=-1 --process-timeout=200 - nosetests -vv --processes=-1 --process-timeout=200
- popd
env:
global:
# encrypted BINSTAR_TOKEN for push of dev package to binstar
- secure: Qz3pEYXXFnNQ/WK+15ad4cdbLJvzgCIZRwKD9fLiS3CDO2ldAQWxzaz8RQOwqbFtZUWu7lQpr+GukNJz5p0w18QEto+BxLYG9aW5mjoc+F2vCjyWFjkwnJ/Z/3uBKTcr5x9Y7HKaPGivaJ4BNACifjt7cCpeVJzV6u2+bBgSoHc=
matrix:
- python=2.7 CONDA_PY=27
#- python=3.3 CONDA_PY=33
after_success:
- echo "after_success"
- source tools/ci/after_success.sh
...@@ -157,6 +157,7 @@ public: ...@@ -157,6 +157,7 @@ public:
* of r, the distance between them, as well as any global and per-particle parameters * of r, the distance between them, as well as any global and per-particle parameters
*/ */
explicit CustomNonbondedForce(const std::string& energy); explicit CustomNonbondedForce(const std::string& energy);
CustomNonbondedForce(const CustomNonbondedForce& rhs); // copy constructor
~CustomNonbondedForce(); ~CustomNonbondedForce();
/** /**
* Get the number of particles for which force field parameters have been defined. * Get the number of particles for which force field parameters have been defined.
...@@ -466,6 +467,7 @@ public: ...@@ -466,6 +467,7 @@ public:
protected: protected:
ForceImpl* createImpl() const; ForceImpl* createImpl() const;
private: private:
// REMEMBER TO UPDATE THE COPY CONSTRUCTOR IF YOU ADD ANY NEW FIELDS !!
class ParticleInfo; class ParticleInfo;
class PerParticleParameterInfo; class PerParticleParameterInfo;
class GlobalParameterInfo; class GlobalParameterInfo;
......
...@@ -59,6 +59,7 @@ class OPENMM_EXPORT TabulatedFunction { ...@@ -59,6 +59,7 @@ class OPENMM_EXPORT TabulatedFunction {
public: public:
virtual ~TabulatedFunction() { virtual ~TabulatedFunction() {
} }
virtual TabulatedFunction* Copy() const = 0;
}; };
/** /**
...@@ -96,6 +97,10 @@ public: ...@@ -96,6 +97,10 @@ public:
* @param max the value of x corresponding to the last element of values * @param max the value of x corresponding to the last element of values
*/ */
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.
*/
Continuous1DFunction* Copy() const;
private: private:
std::vector<double> values; std::vector<double> values;
double min, max; double min, max;
...@@ -151,6 +156,10 @@ public: ...@@ -151,6 +156,10 @@ public:
* @param ymax the value of y corresponding to the last element of values * @param ymax the value of y corresponding to the last element of values
*/ */
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
*/
Continuous2DFunction* Copy() const;
private: private:
std::vector<double> values; std::vector<double> values;
int xsize, ysize; int xsize, ysize;
...@@ -222,6 +231,10 @@ public: ...@@ -222,6 +231,10 @@ public:
* @param zmax the value of z corresponding to the last element of values * @param zmax the value of z corresponding to the last element of values
*/ */
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
*/
Continuous3DFunction* Copy() const;
private: private:
std::vector<double> values; std::vector<double> values;
int xsize, ysize, zsize; int xsize, ysize, zsize;
...@@ -253,6 +266,10 @@ public: ...@@ -253,6 +266,10 @@ public:
* @param values the tabulated values of the function f(x) * @param values the tabulated values of the function f(x)
*/ */
void setFunctionParameters(const std::vector<double>& values); void setFunctionParameters(const std::vector<double>& values);
/**
* Create a deep copy of the tabulated function
*/
Discrete1DFunction* Copy() const;
private: private:
std::vector<double> values; std::vector<double> values;
}; };
...@@ -291,6 +308,10 @@ public: ...@@ -291,6 +308,10 @@ public:
* values[i+xsize*j] = f(i,j). This must be of length xsize*ysize. * values[i+xsize*j] = f(i,j). This must be of length xsize*ysize.
*/ */
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
*/
Discrete2DFunction* Copy() const;
private: private:
int xsize, ysize; int xsize, ysize;
std::vector<double> values; std::vector<double> values;
...@@ -333,6 +354,10 @@ public: ...@@ -333,6 +354,10 @@ public:
* values[i+xsize*j+xsize*ysize*k] = f(i,j,k). This must be of length xsize*ysize*zsize. * values[i+xsize*j+xsize*ysize*k] = f(i,j,k). This must be of length xsize*ysize*zsize.
*/ */
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
*/
Discrete3DFunction* Copy() const;
private: private:
int xsize, ysize, zsize; int xsize, ysize, zsize;
std::vector<double> values; std::vector<double> values;
......
...@@ -51,6 +51,23 @@ CustomNonbondedForce::CustomNonbondedForce(const string& energy) : energyExpress ...@@ -51,6 +51,23 @@ CustomNonbondedForce::CustomNonbondedForce(const string& energy) : energyExpress
switchingDistance(-1.0), useSwitchingFunction(false), useLongRangeCorrection(false) { switchingDistance(-1.0), useSwitchingFunction(false), useLongRangeCorrection(false) {
} }
CustomNonbondedForce::CustomNonbondedForce(const CustomNonbondedForce& rhs) {
// Copy everything and deep copy the tabulated functions
energyExpression = rhs.energyExpression;
nonbondedMethod = rhs.nonbondedMethod;
cutoffDistance = rhs.cutoffDistance;
switchingDistance = rhs.switchingDistance;
useSwitchingFunction = rhs.useSwitchingFunction;
useLongRangeCorrection = rhs.useLongRangeCorrection;
parameters = rhs.parameters;
globalParameters = rhs.globalParameters;
particles = rhs.particles;
exclusions = rhs.exclusions;
interactionGroups = rhs.interactionGroups;
for (vector<FunctionInfo>::const_iterator it = rhs.functions.begin(); it != rhs.functions.end(); it++)
functions.push_back(FunctionInfo(it->name, it->function->Copy()));
}
CustomNonbondedForce::~CustomNonbondedForce() { CustomNonbondedForce::~CustomNonbondedForce() {
for (int i = 0; i < (int) functions.size(); i++) for (int i = 0; i < (int) functions.size(); i++)
delete functions[i].function; delete functions[i].function;
......
...@@ -61,6 +61,13 @@ void Continuous1DFunction::setFunctionParameters(const vector<double>& values, d ...@@ -61,6 +61,13 @@ void Continuous1DFunction::setFunctionParameters(const vector<double>& values, d
this->max = max; this->max = max;
} }
Continuous1DFunction* Continuous1DFunction::Copy() const {
vector<double> new_vec(values.size());
for (size_t i = 0; i < values.size(); i++)
new_vec[i] = values[i];
return new Continuous1DFunction(new_vec, min, max);
}
Continuous2DFunction::Continuous2DFunction(int xsize, int ysize, const vector<double>& values, double xmin, double xmax, double ymin, double ymax) { Continuous2DFunction::Continuous2DFunction(int xsize, int ysize, const vector<double>& values, double xmin, double xmax, double ymin, double ymax) {
if (xsize < 2 || ysize < 2) if (xsize < 2 || ysize < 2)
throw OpenMMException("Continuous2DFunction: must have at least two points along each axis"); throw OpenMMException("Continuous2DFunction: must have at least two points along each axis");
...@@ -107,6 +114,13 @@ void Continuous2DFunction::setFunctionParameters(int xsize, int ysize, const vec ...@@ -107,6 +114,13 @@ void Continuous2DFunction::setFunctionParameters(int xsize, int ysize, const vec
this->ymax = ymax; this->ymax = ymax;
} }
Continuous2DFunction* Continuous2DFunction::Copy() const {
vector<double> new_vec(values.size());
for (size_t i = 0; i < values.size(); i++)
new_vec[i] = values[i];
return new Continuous2DFunction(xsize, ysize, new_vec, xmin, xmax, ymin, ymax);
}
Continuous3DFunction::Continuous3DFunction(int xsize, int ysize, int zsize, const vector<double>& values, double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { Continuous3DFunction::Continuous3DFunction(int xsize, int ysize, int zsize, const vector<double>& values, double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) {
if (xsize < 2 || ysize < 2 || zsize < 2) if (xsize < 2 || ysize < 2 || zsize < 2)
throw OpenMMException("Continuous3DFunction: must have at least two points along each axis"); throw OpenMMException("Continuous3DFunction: must have at least two points along each axis");
...@@ -166,6 +180,14 @@ void Continuous3DFunction::setFunctionParameters(int xsize, int ysize, int zsize ...@@ -166,6 +180,14 @@ void Continuous3DFunction::setFunctionParameters(int xsize, int ysize, int zsize
this->zmax = zmax; this->zmax = zmax;
} }
Continuous3DFunction* Continuous3DFunction::Copy() const {
vector<double> new_vec(values.size());
for (size_t i = 0; i < values.size(); i++)
new_vec[i] = values[i];
return new Continuous3DFunction(xsize, ysize, zsize, new_vec, xmin, xmax, ymin, ymax, zmin, zmax);
}
Discrete1DFunction::Discrete1DFunction(const vector<double>& values) { Discrete1DFunction::Discrete1DFunction(const vector<double>& values) {
this->values = values; this->values = values;
} }
...@@ -178,6 +200,13 @@ void Discrete1DFunction::setFunctionParameters(const vector<double>& values) { ...@@ -178,6 +200,13 @@ void Discrete1DFunction::setFunctionParameters(const vector<double>& values) {
this->values = values; this->values = values;
} }
Discrete1DFunction* Discrete1DFunction::Copy() const {
vector<double> new_vec(values.size());
for (size_t i = 0; i < values.size(); i++)
new_vec[i] = values[i];
return new Discrete1DFunction(new_vec);
}
Discrete2DFunction::Discrete2DFunction(int xsize, int ysize, const vector<double>& values) { Discrete2DFunction::Discrete2DFunction(int xsize, int ysize, const vector<double>& values) {
if (values.size() != xsize*ysize) if (values.size() != xsize*ysize)
throw OpenMMException("Discrete2DFunction: incorrect number of values"); throw OpenMMException("Discrete2DFunction: incorrect number of values");
...@@ -200,6 +229,13 @@ void Discrete2DFunction::setFunctionParameters(int xsize, int ysize, const vecto ...@@ -200,6 +229,13 @@ void Discrete2DFunction::setFunctionParameters(int xsize, int ysize, const vecto
this->values = values; this->values = values;
} }
Discrete2DFunction* Discrete2DFunction::Copy() const {
vector<double> new_vec(values.size());
for (size_t i = 0; i < values.size(); i++)
new_vec[i] = values[i];
return new Discrete2DFunction(xsize, ysize, new_vec);
}
Discrete3DFunction::Discrete3DFunction(int xsize, int ysize, int zsize, const vector<double>& values) { Discrete3DFunction::Discrete3DFunction(int xsize, int ysize, int zsize, const vector<double>& values) {
if (values.size() != xsize*ysize*zsize) if (values.size() != xsize*ysize*zsize)
throw OpenMMException("Discrete3DFunction: incorrect number of values"); throw OpenMMException("Discrete3DFunction: incorrect number of values");
...@@ -224,3 +260,10 @@ void Discrete3DFunction::setFunctionParameters(int xsize, int ysize, int zsize, ...@@ -224,3 +260,10 @@ void Discrete3DFunction::setFunctionParameters(int xsize, int ysize, int zsize,
this->zsize = zsize; this->zsize = zsize;
this->values = values; this->values = values;
} }
Discrete3DFunction* Discrete3DFunction::Copy() const {
vector<double> new_vec(values.size());
for (size_t i = 0; i < values.size(); i++)
new_vec[i] = values[i];
return new Discrete3DFunction(xsize, ysize, zsize, new_vec);
}
...@@ -55,6 +55,7 @@ foreach(SUBDIR ${SUBDIRS}) ...@@ -55,6 +55,7 @@ foreach(SUBDIR ${SUBDIRS})
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xml" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xml"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pdb" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.pdb"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.prmtop" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.prmtop"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.inpcrd"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.parm7" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.parm7"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.rst7" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.rst7"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.ncrst" "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.ncrst"
......
...@@ -100,7 +100,7 @@ class ForceField(object): ...@@ -100,7 +100,7 @@ class ForceField(object):
"""Load one or more XML files and create a ForceField object based on them. """Load one or more XML files and create a ForceField object based on them.
Parameters: Parameters:
- files A list of XML files defining the force field. Each entry may - files (list) A list of XML files defining the force field. Each entry may
be an absolute file path, a path relative to the current working be an absolute file path, a path relative to the current working
directory, a path relative to this module's data subdirectory directory, a path relative to this module's data subdirectory
(for built in force fields), or an open file-like object with a (for built in force fields), or an open file-like object with a
...@@ -113,47 +113,59 @@ class ForceField(object): ...@@ -113,47 +113,59 @@ class ForceField(object):
self._forces = [] self._forces = []
self._scripts = [] self._scripts = []
for file in files: for file in files:
try: self.loadFile(file)
# this handles either filenames or open file-like objects
tree = etree.parse(file) def loadFile(self, file):
except IOError: """Load an XML file and add the definitions from it to this FieldField.
tree = etree.parse(os.path.join(os.path.dirname(__file__), 'data', file))
root = tree.getroot() Parameters:
- file (string or file) An XML file containing force field definitions. It may
# Load the atom types. be either an absolute file path, a path relative to the current working
directory, a path relative to this module's data subdirectory
if tree.getroot().find('AtomTypes') is not None: (for built in force fields), or an open file-like object with a
for type in tree.getroot().find('AtomTypes').findall('Type'): read() method from which the forcefield XML data can be loaded.
self.registerAtomType(type.attrib) """
try:
# Load the residue templates. # this handles either filenames or open file-like objects
tree = etree.parse(file)
if tree.getroot().find('Residues') is not None: except IOError:
for residue in root.find('Residues').findall('Residue'): tree = etree.parse(os.path.join(os.path.dirname(__file__), 'data', file))
resName = residue.attrib['name'] root = tree.getroot()
template = ForceField._TemplateData(resName)
for atom in residue.findall('Atom'): # Load the atom types.
template.atoms.append(ForceField._TemplateAtomData(atom.attrib['name'], atom.attrib['type'], self._atomTypes[atom.attrib['type']][2]))
for site in residue.findall('VirtualSite'): if tree.getroot().find('AtomTypes') is not None:
template.virtualSites.append(ForceField._VirtualSiteData(site)) for type in tree.getroot().find('AtomTypes').findall('Type'):
for bond in residue.findall('Bond'): self.registerAtomType(type.attrib)
template.addBond(int(bond.attrib['from']), int(bond.attrib['to']))
for bond in residue.findall('ExternalBond'): # Load the residue templates.
b = int(bond.attrib['from'])
template.externalBonds.append(b) if tree.getroot().find('Residues') is not None:
template.atoms[b].externalBonds += 1 for residue in root.find('Residues').findall('Residue'):
self.registerResidueTemplate(template) resName = residue.attrib['name']
template = ForceField._TemplateData(resName)
# Load force definitions for atom in residue.findall('Atom'):
template.atoms.append(ForceField._TemplateAtomData(atom.attrib['name'], atom.attrib['type'], self._atomTypes[atom.attrib['type']][2]))
for child in root: for site in residue.findall('VirtualSite'):
if child.tag in parsers: template.virtualSites.append(ForceField._VirtualSiteData(site))
parsers[child.tag](child, self) for bond in residue.findall('Bond'):
template.addBond(int(bond.attrib['from']), int(bond.attrib['to']))
# Load scripts for bond in residue.findall('ExternalBond'):
b = int(bond.attrib['from'])
for node in tree.getroot().findall('Script'): template.externalBonds.append(b)
self.registerScript(node.text) template.atoms[b].externalBonds += 1
self.registerResidueTemplate(template)
# Load force definitions
for child in root:
if child.tag in parsers:
parsers[child.tag](child, self)
# Load scripts
for node in tree.getroot().findall('Script'):
self.registerScript(node.text)
def getGenerators(self): def getGenerators(self):
"""Get the list of all registered generators.""" """Get the list of all registered generators."""
......
...@@ -52,6 +52,7 @@ except: ...@@ -52,6 +52,7 @@ except:
import simtk.unit as units import simtk.unit as units
import simtk.openmm import simtk.openmm
from simtk.openmm.app import element as elem from simtk.openmm.app import element as elem
from simtk.openmm.vec3 import Vec3
import customgbforces as customgb import customgbforces as customgb
#============================================================================================= #=============================================================================================
...@@ -116,6 +117,7 @@ class PrmtopLoader(object): ...@@ -116,6 +117,7 @@ class PrmtopLoader(object):
self._flags=[] self._flags=[]
self._raw_format={} self._raw_format={}
self._raw_data={} self._raw_data={}
self._has_nbfix_terms = False
fIn=open(inFilename) fIn=open(inFilename)
for line in fIn: for line in fIn:
...@@ -218,28 +220,16 @@ class PrmtopLoader(object): ...@@ -218,28 +220,16 @@ class PrmtopLoader(object):
try: try:
return self._massList return self._massList
except AttributeError: except AttributeError:
pass self._massList = [float(x) for x in self._raw_data['MASS']]
return self._massList
self._massList=[]
raw_masses=self._raw_data['MASS']
for ii in range(self.getNumAtoms()):
self._massList.append(float(raw_masses[ii]))
self._massList = self._massList
return self._massList
def getCharges(self): def getCharges(self):
"""Return a list of atomic charges in the system""" """Return a list of atomic charges in the system"""
try: try:
return self._chargeList return self._chargeList
except AttributeError: except AttributeError:
pass self._chargeList = [float(x)/18.2223 for x in self._raw_data['CHARGE']]
return self._chargeList
self._chargeList=[]
raw_charges=self._raw_data['CHARGE']
for ii in range(self.getNumAtoms()):
self._chargeList.append(float(raw_charges[ii])/18.2223)
self._chargeList = self._chargeList
return self._chargeList
def getAtomName(self, iAtom): def getAtomName(self, iAtom):
"""Return the atom name for iAtom""" """Return the atom name for iAtom"""
...@@ -254,11 +244,8 @@ class PrmtopLoader(object): ...@@ -254,11 +244,8 @@ class PrmtopLoader(object):
try: try:
return self._atomTypeIndexes return self._atomTypeIndexes
except AttributeError: except AttributeError:
pass self._atomTypeIndexes = [int(x) for x in self._raw_data['ATOM_TYPE_INDEX']]
self._atomTypeIndexes=[] return self._atomTypeIndexes
for atomTypeIndex in self._raw_data['ATOM_TYPE_INDEX']:
self._atomTypeIndexes.append(int(atomTypeIndex))
return self._atomTypeIndexes
def getAtomType(self, iAtom): def getAtomType(self, iAtom):
"""Return the AMBER atom type for iAtom""" """Return the AMBER atom type for iAtom"""
...@@ -275,11 +262,11 @@ class PrmtopLoader(object): ...@@ -275,11 +262,11 @@ class PrmtopLoader(object):
def getResidueLabel(self, iAtom=None, iRes=None): def getResidueLabel(self, iAtom=None, iRes=None):
"""Return residue label for iAtom OR iRes""" """Return residue label for iAtom OR iRes"""
if iRes==None and iAtom==None: if iRes is None and iAtom is None:
raise Exception("only specify iRes or iAtom, not both") raise Exception("only specify iRes or iAtom, not both")
if iRes!=None and iAtom!=None: if iRes is not None and iAtom is not None:
raise Exception("iRes or iAtom must be set") raise Exception("iRes or iAtom must be set")
if iRes!=None: if iRes is not None:
return self._raw_data['RESIDUE_LABEL'][iRes] return self._raw_data['RESIDUE_LABEL'][iRes]
else: else:
return self.getResidueLabel(iRes=self._getResiduePointer(iAtom)) return self.getResidueLabel(iRes=self._getResiduePointer(iAtom))
...@@ -306,6 +293,9 @@ class PrmtopLoader(object): ...@@ -306,6 +293,9 @@ class PrmtopLoader(object):
elements of the Lennard-Jones A and B coefficient matrices are found, elements of the Lennard-Jones A and B coefficient matrices are found,
NbfixPresent exception is raised NbfixPresent exception is raised
""" """
if self._has_nbfix_terms:
raise NbfixPresent('Off-diagonal Lennard-Jones elements found. '
'Cannot determine LJ parameters for individual atoms.')
try: try:
return self._nonbondTerms return self._nonbondTerms
except AttributeError: except AttributeError:
...@@ -344,13 +334,13 @@ class PrmtopLoader(object): ...@@ -344,13 +334,13 @@ class PrmtopLoader(object):
b = float(self._raw_data['LENNARD_JONES_BCOEF'][index]) b = float(self._raw_data['LENNARD_JONES_BCOEF'][index])
if a == 0 or b == 0: if a == 0 or b == 0:
if a != 0 or b != 0 or (wdij != 0 and rij != 0): if a != 0 or b != 0 or (wdij != 0 and rij != 0):
del self._nonbondTerms self._has_nbfix_terms = True
raise NbfixPresent('Off-diagonal Lennard-Jones elements' raise NbfixPresent('Off-diagonal Lennard-Jones elements'
' found. Cannot determine LJ ' ' found. Cannot determine LJ '
'parameters for individual atoms.') 'parameters for individual atoms.')
elif (abs((a - (wdij * rij ** 12)) / a) > 1e-6 or elif (abs((a - (wdij * rij ** 12)) / a) > 1e-6 or
abs((b - (2 * wdij * rij**6)) / b) > 1e-6): abs((b - (2 * wdij * rij**6)) / b) > 1e-6):
del self._nonbondTerms self._has_nbfix_terms = True
raise NbfixPresent('Off-diagonal Lennard-Jones elements ' raise NbfixPresent('Off-diagonal Lennard-Jones elements '
'found. Cannot determine LJ parameters ' 'found. Cannot determine LJ parameters '
'for individual atoms.') 'for individual atoms.')
...@@ -712,6 +702,10 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -712,6 +702,10 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
warnings.warn("1-4 scaling parameters in topology file are being ignored. " warnings.warn("1-4 scaling parameters in topology file are being ignored. "
"This is not recommended unless you know what you are doing.") "This is not recommended unless you know what you are doing.")
has_1264 = 'LENNARD_JONES_CCOEF' in prmtop._raw_data.keys()
if has_1264:
parm_ccoef = [float(x) for x in prmtop._raw_data['LENNARD_JONES_CCOEF']]
# Use pyopenmm implementation of OpenMM by default. # Use pyopenmm implementation of OpenMM by default.
if mm is None: if mm is None:
mm = simtk.openmm mm = simtk.openmm
...@@ -875,32 +869,52 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -875,32 +869,52 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
idx = nbidx[numTypes*i+j] - 1 idx = nbidx[numTypes*i+j] - 1
acoef[i+numTypes*j] = sqrt(parm_acoef[idx]) * afac acoef[i+numTypes*j] = sqrt(parm_acoef[idx]) * afac
bcoef[i+numTypes*j] = parm_bcoef[idx] * bfac bcoef[i+numTypes*j] = parm_bcoef[idx] * bfac
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6; r6=r^6;' if has_1264:
'a=acoef(type1, type2);' cfac = ene_conv * length_conv**4
'b=bcoef(type1, type2);') ccoef = [0 for i in range(numTypes*numTypes)]
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
ccoef[i+numTypes*j] = parm_ccoef[idx] * cfac
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6-c/r^4; r6=r^6;'
'a=acoef(type1, type2);'
'b=bcoef(type1, type2);'
'c=ccoef(type1, type2);')
else:
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6; r6=r^6;'
'a=acoef(type1, type2);'
'b=bcoef(type1, type2);')
cforce.addTabulatedFunction('acoef', cforce.addTabulatedFunction('acoef',
mm.Discrete2DFunction(numTypes, numTypes, acoef)) mm.Discrete2DFunction(numTypes, numTypes, acoef))
cforce.addTabulatedFunction('bcoef', cforce.addTabulatedFunction('bcoef',
mm.Discrete2DFunction(numTypes, numTypes, bcoef)) mm.Discrete2DFunction(numTypes, numTypes, bcoef))
if has_1264:
cforce.addTabulatedFunction('ccoef',
mm.Discrete2DFunction(numTypes, numTypes, ccoef))
cforce.addPerParticleParameter('type') cforce.addPerParticleParameter('type')
for atom in prmtop._getAtomTypeIndexes(): for atom in prmtop._getAtomTypeIndexes():
cforce.addParticle((atom-1,)) cforce.addParticle((atom-1,))
# Now set the various properties based on the NonbondedForce object
if nonbondedMethod in ('PME', 'Ewald', 'CutoffPeriodic'):
cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
cforce.setUseLongRangeCorrection(True)
elif nonbondedMethod == 'CutoffNonPeriodic':
cforce.setNonbondedMethod(cforce.CutoffNonPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
elif nonbondedMethod == 'NoCutoff':
cforce.setNonbondedMethod(cforce.NoCutoff)
else:
raise ValueError('Unrecognized cutoff option %s' % nonbondedMethod)
else: else:
for (charge, (rVdw, epsilon)) in zip(prmtop.getCharges(), nonbondTerms): for (charge, (rVdw, epsilon)) in zip(prmtop.getCharges(), nonbondTerms):
sigma = rVdw * sigmaScale sigma = rVdw * sigmaScale
force.addParticle(charge, sigma, epsilon) force.addParticle(charge, sigma, epsilon)
if has_1264:
numTypes = prmtop.getNumTypes()
nbidx = [int(x) for x in prmtop._raw_data['NONBONDED_PARM_INDEX']]
ccoef = [0 for i in range(numTypes*numTypes)]
ene_conv = units.kilocalories_per_mole.conversion_factor_to(units.kilojoules_per_mole)
length_conv = units.angstroms.conversion_factor_to(units.nanometers)
cfac = ene_conv * length_conv**4
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
ccoef[i+numTypes*j] = parm_ccoef[idx] * cfac
cforce = mm.CustomNonbondedForce('-c/r^4; c=ccoef(type1, type2)')
cforce.addTabulatedFunction('ccoef',
mm.Discrete2DFunction(numTypes, numTypes, ccoef))
cforce.addPerParticleParameter('type')
for atom in prmtop._getAtomTypeIndexes():
cforce.addParticle((atom-1,))
# Add 1-4 Interactions # Add 1-4 Interactions
...@@ -926,10 +940,23 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode ...@@ -926,10 +940,23 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
# Copy the exceptions as exclusions to the CustomNonbondedForce if we have # Copy the exceptions as exclusions to the CustomNonbondedForce if we have
# NBFIX terms # NBFIX terms
if nbfix: if nbfix or has_1264:
for i in range(force.getNumExceptions()): for i in range(force.getNumExceptions()):
ii, jj, chg, sig, eps = force.getExceptionParameters(i) ii, jj, chg, sig, eps = force.getExceptionParameters(i)
cforce.addExclusion(ii, jj) cforce.addExclusion(ii, jj)
# Now set the various properties based on the NonbondedForce object
if nonbondedMethod in ('PME', 'Ewald', 'CutoffPeriodic'):
cforce.setNonbondedMethod(cforce.CutoffPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
cforce.setUseLongRangeCorrection(True)
elif nonbondedMethod == 'CutoffNonPeriodic':
cforce.setNonbondedMethod(cforce.CutoffNonPeriodic)
cforce.setCutoffDistance(nonbondedCutoff)
elif nonbondedMethod == 'NoCutoff':
cforce.setNonbondedMethod(cforce.NoCutoff)
else:
raise ValueError('Unrecognized cutoff option %s' % nonbondedMethod)
# Add this force to the system
system.addForce(cforce) system.addForce(cforce)
system.addForce(force) system.addForce(force)
...@@ -1191,9 +1218,9 @@ class AmberAsciiRestart(object): ...@@ -1191,9 +1218,9 @@ class AmberAsciiRestart(object):
if hasbox: if hasbox:
boxVectors = np.zeros((3, 3), np.float32) boxVectors = np.zeros((3, 3), np.float32)
else: else:
coordinates = [[0.0, 0.0, 0.0] for i in range(self.natom)] coordinates = [Vec3(0.0, 0.0, 0.0) for i in range(self.natom)]
if hasvels: if hasvels:
velocities = [[0.0, 0.0, 0.0] for i in range(self.natom)] velocities = [Vec3(0.0, 0.0, 0.0) for i in range(self.natom)]
if hasbox: if hasbox:
boxVectors = [[0.0, 0.0, 0.0] for i in range(3)] boxVectors = [[0.0, 0.0, 0.0] for i in range(3)]
...@@ -1203,14 +1230,16 @@ class AmberAsciiRestart(object): ...@@ -1203,14 +1230,16 @@ class AmberAsciiRestart(object):
idx = 0 idx = 0
for i in range(startline, endline): for i in range(startline, endline):
line = lines[i] line = lines[i]
coordinates[idx][0] = float(line[ 0:12]) x = float(line[ 0:12])
coordinates[idx][1] = float(line[12:24]) y = float(line[12:24])
coordinates[idx][2] = float(line[24:36]) z = float(line[24:36])
coordinates[idx] = Vec3(x, y, z)
idx += 1 idx += 1
if idx < self.natom: if idx < self.natom:
coordinates[idx][0] = float(line[36:48]) x = float(line[36:48])
coordinates[idx][1] = float(line[48:60]) y = float(line[48:60])
coordinates[idx][2] = float(line[60:72]) z = float(line[60:72])
coordinates[idx] = Vec3(x, y, z)
idx += 1 idx += 1
self.coordinates = units.Quantity(coordinates, units.angstroms) self.coordinates = units.Quantity(coordinates, units.angstroms)
startline = endline startline = endline
...@@ -1220,14 +1249,16 @@ class AmberAsciiRestart(object): ...@@ -1220,14 +1249,16 @@ class AmberAsciiRestart(object):
idx = 0 idx = 0
for i in range(startline, endline): for i in range(startline, endline):
line = lines[i] line = lines[i]
velocities[idx][0] = float(line[ 0:12]) * VELSCALE x = float(line[ 0:12]) * VELSCALE
velocities[idx][1] = float(line[12:24]) * VELSCALE y = float(line[12:24]) * VELSCALE
velocities[idx][2] = float(line[24:36]) * VELSCALE z = float(line[24:36]) * VELSCALE
velocities[idx] = Vec3(x, y, z)
idx += 1 idx += 1
if idx < self.natom: if idx < self.natom:
velocities[idx][0] = float(line[36:48]) * VELSCALE x = float(line[36:48]) * VELSCALE
velocities[idx][1] = float(line[48:60]) * VELSCALE y = float(line[48:60]) * VELSCALE
velocities[idx][2] = float(line[60:72]) * VELSCALE z = float(line[60:72]) * VELSCALE
velocities[idx] = Vec3(x, y, z)
idx += 1 idx += 1
startline = endline startline = endline
self.velocities = units.Quantity(velocities, self.velocities = units.Quantity(velocities,
...@@ -1242,7 +1273,7 @@ class AmberAsciiRestart(object): ...@@ -1242,7 +1273,7 @@ class AmberAsciiRestart(object):
lengths = tmp[:3] lengths = tmp[:3]
angles = tmp[3:] angles = tmp[3:]
_box_vectors_from_lengths_angles(lengths, angles, boxVectors) _box_vectors_from_lengths_angles(lengths, angles, boxVectors)
self.boxVectors = units.Quantity(boxVectors, units.angstroms) self.boxVectors = [units.Quantity(Vec3(*x), units.angstrom) for x in boxVectors]
class AmberNetcdfRestart(object): class AmberNetcdfRestart(object):
""" """
...@@ -1325,11 +1356,11 @@ class AmberNetcdfRestart(object): ...@@ -1325,11 +1356,11 @@ class AmberNetcdfRestart(object):
# They are already numpy -- convert to list if we don't want numpy # They are already numpy -- convert to list if we don't want numpy
if not asNumpy: if not asNumpy:
self.coordinates = self.coordinates.tolist() self.coordinates = [Vec3(*x) for x in self.coordinates]
if self.velocities is not None: if self.velocities is not None:
self.velocities = self.velocities.tolist() self.velocities = [Vec3(*x) for x in self.velocities]
if self.boxVectors is not None: if self.boxVectors is not None:
self.boxVectors = self.boxVectors.tolist() self.boxVectors = [Vec3(*x) for x in self.boxVectors]
# Now add the units # Now add the units
self.coordinates = units.Quantity(self.coordinates, units.angstroms) self.coordinates = units.Quantity(self.coordinates, units.angstroms)
...@@ -1337,7 +1368,7 @@ class AmberNetcdfRestart(object): ...@@ -1337,7 +1368,7 @@ class AmberNetcdfRestart(object):
self.velocities = units.Quantity(self.velocities, self.velocities = units.Quantity(self.velocities,
units.angstroms/units.picoseconds) units.angstroms/units.picoseconds)
if self.boxVectors is not None: if self.boxVectors is not None:
self.boxVectors = units.Quantity(self.boxVectors, units.angstroms) self.boxVectors = [units.Quantity(x, units.angstroms) for x in self.boxVectors]
self.time = units.Quantity(self.time, units.picosecond) self.time = units.Quantity(self.time, units.picosecond)
def _box_vectors_from_lengths_angles(lengths, angles, boxVectors): def _box_vectors_from_lengths_angles(lengths, angles, boxVectors):
...@@ -1427,6 +1458,7 @@ def readAmberCoordinates(filename, asNumpy=False): ...@@ -1427,6 +1458,7 @@ def readAmberCoordinates(filename, asNumpy=False):
try: try:
crdfile = AmberAsciiRestart(filename) crdfile = AmberAsciiRestart(filename)
except TypeError: except TypeError:
raise
raise TypeError('Problem parsing %s as an ASCII Amber restart file' raise TypeError('Problem parsing %s as an ASCII Amber restart file'
% filename) % filename)
except (IndexError, ValueError): except (IndexError, ValueError):
......
...@@ -8,7 +8,9 @@ import simtk.openmm.app.element as elem ...@@ -8,7 +8,9 @@ import simtk.openmm.app.element as elem
prmtop1 = AmberPrmtopFile('systems/alanine-dipeptide-explicit.prmtop') prmtop1 = AmberPrmtopFile('systems/alanine-dipeptide-explicit.prmtop')
prmtop2 = AmberPrmtopFile('systems/alanine-dipeptide-implicit.prmtop') prmtop2 = AmberPrmtopFile('systems/alanine-dipeptide-implicit.prmtop')
prmtop3 = AmberPrmtopFile('systems/ff14ipq.parm7') prmtop3 = AmberPrmtopFile('systems/ff14ipq.parm7')
prmtop4 = AmberPrmtopFile('systems/Mg_water.prmtop')
inpcrd3 = AmberInpcrdFile('systems/ff14ipq.rst7') inpcrd3 = AmberInpcrdFile('systems/ff14ipq.rst7')
inpcrd4 = AmberInpcrdFile('systems/Mg_water.inpcrd')
class TestAmberPrmtopFile(unittest.TestCase): class TestAmberPrmtopFile(unittest.TestCase):
...@@ -145,35 +147,35 @@ class TestAmberPrmtopFile(unittest.TestCase): ...@@ -145,35 +147,35 @@ class TestAmberPrmtopFile(unittest.TestCase):
totalMass2 = sum([system2.getParticleMass(i) for i in range(system2.getNumParticles())]).value_in_unit(amu) totalMass2 = sum([system2.getParticleMass(i) for i in range(system2.getNumParticles())]).value_in_unit(amu)
self.assertAlmostEqual(totalMass1, totalMass2) self.assertAlmostEqual(totalMass1, totalMass2)
# def test_NBFIX_LongRange(self): def test_NBFIX_LongRange(self):
# """Test prmtop files with NBFIX LJ modifications w/ long-range correction""" """Test prmtop files with NBFIX LJ modifications w/ long-range correction"""
# system = prmtop3.createSystem(nonbondedMethod=PME, system = prmtop3.createSystem(nonbondedMethod=PME,
# nonbondedCutoff=8*angstroms) nonbondedCutoff=8*angstroms)
# # Check the forces # Check the forces
# has_nonbond_force = has_custom_nonbond_force = False has_nonbond_force = has_custom_nonbond_force = False
# nonbond_exceptions = custom_nonbond_exclusions = 0 nonbond_exceptions = custom_nonbond_exclusions = 0
# for force in system.getForces(): for force in system.getForces():
# if isinstance(force, NonbondedForce): if isinstance(force, NonbondedForce):
# has_nonbond_force = True has_nonbond_force = True
# nonbond_exceptions = force.getNumExceptions() nonbond_exceptions = force.getNumExceptions()
# elif isinstance(force, CustomNonbondedForce): elif isinstance(force, CustomNonbondedForce):
# has_custom_nonbond_force = True has_custom_nonbond_force = True
# custom_nonbond_exceptions = force.getNumExclusions() custom_nonbond_exceptions = force.getNumExclusions()
# self.assertTrue(has_nonbond_force) self.assertTrue(has_nonbond_force)
# self.assertTrue(has_custom_nonbond_force) self.assertTrue(has_custom_nonbond_force)
# self.assertEqual(nonbond_exceptions, custom_nonbond_exceptions) self.assertEqual(nonbond_exceptions, custom_nonbond_exceptions)
# integrator = VerletIntegrator(1.0*femtoseconds) integrator = VerletIntegrator(1.0*femtoseconds)
# # Use reference platform, since it should always be present and # Use reference platform, since it should always be present and
# # 'working', and the system is plenty small so this won't be too slow # 'working', and the system is plenty small so this won't be too slow
# sim = Simulation(prmtop3.topology, system, integrator, Platform.getPlatformByName('Reference')) sim = Simulation(prmtop3.topology, system, integrator, Platform.getPlatformByName('Reference'))
# # Check that the energy is about what we expect it to be # Check that the energy is about what we expect it to be
# sim.context.setPeriodicBoxVectors(*inpcrd3.boxVectors) sim.context.setPeriodicBoxVectors(*inpcrd3.boxVectors)
# sim.context.setPositions(inpcrd3.positions) sim.context.setPositions(inpcrd3.positions)
# ene = sim.context.getState(getEnergy=True, enforcePeriodicBox=True).getPotentialEnergy() ene = sim.context.getState(getEnergy=True, enforcePeriodicBox=True).getPotentialEnergy()
# ene = ene.value_in_unit(kilocalories_per_mole) ene = ene.value_in_unit(kilocalories_per_mole)
# # Make sure the energy is relatively close to the value we get with # Make sure the energy is relatively close to the value we get with
# # Amber using this force field. # Amber using this force field.
# self.assertAlmostEqual(-7099.44989739/ene, 1, places=3) self.assertAlmostEqual(-7099.44989739/ene, 1, places=3)
def test_NBFIX_noLongRange(self): def test_NBFIX_noLongRange(self):
"""Test prmtop files with NBFIX LJ modifications w/out long-range correction""" """Test prmtop files with NBFIX LJ modifications w/out long-range correction"""
...@@ -198,13 +200,46 @@ class TestAmberPrmtopFile(unittest.TestCase): ...@@ -198,13 +200,46 @@ class TestAmberPrmtopFile(unittest.TestCase):
# 'working', and the system is plenty small so this won't be too slow # 'working', and the system is plenty small so this won't be too slow
sim = Simulation(prmtop3.topology, system, integrator, Platform.getPlatformByName('Reference')) sim = Simulation(prmtop3.topology, system, integrator, Platform.getPlatformByName('Reference'))
# Check that the energy is about what we expect it to be # Check that the energy is about what we expect it to be
sim.context.setPeriodicBoxVectors(*inpcrd3.boxVectors) sim.context.setPeriodicBoxVectors(*inpcrd3.getBoxVectors())
sim.context.setPositions(inpcrd3.positions) sim.context.setPositions(inpcrd3.getPositions())
ene = sim.context.getState(getEnergy=True, enforcePeriodicBox=True).getPotentialEnergy() ene = sim.context.getState(getEnergy=True, enforcePeriodicBox=True).getPotentialEnergy()
ene = ene.value_in_unit(kilocalories_per_mole) ene = ene.value_in_unit(kilocalories_per_mole)
# Make sure the energy is relatively close to the value we get with # Make sure the energy is relatively close to the value we get with
# Amber using this force field. # Amber using this force field.
self.assertAlmostEqual(-7042.3903307/ene, 1, places=3) self.assertAlmostEqual(-7042.3903307/ene, 1, places=3)
def test_LJ1264(self):
"""Test prmtop with 12-6-4 vdW potential implemented"""
system = prmtop4.createSystem(nonbondedMethod=PME,
nonbondedCutoff=8*angstroms)
# Check the forces
has_nonbond_force = has_custom_nonbond_force = False
nonbond_exceptions = custom_nonbond_exclusions = 0
for force in system.getForces():
if isinstance(force, NonbondedForce):
has_nonbond_force = True
nonbond_exceptions = force.getNumExceptions()
force.setUseDispersionCorrection(False)
elif isinstance(force, CustomNonbondedForce):
self.assertTrue(force.getUseLongRangeCorrection())
has_custom_nonbond_force = True
custom_nonbond_exceptions = force.getNumExclusions()
force.setUseLongRangeCorrection(False)
self.assertTrue(has_nonbond_force)
self.assertTrue(has_custom_nonbond_force)
self.assertEqual(nonbond_exceptions, custom_nonbond_exceptions)
integrator = VerletIntegrator(1.0*femtoseconds)
# Use reference platform, since it should always be present and
# 'working', and the system is plenty small so this won't be too slow
sim = Simulation(prmtop4.topology, system, integrator, Platform.getPlatformByName('Reference'))
# Check that the energy is about what we expect it to be
sim.context.setPeriodicBoxVectors(*inpcrd4.boxVectors)
sim.context.setPositions(inpcrd4.positions)
ene = sim.context.getState(getEnergy=True, enforcePeriodicBox=True).getPotentialEnergy()
ene = ene.value_in_unit(kilocalories_per_mole)
# Make sure the energy is relatively close to the value we get with
# Amber using this force field.
self.assertAlmostEqual(-7307.2735621/ene, 1, places=3)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
This diff is collapsed.
This diff is collapsed.
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