Exemple #1
0
    def from_euler(cls, euler):
        """Creates a rotation from an array of Euler angles.

        Parameters
        ----------
        euler : array-like
            Euler angles in the Bunge convention.

        """
        # Bunge convention
        euler = np.array(euler)
        n = euler.shape[:-1]
        alpha, beta, gamma = euler[..., 0], euler[..., 1], euler[..., 2]
        alpha -= np.pi / 2
        gamma -= 3 * np.pi / 2
        zero = np.zeros(n)
        qalpha = Quaternion(
            np.stack((np.cos(alpha / 2), zero, zero, np.sin(alpha / 2)),
                     axis=-1))
        qbeta = Quaternion(
            np.stack((np.cos(beta / 2), zero, np.sin(beta / 2), zero),
                     axis=-1))
        qgamma = Quaternion(
            np.stack((np.cos(gamma / 2), zero, zero, np.sin(gamma / 2)),
                     axis=-1))
        data = qalpha * qbeta * qgamma
        rot = cls(data.data)
        rot.improper = zero
        return rot
Exemple #2
0
 def __mul__(self, other):
     if isinstance(other, Rotation):
         q = Quaternion(self) * Quaternion(other)
         r = other.__class__(q)
         i = np.logical_xor(self.improper, other.improper)
         r.improper = i
         return r
     if isinstance(other, Quaternion):
         q = Quaternion(self) * other
         return q
     if isinstance(other, Vector3d):
         v = Quaternion(self) * other
         improper = (self.improper * np.ones(other.shape)).astype(bool)
         v[improper] = -v[improper]
         return v
     if isinstance(other, int) or isinstance(other,
                                             list):  # has to plus/minus 1
         other = np.atleast_1d(other).astype(int)
     if isinstance(other, np.ndarray):
         assert np.all(
             abs(other) == 1), "Rotations can only be multiplied by 1 or -1"
         r = Rotation(self.data)
         r.improper = np.logical_xor(self.improper, other == -1)
         return r
     return NotImplemented
Exemple #3
0
    def __gt__(self, other):
        """Overridden greater than method. Applying this to an Orientation
        will return only orientations those that lie within the OrientationRegion
        """

        c = Quaternion(self).dot_outer(Quaternion(other)).data
        inside = np.logical_or(
            np.all(np.greater_equal(c, -EPSILON), axis=0),
            np.all(np.less_equal(c, +EPSILON), axis=0),
        )
        return inside
Exemple #4
0
def test_abcd():
    quat = Quaternion([2, 2, 2, 2])
    quat.a = 1
    quat.b = 1
    quat.c = 1
    quat.d = 1
    assert np.allclose(quat.data, 1)
Exemple #5
0
    def from_euler(cls, euler, convention="bunge", direction="crystal2lab"):
        """Creates a rotation from an array of Euler angles.

        Parameters
        ----------
        euler : array-like
            Euler angles in the Bunge convention.
        convention : str
            Only 'bunge' is currently suppported
        direction : str
            'lab2crystal' or 'crystal2lab'
        """
        if convention != "bunge":
            raise ValuerError("Only 'bunge' is an acceptable convention")
        if direction not in ["lab2crystal", "crystal2lab"]:
            raise ValueError(
                "The chosen direction is not one of the allowed options")

        euler = np.array(euler)
        n = euler.shape[:-1]

        # Uses A.5 & A.6 from Modelling Simul. Mater. Sci. Eng. 23 (2015) 083501

        alpha = euler[..., 0]  # psi1
        beta = euler[..., 1]  # Psi
        gamma = euler[..., 2]  # psi3

        sigma = 0.5 * np.add(alpha, gamma)
        delta = 0.5 * np.subtract(alpha, gamma)
        c = np.cos(beta / 2)
        s = np.sin(beta / 2)

        # Using P = 1 from A.6
        q = np.zeros(n + (4, ))
        q[..., 0] = c * np.cos(sigma)
        q[..., 1] = -s * np.cos(delta)
        q[..., 2] = -s * np.sin(delta)
        q[..., 3] = -c * np.sin(sigma)

        for i in [1, 2, 3, 0]:  # flip the zero element last
            q[..., i] = np.where(q[..., 0] < 0, -q[..., i], q[..., i])

        data = Quaternion(q)

        if direction == "lab2crystal":
            data = ~data

        rot = cls(data.data)
        rot.improper = np.zeros((n))
        return rot
