Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trim coordinate_transform.py, new features for spin method #1054

Merged
merged 6 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions mbuild/compound.py
Original file line number Diff line number Diff line change
Expand Up @@ -2416,7 +2416,7 @@ def rotate(self, theta, around):
new_positions = _rotate(self.xyz_with_ports, theta, around)
self.xyz_with_ports = new_positions

def spin(self, theta, around):
def spin(self, theta, around, anchor=None):
"""Rotate Compound in place around an arbitrary vector.

Parameters
Expand All @@ -2425,12 +2425,23 @@ def spin(self, theta, around):
The angle by which to rotate the Compound, in radians.
around : np.ndarray, shape=(3,), dtype=float
The axis about which to spin the Compound.
anchor : mb.Compound, optional, default=None (self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you pass it a compound, it should spin around the center of mass of that compound. This way you don't have to specify particle/compound, since it'll still use the center of mass of a single bead compound (the synonym for a particle in mbuild). Also, what does the "(self)" mean? I'm inferring that this means the value of None really will use self. Not sure if this is standard to put in the function definition, but maybe could add a bit of uncertainty?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if None is provided for the anchor, the Compound will rotate around its own self.pos, which will be its center of mass, this option is for when you want rotate a compound but around one particular particle instead the center of mass (e.g., rotate a chain attached to a surface, but you want the particle attached to the surface to be fixed, or else that bond will be wonky)

Anchor compound/particle to perform spinning.
If the anchor is not a particle, the spin will be
around the center of the anchor Compound.
"""
around = np.asarray(around).reshape(3)
center_pos = self.center
self.translate(-center_pos)

if anchor:
msg = f"{anchor} is not part of {self}."
assert anchor in self.successors(), msg
else:
anchor = self
anchor_pos = anchor.center

self.translate(-anchor_pos)
self.rotate(theta, around)
self.translate(center_pos)
self.translate(anchor_pos)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is smart.


def rotate_dihedral(self, bond, phi):
"""Rotate a dihedral about a central bond.
Expand Down
157 changes: 0 additions & 157 deletions mbuild/coordinate_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,12 @@
import numpy as np
from numpy.linalg import inv, norm, svd

from mbuild.utils.exceptions import RemovedFuncError

__all__ = [
"force_overlap",
"x_axis_transform",
"y_axis_transform",
"z_axis_transform",
# Deprecated
"equivalence_transform",
"rotate",
"rotate_around_x",
"rotate_around_y",
"rotate_around_z",
"spin",
"spin_x",
"spin_y",
"spin_z",
"translate",
"translate_to",
]


Expand Down Expand Up @@ -450,36 +437,6 @@ def _choose_correct_port(from_port, to_port):
return [(correct_port, to_port["up"])], T


def translate(compound, pos):
"""Translate a compound by a vector.

Parameters
----------
compound : mb.Compound
The compound being translated.
pos : np.ndarray, shape=(3,), dtype=float
The vector to translate the compound by.
"""
raise RemovedFuncError(
"translate()", "Compound.translate()", "0.7.0", "0.11.0"
)


def translate_to(compound, pos):
"""Translate a compound to a coordinate.

Parameters
----------
compound : mb.Compound
The compound being translated.
pos : np.ndarray, shape=(3,), dtype=float
The coordinate to translate the compound to.
"""
raise RemovedFuncError(
"translate_to()", "Compound.translate_to()", "0.7.0", "0.11.0"
)


def _translate(coordinates, by):
"""Translate a set of coordinates by a vector.

Expand Down Expand Up @@ -525,81 +482,6 @@ def _rotate(coordinates, theta, around):
return Rotation(theta, around).apply_to(coordinates)


def rotate(compound, theta, around):
"""Rotate a compound around an arbitrary vector.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound, in radians.
around : np.ndarray, shape=(3,), dtype=float
The vector about which to rotate the compound.
"""
raise RemovedFuncError("rotate()", "Compound.rotate()", "0.7.0", "0.11.0")


def rotate_around_x(compound, theta):
"""Rotate a compound around the x axis.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound.
"""
raise RemovedFuncError(
"rotate_around_x()", "Compound.rotate()", "0.7.0", "0.11.0"
)


def rotate_around_y(compound, theta):
"""Rotate a compound around the y axis.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound.
"""
raise RemovedFuncError(
"rotate_around_y()", "Compound.rotate()", "0.7.0", "0.11.0"
)


