Skip to content

Commit

Permalink
Implement points 0.4 and remove orientation
Browse files Browse the repository at this point in the history
  • Loading branch information
samirelanduk committed Apr 3, 2018
1 parent b2bcc43 commit 1f5ba4b
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 264 deletions.
4 changes: 2 additions & 2 deletions atomium/structures/atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import weakref
from math import sqrt, acos, degrees
from points import Vector
from points import Vector, rotate_3d_vectors

def atom_query(func):
"""Decorator which can be applied to any function which returns atoms. It
Expand Down Expand Up @@ -202,7 +202,7 @@ def rotate(self, angle, axis):
:param str axis: The axis to rotate around."""

vector = Vector(self._x, self._y, self._z)
vector.rotate(angle, axis)
rotate_3d_vectors(angle, ["x", "y", "z"].index(axis), vector)
self._x, self._y, self._z = vector.values()


Expand Down
62 changes: 1 addition & 61 deletions atomium/structures/molecules.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from itertools import combinations
from points import Vector
from points import Matrix
import points
import weakref
from math import sqrt, pi, degrees, floor, ceil
from .atoms import Atom, atom_query
Expand Down Expand Up @@ -264,67 +265,6 @@ def rotate(self, angle, axis):
atom.rotate(angle, axis)


def orient(self, atom1, atom2=None, axis="x", atom3=None, plane="xy"):
"""Orients the structure so that a given atom is at the origin. It can
also then orient it further so that a given atom lies on a given axis,
and can orient it further still so that a given atom lies on a given
plane.
:param Atom atom1: The atom to move to the origin.
:param Atom atom2: The atom to move to an axis.
:param str axis: The axis to move atom2 to.
:param Atom atom3: The atom to move to a plane.
:param str plane: The plane to move atom3 to.
:raises TypeError: if any of the atoms are not atoms.
:raises ValueError: if the plane given is not recognised.
:raises ValueError: if the plane given does not include the axis\
given."""

if not isinstance(atom1, Atom):
raise TypeError("{} is not an atom - cannot orient".format(atom1))
if atom2 is not None and not isinstance(atom2, (Atom)):
raise TypeError("{} is not an atom - cannot orient".format(atom2))
if atom3 is not None and not isinstance(atom3, (Atom)):
raise TypeError("{} is not an atom - cannot orient".format(atom3))
self.translate(*[-n for n in atom1.location()])
if atom2:
xyz, next_ = ["x", "y", "z"], {"x": "y", "y": "z", "z": "x"}
if axis not in xyz:
raise ValueError("{} is not a valid axis".format(axis))
first_axis = (axis, xyz.index(axis))
second_axis = (next_[axis], xyz.index(next_[axis]))
third_axis = (next_[next_[axis]], xyz.index(next_[next_[axis]]))
axis_v = Vector(*[1 if n == first_axis[1] else 0 for n in range(3)])
atom_vector = Vector(*[0 if i == second_axis[1] else n
for i, n in enumerate(atom2.location())])
angle = atom_vector.angle_with(axis_v)
angle = -angle if atom_vector[third_axis[1]] < 0 else angle
self.rotate(angle, second_axis[0])
atom_vector = Vector(*atom2.location())
angle = atom_vector.angle_with(axis_v)
angle = -angle if atom_vector[second_axis[1]] > 0 else angle
self.rotate(angle, third_axis[0])
if atom3:
if len(plane) != 2 or not set(plane) < set(xyz):
raise ValueError("{} is not a valid plane".format(plane))
if axis not in plane:
raise ValueError(
"Can't move to {} plane by rotating {}-axis".format(plane, axis)
)
atom_vector = Vector(*[0 if i == first_axis[1] else n
for i, n in enumerate(atom3.location())])
codimension = plane.replace(axis, "")
axis_vector = Vector(*[1 if n == xyz.index(codimension)
else 0 for n in range(3)])
angle = atom_vector.angle_with(axis_vector)
check_dimension = (set("xyz") - set(plane)).pop()
component = atom_vector[xyz.index(check_dimension)]
neg = codimension != next_[axis]
if (component < 0 and neg) or (component > 0 and not neg):
angle = -angle
self.rotate(angle, first_axis[0])