Exemple #6
0
    def from_matrix(cls, matrix):
        """Creates rotations from orientation matrices
        [Rowenhorst2015]_.

        Parameters
        ----------
        matrix : array_like
            Array of orientation matrices.

        Examples
        --------
        >>> import numpy as np
        >>> from orix.quaternion.rotation import Rotation
        >>> r = Rotation.from_matrix(np.eye(3))
        >>> np.allclose(r.data, [1, 0, 0, 0])
        True
        >>> r = Rotation.from_matrix(np.diag([1, -1, -1]))
        >>> np.allclose(r.data, [0, 1, 0, 0])
        True
        """
        om = np.asarray(matrix)
        # Assuming (3, 3) as last two dims
        n = (1, ) if om.ndim == 2 else om.shape[:-2]
        q = np.zeros(n + (4, ))

        # Compute quaternion components
        q0_almost = 1 + om[..., 0, 0] + om[..., 1, 1] + om[..., 2, 2]
        q1_almost = 1 + om[..., 0, 0] - om[..., 1, 1] - om[..., 2, 2]
        q2_almost = 1 - om[..., 0, 0] + om[..., 1, 1] - om[..., 2, 2]
        q3_almost = 1 - om[..., 0, 0] - om[..., 1, 1] + om[..., 2, 2]
        q[...,
          0] = 0.5 * np.sqrt(np.where(q0_almost < _FLOAT_EPS, 0, q0_almost))
        q[...,
          1] = 0.5 * np.sqrt(np.where(q1_almost < _FLOAT_EPS, 0, q1_almost))
        q[...,
          2] = 0.5 * np.sqrt(np.where(q2_almost < _FLOAT_EPS, 0, q2_almost))
        q[...,
          3] = 0.5 * np.sqrt(np.where(q3_almost < _FLOAT_EPS, 0, q3_almost))

        # Modify component signs if necessary
        q[..., 1] = np.where(om[..., 2, 1] < om[..., 1, 2], -q[..., 1], q[...,
                                                                          1])
        q[..., 2] = np.where(om[..., 0, 2] < om[..., 2, 0], -q[..., 2], q[...,
                                                                          2])
        q[..., 3] = np.where(om[..., 1, 0] < om[..., 0, 1], -q[..., 3], q[...,
                                                                          3])

        return cls(Quaternion(q)).unit  # Normalized
Exemple #7
0
def test_init(input_length):
    with pytest.raises(DimensionError):
        Quaternion(tuple(range(input_length)))
Exemple #8
0
def something(request):
    return Quaternion(request.param)
Exemple #9
0
def identity():
    return Quaternion((1, 0, 0, 0))
Exemple #10
0
def test_multiply_vector(quaternion, vector, expected):
    q = Quaternion(quaternion)
    v = Vector3d(vector)
    v_new = q * v
    assert np.allclose(v_new.data, expected)
Exemple #11
0
    def from_euler(cls, euler, convention="bunge", direction="crystal2lab"):
        """Creates a rotation from an array of Euler angles in radians.

        Parameters
        ----------
        euler : array-like
            Euler angles in radians in the Bunge convention.
        convention : str
            Only "bunge" is supported for new data.
        direction : str
            "lab2crystal" or "crystal2lab".
        """
        conventions = ["bunge", "Krakow_Hielscher"]
        if convention not in conventions:
            raise ValueError(
                f"The chosen convention is not one of the allowed options {conventions}"
            )
        directions = ["lab2crystal", "crystal2lab"]
        if direction not in directions:
            raise ValueError(
                f"The chosen direction is not one of the allowed options {directions}"
            )

        euler = np.array(euler)
        if np.any(np.abs(euler) > 9):
            warnings.warn(
                "Angles are assumed to be in radians, but degrees might have been "
                "passed")
        n = euler.shape[:-1]
        alpha, beta, gamma = euler[..., 0], euler[..., 1], euler[..., 2]

        if convention == "Krakow_Hielscher":
            # To be applied to the data found at:
            # https://www.repository.cam.ac.uk/handle/1810/263510
            alpha -= np.pi / 2
            gamma -= 3 * np.pi / 2
            zero = np.zeros(n)
            qalpha = Quaternion(
                np.stack((np.cos(alpha / 2), zero, zero, np.sin(alpha / 2)),
                         axis=-1))
            qbeta = Quaternion(
                np.stack((np.cos(beta / 2), zero, np.sin(beta / 2), zero),
                         axis=-1))
            qgamma = Quaternion(
                np.stack((np.cos(gamma / 2), zero, zero, np.sin(gamma / 2)),
                         axis=-1))
            data = qalpha * qbeta * qgamma

            rot = cls(data.data)
            rot.improper = zero
            return rot
        elif convention == "bunge":
            # Uses A.5 & A.6 from Modelling Simul. Mater. Sci. Eng. 23
            # (2015) 083501
            sigma = 0.5 * np.add(alpha, gamma)
            delta = 0.5 * np.subtract(alpha, gamma)
            c = np.cos(beta / 2)
            s = np.sin(beta / 2)

            # Using P = 1 from A.6
            q = np.zeros(n + (4, ))
            q[..., 0] = c * np.cos(sigma)
            q[..., 1] = -s * np.cos(delta)
            q[..., 2] = -s * np.sin(delta)
            q[..., 3] = -c * np.sin(sigma)

            for i in [1, 2, 3, 0]:  # flip the zero element last
                q[..., i] = np.where(q[..., 0] < 0, -q[..., i], q[..., i])

            data = Quaternion(q)

            if direction == "lab2crystal":
                data = ~data

            rot = cls(data.data)
            rot.improper = np.zeros((n))
            return rot