def rotate_around_z(compound, theta):
"""Rotate a compound around the z axis.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound.
"""
raise RemovedFuncError(
"rotate_around_z()", "Compound.rotate()", "0.7.0", "0.11.0"
)


def spin(compound, theta, around):
"""Rotate a compound in place around an arbitrary vector.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound, in radians.
around : np.ndarray, shape=(3,), dtype=float
The axis about which to spin the compound.
"""
raise RemovedFuncError("spin()", "Compound.spin()", "0.7.0", "0.11.0")


def _spin(coordinates, theta, around):
"""Rotate a set of coordinates in place around an arbitrary vector.

Expand All @@ -622,45 +504,6 @@ def _spin(coordinates, theta, around):
return coordinates


def spin_x(compound, theta):
"""Rotate a compound in place around the x axis.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound.
"""
raise RemovedFuncError("spin_x()", "Compound.spin_x()", "0.7.0", "0.11.0")


def spin_y(compound, theta):
"""Rotate a compound in place around the y axis.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound.
"""
raise RemovedFuncError("spin_y()", "Compound.spin_y()", "0.7.0", "0.11.0")


def spin_z(compound, theta):
"""Rotate a compound in place around the z axis.

Parameters
----------
compound : mb.Compound
The compound being rotated.
theta : float
The angle by which to rotate the compound.
"""
raise RemovedFuncError("spin_z()", "Compound.spin_z()", "0.7.0", "0.11.0")


def x_axis_transform(
compound, new_origin=None, point_on_x_axis=None, point_on_xy_plane=None
):
Expand Down
43 changes: 8 additions & 35 deletions mbuild/tests/test_coordinate_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,11 @@
_spin,
angle,
force_overlap,
rotate,
rotate_around_x,
rotate_around_y,
rotate_around_z,
spin,
spin_x,
spin_y,
spin_z,
translate,
translate_to,
x_axis_transform,
y_axis_transform,
z_axis_transform,
)
from mbuild.tests.base_test import BaseTest
from mbuild.utils.exceptions import RemovedFuncError


class TestCoordinateTransform(BaseTest):
Expand Down Expand Up @@ -136,6 +125,14 @@ def test_spin_inputs(self, methane):
methane.spin(6.9, [1, 0, 0])
methane.spin(6.9, (1, 0, 0))

def test_spin_with_anchor(self, methane):
original_posH = methane[1].pos
original_posC = methane[0].pos
methane.spin(6.9, [1, 0, 0], anchor=methane[1])

assert all(methane[1].pos == original_posH)
assert any(methane[0].pos != original_posC)

def test_rotate_inputs(self, methane):
methane.rotate(6.9, [1, 0, 0])
methane.rotate(6.9, (1, 0, 0))
Expand Down Expand Up @@ -248,37 +245,13 @@ def test_spin_z_eq(self, sixpoints):
compound2.spin(np.pi * 1.23456789, around=np.asarray([0, 0, 1]))
assert np.allclose(compound2.xyz, sixpoints.xyz, atol=1e-16)

def test_spin_deprecated_x(self, sixpoints):
with pytest.raises(RemovedFuncError):
spin_x(sixpoints, np.pi * 3 / 2)

def test_spin_deprecated_y(self, sixpoints):
with pytest.raises(RemovedFuncError):
spin_y(sixpoints, np.pi * 3 / 2)

def test_spin_deprecated_z(self, sixpoints):
with pytest.raises(RemovedFuncError):
spin_z(sixpoints, 69)

def test_spin_arbitraty(self, sixpoints):
before = mb.clone(sixpoints)
sixpoints.spin(np.pi, np.asarray([1, 1, 0]))
assert np.allclose(
sixpoints["up"].xyz, before["right"].xyz, atol=1e-16
) and np.allclose(sixpoints["down"].xyz, before["left"].xyz, atol=1e-16)

def test_error_rotate_x(self, methane):
with pytest.raises(RemovedFuncError):
rotate_around_x(methane, np.pi)

def test_error_rotate_y(self, methane):
with pytest.raises(RemovedFuncError):
rotate_around_y(methane, np.pi)

def test_error_rotate_z(self, methane):
with pytest.raises(RemovedFuncError):
rotate_around_z(methane, np.pi)

def test_spin_relative_compound_coordinates(self, sixpoints):
"""Check compounds's relative coordinates don't change upon spinning"""
np.random.seed(0)
Expand Down