Unverified Commit cd8f19c5 authored by Evan Pretti's avatar Evan Pretti Committed by GitHub
Browse files

Properly handle and test multiple registration of atom types without elements (#4795)

* Properly handle duplicate atom type definitions without elements

* Correct the description of a test in a docstring

* Correctly handle existing type without element and duplicate type with element

* Try to update actions/cache to v4
parent fca5cac4
...@@ -212,7 +212,7 @@ jobs: ...@@ -212,7 +212,7 @@ jobs:
ccache -z ccache -z
- name: "Restore ccache" - name: "Restore ccache"
uses: actions/cache@v3.3.2 uses: actions/cache@v4
with: with:
path: .ccache path: .ccache
key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }} key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }}
...@@ -354,7 +354,7 @@ jobs: ...@@ -354,7 +354,7 @@ jobs:
ccache -z ccache -z
- name: "Restore ccache" - name: "Restore ccache"
uses: actions/cache@v3.3.2 uses: actions/cache@v4
with: with:
path: .ccache path: .ccache
key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }} key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }}
...@@ -495,7 +495,7 @@ jobs: ...@@ -495,7 +495,7 @@ jobs:
echo "timestamp=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT echo "timestamp=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT
- name: "Restore ccache" - name: "Restore ccache"
uses: actions/cache@v3.3.2 uses: actions/cache@v4
with: with:
path: .ccache path: .ccache
key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }} key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }}
...@@ -567,7 +567,7 @@ jobs: ...@@ -567,7 +567,7 @@ jobs:
ccache -z ccache -z
- name: "Restore ccache" - name: "Restore ccache"
uses: actions/cache@v3.3.2 uses: actions/cache@v4
with: with:
path: .ccache path: .ccache
key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }} key: ccache-${{ secrets.CACHE_VERSION }}-${{ steps.prepare-ccache.outputs.key }}-${{ steps.prepare-ccache.outputs.timestamp }}
......
...@@ -444,7 +444,8 @@ class ForceField(object): ...@@ -444,7 +444,8 @@ class ForceField(object):
if name in self._atomTypes: if name in self._atomTypes:
# allow multiple registrations of the same atom type provided the definitions are identical # allow multiple registrations of the same atom type provided the definitions are identical
existing = self._atomTypes[name] existing = self._atomTypes[name]
if existing.atomClass == parameters['class'] and existing.mass == float(parameters['mass']) and existing.element.symbol == parameters['element']: elementsMatch = ((existing.element is None and 'element' not in parameters) or (existing.element is not None and 'element' in parameters and existing.element.symbol == parameters['element']))
if existing.atomClass == parameters['class'] and existing.mass == float(parameters['mass']) and elementsMatch:
return return
raise ValueError('Found multiple definitions for atom type: '+name) raise ValueError('Found multiple definitions for atom type: '+name)
atomClass = parameters['class'] atomClass = parameters['class']
......
...@@ -379,6 +379,156 @@ class TestForceField(unittest.TestCase): ...@@ -379,6 +379,156 @@ class TestForceField(unittest.TestCase):
self.assertEqual(vectors[i], self.pdb1.topology.getPeriodicBoxVectors()[i]) self.assertEqual(vectors[i], self.pdb1.topology.getPeriodicBoxVectors()[i])
self.assertEqual(vectors[i], system.getDefaultPeriodicBoxVectors()[i]) self.assertEqual(vectors[i], system.getDefaultPeriodicBoxVectors()[i])
def test_duplicateAtomTypeAllowed(self):
"""Test that multiple registrations of the same atom type with identical definitions are allowed."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
ff = ForceField(StringIO(xml1), StringIO(xml2))
self.assertTrue("test-name" in ff._atomTypes)
at = ff._atomTypes["test-name"]
self.assertEqual(at.atomClass, "test")
self.assertEqual(at.element, elem.hydrogen)
self.assertEqual(at.mass, 1.007947)
def test_duplicateAtomTypeAllowedNoElement(self):
"""Test that multiple registrations of the same atom type with identical definitions and without elements are allowed."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" mass="0.0"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" mass="0.0"/>
</AtomTypes>
</ForceField>"""
ff = ForceField(StringIO(xml1), StringIO(xml2))
self.assertTrue("test-name" in ff._atomTypes)
at = ff._atomTypes["test-name"]
self.assertEqual(at.atomClass, "test")
self.assertEqual(at.element, None)
self.assertEqual(at.mass, 0.0)
def test_duplicateAtomTypeForbiddenClass(self):
"""Test that multiple registrations of the same atom type with different classes are forbidden."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test-1" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test-2" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
with self.assertRaises(ValueError):
ff = ForceField(StringIO(xml1), StringIO(xml2))
def test_duplicateAtomTypeForbiddenElement(self):
"""Test that multiple registrations of the same atom type with different elements are forbidden."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="C" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
with self.assertRaises(ValueError):
ff = ForceField(StringIO(xml1), StringIO(xml2))
def test_duplicateAtomTypeForbiddenElementAdded(self):
"""Test that multiple registrations of the same atom type, the first without and the second with an element, are forbidden."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
with self.assertRaises(ValueError):
ff = ForceField(StringIO(xml1), StringIO(xml2))
def test_duplicateAtomTypeForbiddenElementRemoved(self):
"""Test that multiple registrations of the same atom type, the first with and the second without an element, are forbidden."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
with self.assertRaises(ValueError):
ff = ForceField(StringIO(xml1), StringIO(xml2))
def test_duplicateAtomTypeForbiddenMass(self):
"""Test that multiple registrations of the same atom type with different masses are forbidden."""
xml1 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="1.007947"/>
</AtomTypes>
</ForceField>"""
xml2 = """
<ForceField>
<AtomTypes>
<Type name="test-name" class="test" element="H" mass="12.01078"/>
</AtomTypes>
</ForceField>"""
with self.assertRaises(ValueError):
ff = ForceField(StringIO(xml1), StringIO(xml2))
def test_ResidueAttributes(self): def test_ResidueAttributes(self):
"""Test a ForceField that gets per-particle parameters from residue attributes.""" """Test a ForceField that gets per-particle parameters from residue attributes."""
......
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