Exemple #12
0
    def from_euler(cls, euler, convention="bunge", direction="crystal2lab"):
        """Creates a rotation from an array of Euler angles.

        Parameters
        ----------
        euler : array-like
            Euler angles in the Bunge convention.
        convention : str
            Only 'bunge' is currently supported for new data
        direction : str
            'lab2crystal' or 'crystal2lab'
        """
        if convention not in ["bunge", "Krakow_Hielscher"]:
            raise ValueError("The chosen convention is not one of the allowed options")
        if direction not in ["lab2crystal", "crystal2lab"]:
            raise ValueError("The chosen direction is not one of the allowed options")

        if convention == "Krakow_Hielscher":
            # To be applied to the data found at:
            # https://www.repository.cam.ac.uk/handle/1810/263510
            euler = np.array(euler)
            n = euler.shape[:-1]
            alpha, beta, gamma = euler[..., 0], euler[..., 1], euler[..., 2]
            alpha -= np.pi / 2
            gamma -= 3 * np.pi / 2
            zero = np.zeros(n)
            qalpha = Quaternion(
                np.stack((np.cos(alpha / 2), zero, zero, np.sin(alpha / 2)), axis=-1)
            )
            qbeta = Quaternion(
                np.stack((np.cos(beta / 2), zero, np.sin(beta / 2), zero), axis=-1)
            )
            qgamma = Quaternion(
                np.stack((np.cos(gamma / 2), zero, zero, np.sin(gamma / 2)), axis=-1)
            )
            data = qalpha * qbeta * qgamma

            rot = cls(data.data)
            rot.improper = zero
            return rot

        elif convention == "bunge":
            euler = np.array(euler)
            n = euler.shape[:-1]

            # Uses A.5 & A.6 from Modelling Simul. Mater. Sci. Eng. 23 (2015) 083501

            alpha = euler[..., 0]  # psi1
            beta = euler[..., 1]  # Psi
            gamma = euler[..., 2]  # psi3

            sigma = 0.5 * np.add(alpha, gamma)
            delta = 0.5 * np.subtract(alpha, gamma)
            c = np.cos(beta / 2)
            s = np.sin(beta / 2)

            # Using P = 1 from A.6
            q = np.zeros(n + (4,))
            q[..., 0] = c * np.cos(sigma)
            q[..., 1] = -s * np.cos(delta)
            q[..., 2] = -s * np.sin(delta)
            q[..., 3] = -c * np.sin(sigma)

            for i in [1, 2, 3, 0]:  # flip the zero element last
                q[..., i] = np.where(q[..., 0] < 0, -q[..., i], q[..., i])

            data = Quaternion(q)

            if direction == "lab2crystal":
                data = ~data

            rot = cls(data.data)
            rot.improper = np.zeros((n))
            return rot
Exemple #13
0
def test_check_quat():
    """ check is an oddly named function"""
    quat = Quaternion([2, 2, 2, 2])
    assert np.allclose(quat.data, check_quaternion(quat).data)
Exemple #14
0
def quaternion(request):
    return Quaternion(request.param)
Exemple #15
0
import pytest
from orix.base import DimensionError
from orix.quaternion import Quaternion
from orix.vector import Vector3d

values = [
    (0.707, 0., 0., 0.707),
    (0.5, -0.5, -0.5, 0.5),
    (0., 0., 0., 1.),
    (1., 1., 1., 1.),
    (
        (0.5, -0.5, -0.5, 0.5),
        (0., 0., 0., 1.),
    ),
    Quaternion([
        [(0., 0., 0., 1.), (0.707, 0., 0., 0.707), ],
        [(1., 1., 1., 1.), (0.707, 0., 0., 0.707), ]
    ]),
    np.array((4, 3, 2, 1))
]


@pytest.fixture(params=values)
def quaternion(request):
    return Quaternion(request.param)


@pytest.fixture
def identity():
    return Quaternion((1, 0, 0, 0))

Exemple #16
0
 def __gt__(self, other):
     c = Quaternion(self).dot_outer(Quaternion(other)).data
     inside = np.logical_or(
         np.all(np.greater_equal(c, 0), axis=0), np.all(np.less_equal(c, 0), axis=0)
     )
     return inside
Exemple #17
0
from orix.vector import Vector3d

values = [
    (0.707, 0.0, 0.0, 0.707),
    (0.5, -0.5, -0.5, 0.5),
    (0.0, 0.0, 0.0, 1.0),
    (1.0, 1.0, 1.0, 1.0),
    (
        (0.5, -0.5, -0.5, 0.5),
        (0.0, 0.0, 0.0, 1.0),
    ),
    Quaternion([
        [
            (0.0, 0.0, 0.0, 1.0),
            (0.707, 0.0, 0.0, 0.707),
        ],
        [
            (1.0, 1.0, 1.0, 1.0),
            (0.707, 0.0, 0.0, 0.707),
        ],
    ]),
    np.array((4, 3, 2, 1)),
]


@pytest.fixture(params=values)
def quaternion(request):
    return Quaternion(request.param)


@pytest.fixture
def identity():