def center_of_mass(self):
"""Returns the center of mass of the structure. This is the average of
all the atom coordinates, weighted by the mass of each atom.
Expand Down
81 changes: 3 additions & 78 deletions tests/integration/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,84 +146,9 @@ def test_structures(self):
model.rotate(math.pi / 8, "z"), model.round(6)
self.assertEqual(atoms[0].location(), (0, 0, 0))
self.assertEqual(atoms[13].location(), (1.689247, -0.382683, 0))
model.orient(atoms[-1])
self.assertEqual(atoms[-1].location(), (0, 0, 0))
self.assertNotEqual(atoms[0].location(), (0, 0, 0))
model.orient(atoms[4], atom2=atoms[-1], axis="y"), model.round(8)
self.assertEqual(atoms[4].location(), (0, 0, 0))
self.assertEqual((atoms[-1].x(), atoms[-1].z()), (0, 0))
model.orient(atoms[8], atom2=atoms[9], axis="z"), model.round(8)
self.assertEqual(atoms[8].location(), (0, 0, 0))
self.assertEqual((atoms[9].x(), atoms[9].y()), (0, 0))
model.orient(atoms[19], atom2=atoms[1], axis="x"), model.round(8)
self.assertEqual(atoms[19].location(), (0, 0, 0))
self.assertEqual((atoms[1].y(), atoms[1].z()), (0, 0))
model.orient(atoms[1], atom2=atoms[19], axis="x"), model.round(8)
self.assertEqual(atoms[1].location(), (0, 0, 0))
self.assertEqual((atoms[19].y(), atoms[19].z()), (0, 0))
model.orient(atoms[25], atom2=atoms[19], axis="x", atom3=atoms[5], plane="xy")
model.round(8)
self.assertEqual(atoms[25].location(), (0, 0, 0))
self.assertEqual((atoms[19].y(), atoms[19].z()), (0, 0))
self.assertEqual(atoms[5].z(), 0)
model.orient(atoms[5], atom2=atoms[25], axis="x", atom3=atoms[19], plane="yx")
model.round(8)
self.assertEqual(atoms[5].location(), (0, 0, 0))
self.assertEqual((atoms[25].y(), atoms[25].z()), (0, 0))
self.assertEqual(atoms[19].z(), 0)
model.orient(atoms[5], atom2=atoms[25], axis="x", atom3=atoms[19], plane="xz")
model.round(8)
self.assertEqual(atoms[5].location(), (0, 0, 0))
self.assertEqual((atoms[25].y(), atoms[25].z()), (0, 0))
self.assertEqual(atoms[19].y(), 0)
model.orient(atoms[21], atom2=atoms[2], axis="x", atom3=atoms[13], plane="zx")
model.round(8)
self.assertEqual(atoms[21].location(), (0, 0, 0))
self.assertEqual((atoms[2].y(), atoms[2].z()), (0, 0))
self.assertEqual(atoms[13].y(), 0)
model.orient(atoms[21], atom2=atoms[2], axis="y", atom3=atoms[13], plane="xy")
model.round(8)
self.assertEqual(atoms[21].location(), (0, 0, 0))
self.assertEqual((atoms[2].x(), atoms[2].z()), (0, 0))
self.assertEqual(atoms[13].z(), 0)
model.orient(atoms[11], atom2=atoms[4], axis="y", atom3=atoms[10], plane="yx")
model.round(8)
self.assertEqual(atoms[11].location(), (0, 0, 0))
self.assertEqual((atoms[4].x(), atoms[4].z()), (0, 0))
self.assertEqual(atoms[10].z(), 0)
model.orient(atoms[11], atom2=atoms[4], axis="y", atom3=atoms[10], plane="yz")
model.round(8)
self.assertEqual(atoms[11].location(), (0, 0, 0))
self.assertEqual((atoms[4].x(), atoms[4].z()), (0, 0))
self.assertEqual(atoms[10].x(), 0)
model.orient(atoms[1], atom2=atoms[2], axis="y", atom3=atoms[17], plane="zy")
model.round(8)
self.assertEqual(atoms[1].location(), (0, 0, 0))
self.assertEqual((atoms[2].x(), atoms[2].z()), (0, 0))
self.assertEqual(atoms[17].x(), 0)
model.orient(atoms[1], atom2=atoms[2], axis="z", atom3=atoms[17], plane="xz")
model.round(8)
self.assertEqual(atoms[1].location(), (0, 0, 0))
self.assertEqual((atoms[2].x(), atoms[2].y()), (0, 0))
self.assertEqual(atoms[17].y(), 0)
model.orient(atoms[11], atom2=atoms[0], axis="z", atom3=atoms[16], plane="zx")
model.round(8)
self.assertEqual(atoms[11].location(), (0, 0, 0))
self.assertEqual((atoms[0].x(), atoms[0].y()), (0, 0))
self.assertEqual(atoms[16].y(), 0)
model.orient(atoms[11], atom2=atoms[0], axis="z", atom3=atoms[16], plane="yz")
model.round(8)
self.assertEqual(atoms[11].location(), (0, 0, 0))
self.assertEqual((atoms[0].x(), atoms[0].y()), (0, 0))
self.assertEqual(atoms[16].x(), 0)
model.orient(atoms[10], atom2=atoms[9], axis="z", atom3=atoms[11], plane="zy")
model.round(8)
self.assertEqual(atoms[10].location(), (0, 0, 0))
self.assertEqual((atoms[9].x(), atoms[9].y()), (0, 0))
self.assertEqual(atoms[11].x(), 0)
model.orient(atoms[0], atom2=atoms[1], axis="x", atom3=atoms[4], plane="xy")
model.round(4)
self.assertEqual(atoms[13].location(), (1, 1, 1))
model.rotate(-math.pi / 8, "z"), model.round(6)
model.rotate(-math.pi / 4, "y"), model.round(6)
model.rotate(-math.pi / 2, "x"), model.round(1)

# The atoms work in the model
self.assertEqual(atoms[0].nearby(0.5), set())
Expand Down
117 changes: 0 additions & 117 deletions tests/unit/structure_tests/test_atomic_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,123 +467,6 @@ def test_can_get_rmsd(self, mock_pair):



class AtomicStructureOrientationTests(AtomicStructureTest):

def setUp(self):
AtomicStructureTest.setUp(self)
self.patch1 = patch("atomium.structures.molecules.AtomicStructure.translate")
self.patch2 = patch("atomium.structures.molecules.AtomicStructure.rotate")
self.mock_translate = self.patch1.start()
self.mock_rotate = self.patch2.start()
self.atom1.location.return_value = (1, 2, 3)
self.atom2.location.return_value = (1, 1, 1)
self.atom3.location.return_value = (7, 8, 9)


def tearDown(self):
self.patch1.stop()
self.patch2.stop()


def test_can_orient_to_origin(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
structure.orient(self.atom1)
self.mock_translate.assert_called_with(-1, -2, -3)


def test_atom1_must_be_atom(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
with self.assertRaises(TypeError):
structure.orient("atom")


def test_can_orient_onto_x_axis(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
structure.orient(self.atom1, atom2=self.atom2, axis="x")
self.mock_translate.assert_called_with(-1, -2, -3)
first_rotation_call = self.mock_rotate.call_args_list[0][0]
self.assertAlmostEqual(first_rotation_call[0], pi / 4, delta=0.00005)
self.assertEqual(first_rotation_call[1], "y")
second_rotation_call = self.mock_rotate.call_args_list[1][0]
self.assertAlmostEqual(second_rotation_call[0], -0.9553166, delta=0.005)
self.assertEqual(second_rotation_call[1], "z")


def test_can_orient_onto_y_axis(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
structure.orient(self.atom1, atom2=self.atom2, axis="y")
self.mock_translate.assert_called_with(-1, -2, -3)
first_rotation_call = self.mock_rotate.call_args_list[0][0]
self.assertAlmostEqual(first_rotation_call[0], pi / 4, delta=0.00005)
self.assertEqual(first_rotation_call[1], "z")
second_rotation_call = self.mock_rotate.call_args_list[1][0]
self.assertAlmostEqual(second_rotation_call[0], -0.9553166, delta=0.005)
self.assertEqual(second_rotation_call[1], "x")


def test_can_orient_onto_z_axis(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
structure.orient(self.atom1, atom2=self.atom2, axis="z")
self.mock_translate.assert_called_with(-1, -2, -3)
first_rotation_call = self.mock_rotate.call_args_list[0][0]
self.assertAlmostEqual(first_rotation_call[0], pi / 4, delta=0.00005)
self.assertEqual(first_rotation_call[1], "x")
second_rotation_call = self.mock_rotate.call_args_list[1][0]
self.assertAlmostEqual(second_rotation_call[0], -0.9553166, delta=0.005)
self.assertEqual(second_rotation_call[1], "y")


def test_atom2_must_be_atom(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
with self.assertRaises(TypeError):
structure.orient(self.atom2, atom2="atom")


def test_axis_must_be_valid(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
with self.assertRaises(ValueError) as e:
structure.orient(self.atom1, atom2=self.atom2, axis="7")
self.assertIn("axis", str(e.exception))


def test_can_rotate_onto_plane(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
structure.orient(
self.atom1, atom2=self.atom2, axis="z", atom3=self.atom3, plane="xz"
)
self.mock_translate.assert_called_with(-1, -2, -3)
first_rotation_call = self.mock_rotate.call_args_list[0][0]
self.assertAlmostEqual(first_rotation_call[0], pi / 4, delta=0.00005)
self.assertEqual(first_rotation_call[1], "x")
second_rotation_call = self.mock_rotate.call_args_list[1][0]
self.assertAlmostEqual(second_rotation_call[0], -0.9553166, delta=0.005)
self.assertEqual(second_rotation_call[1], "y")
third_rotation_call = self.mock_rotate.call_args_list[2][0]
self.assertAlmostEqual(third_rotation_call[0], -0.8519663, delta=0.005)
self.assertEqual(third_rotation_call[1], "z")


def test_atom3_must_be_atom(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
with self.assertRaises(TypeError):
structure.orient(self.atom1, atom2=self.atom2, atom3="atom3")


def test_plane_must_be_valid(self):
structure = AtomicStructure(self.atom1, self.atom2, self.atom3)
with self.assertRaises(ValueError) as e:
structure.orient(self.atom1, atom2=self.atom2, atom3=self.atom3, plane="dtg")
self.assertIn("plane", str(e.exception))
with self.assertRaises(ValueError) as e:
structure.orient(self.atom1, atom2=self.atom2, atom3=self.atom3, plane="xyz")
self.assertIn("plane", str(e.exception))
with self.assertRaises(ValueError) as e:
structure.orient(self.atom1, atom2=self.atom2, atom3=self.atom3, plane="yz")
self.assertIn("x-axis", str(e.exception))




class AtomicStructureTranslationTests(AtomicStructureTest):

@patch("atomium.structures.molecules.AtomicStructure.atoms")
Expand Down
13 changes: 7 additions & 6 deletions tests/unit/structure_tests/test_atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,18 @@ def test_can_translate_atoms(self):
class AtomRotationTEsts(TestCase):

@patch("atomium.structures.atoms.Vector")
def test_can_rotate_atoms(self, mock_vector):
@patch("atomium.structures.atoms.rotate_3d_vectors")
def test_can_rotate_atoms(self, mock_rot, mock_vector):
v = Mock()
mock_vector.return_value = v
v.values.return_value = (10, 20, 30)
v.values.return_value = (11, 21, 31)
atom = Atom("C", 20, 30, 50)
atom.rotate(0.5, "y")
mock_vector.assert_called_with(20, 30, 50)
v.rotate.assert_called_with(0.5, "y")
self.assertEqual(atom._x, 10)
self.assertEqual(atom._y, 20)
self.assertEqual(atom._z, 30)
mock_rot.assert_called_with(0.5, 1, v)
self.assertEqual(atom._x, 11)
self.assertEqual(atom._y, 21)
self.assertEqual(atom._z, 31)



Expand Down

0 comments on commit 1f5ba4b

Please sign in to comment.