def from_symmetry(cls, s1, s2=C1): """The set of unique (mis)orientations of a symmetrical object. Parameters ---------- s1, s2 : Symmetry """ s1, s2 = get_proper_groups(s1, s2) large_cell_normals = _get_large_cell_normals(s1, s2) disjoint = s1 & s2 # if s1._tuples == s2._tuples: # disjoint = disjoint.laue fundamental_sector = disjoint.fundamental_sector() fundamental_sector_normals = Rotation.from_neo_euler( AxAngle.from_axes_angles(fundamental_sector, np.pi)) normals = Rotation( np.concatenate( [large_cell_normals.data, fundamental_sector_normals.data])) orientation_region = cls(normals) vertices = orientation_region.vertices() if vertices.size: orientation_region = orientation_region[np.any(np.isclose( orientation_region.dot_outer(vertices).data, 0), axis=1)] return orientation_region
def test_antipodal(rotation, improper): rotation = Rotation(rotation) rotation.improper = improper a = rotation.antipodal assert np.allclose(a[0].data, rotation.data) assert np.allclose(a[1].data, -rotation.data) assert np.allclose(a[0].improper, rotation.improper) assert np.allclose(a[1].improper, rotation.improper)
def rotate(self, axis=None, angle=0): """Convenience function for rotating this vector. Shapes of 'axis' and 'angle' must be compatible with shape of this vector for broadcasting. Parameters ---------- axis : Vector3d or array_like, optional The axis of rotation. Defaults to the z-vector. angle : array_like, optional The angle of rotation, in radians. Returns ------- Vector3d A new vector with entries rotated. Examples -------- >>> from math import pi >>> v = Vector3d((0, 1, 0)) >>> axis = Vector3d((0, 0, 1)) >>> angles = [0, pi/4, pi/2, 3*pi/4, pi] >>> v.rotate(axis=axis, angle=angles) """ from texpy.quaternion.rotation import Rotation from texpy.vector.neo_euler import AxAngle axis = Vector3d.zvector() if axis is None else axis angle = 0 if angle is None else angle q = Rotation.from_neo_euler(AxAngle.from_axes_angles(axis, angle)) return q * self
def get_plot_data(self): from texpy.vector import Vector3d theta = np.linspace(0, 2 * np.pi + 1e-9, 361) rho = np.linspace(0, np.pi, 181) theta, rho = np.meshgrid(theta, rho) g = Vector3d.from_polar(rho, theta) n = Rodrigues.from_rotation(self).norm.data[:, np.newaxis, np.newaxis] if n.size == 0: return Rotation.from_neo_euler(AxAngle.from_axes_angles(g, np.pi)) d = (-self.axis).dot_outer(g.unit).data x = n * d x = 2 * np.arctan(x**-1) x[x < 0] = np.pi x = np.min(x, axis=0) r = Rotation.from_neo_euler(AxAngle.from_axes_angles(g.unit, x)) return r
def faces(self): normals = Rotation(self) vertices = self.vertices() faces = [] for n in normals: faces.append(vertices[np.isclose(vertices.dot(n).data, 0)]) faces = [f for f in faces if f.size > 2] return faces
def vertices(self): """The vertices of the asymmetric domain. Returns ------- Rotation """ normal_combinations = list(itertools.combinations(self, 3)) if len(normal_combinations) < 1: return Rotation.empty() c1, c2, c3 = zip(*normal_combinations) c1, c2, c3 = Rotation.stack(c1).flatten(), Rotation.stack( c2).flatten(), Rotation.stack(c3).flatten() v = Rotation.triple_cross(c1, c2, c3) v = v[~np.any(np.isnan(v.data), axis=-1)] v = v[v < self].unique() surface = np.any(np.isclose(v.dot_outer(self).data, 0), axis=1) return v[surface]
def _get_large_cell_normals(s1, s2): dp = get_distinguished_points(s1, s2) normals = Rodrigues.zero(dp.shape + (2, )) planes1 = dp.axis * np.tan(dp.angle.data / 4) planes2 = -dp.axis * np.tan(dp.angle.data / 4)**-1 planes2.data[np.isnan(planes2.data)] = 0 normals[:, 0] = planes1 normals[:, 1] = planes2 normals: Rotation = Rotation.from_neo_euler(normals).flatten().unique( antipodal=False) if not normals.size: return normals _, inv = normals.axis.unique(return_inverse=True) axes_unique = [] angles_unique = [] for i in np.unique(inv): n = normals[inv == i] axes_unique.append(n.axis.data[0]) angles_unique.append(n.angle.data.max()) normals = Rotation.from_neo_euler( AxAngle.from_axes_angles(np.array(axes_unique), angles_unique)) return normals
def test_mul_rotation(r1, i1, r2, i2, expected, expected_i): r1 = Rotation(r1) r1.improper = i1 r2 = Rotation(r2) r2.improper = i2 r = r1 * r2 assert isinstance(r, Rotation) assert np.allclose(r.data, expected) assert np.all(r.improper == expected_i)
def loadang(file_string: str): """Load ``.ang`` files. Parameters ---------- file_string : str Path to the ``.ang`` file. This file is assumed to list the Euler angles in the Bunge convention in the first three columns. Returns ------- Rotation """ from texpy.quaternion.rotation import Rotation data = np.loadtxt(file_string) euler = data[:, :3] rotation = Rotation.from_euler(euler) return rotation
def loadctf(file_string: str): """Load ``.ang`` files. Parameters ---------- file_string : str Path to the ``.ctf`` file. This file is assumed to list the Euler angles in the Bunge convention in the columns 5, 6, and 7. Returns ------- Rotation """ from texpy.quaternion.rotation import Rotation data = np.loadtxt(file_string, skiprows=17)[:, 5:8] euler = np.radians(data) rotation = Rotation.from_euler(euler) return rotation
def test_random_vonmises(shape, reference): r = Rotation.random_vonmises(shape, 1., reference) assert r.shape == shape assert isinstance(r, Rotation)
def rotation(request): return Rotation(request.param)
from math import cos, sin, tan, pi import numpy as np import pytest import itertools from texpy.quaternion import Quaternion from texpy.quaternion.rotation import Rotation from texpy.vector import Vector3d rotations = [(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.), ), Rotation([(2, 4, 6, 8), (-1, -2, -3, -4)]), np.array((4, 3, 2, 1))] quaternions = [(0.881, 0.665, 0.123, 0.517), (0.111, 0.222, 0.333, 0.444), ( (1, 0, 0.5, 0), (3, 1, -1, -2), ), [[ [0.343, 0.343, 0, -0.333], [-7, -8, -9, -10], ], [[0.00001, -0.0001, 0.001, -0.01], [0, 0, 0, 0]]]] vectors = [(1, 0, 0), (1, 1, 0), (0.7, 0.8, 0.9), [ [1, 1, 1], [0.4, 0.5, -0.6],
@pytest.fixture(params=axangles[:100]) def axangle(request): return AxAngle(request.param.data) def test_angle(axangle): assert np.allclose(axangle.angle.data, axangle.norm.data) def test_axis(axangle): assert axangle.axis.shape == axangle.shape @pytest.mark.parametrize('axis, angle, expected_axis', [((2, 1, 1), np.pi / 4, (0.816496, 0.408248, 0.408248)), (Vector3d((2, 0, 0)), -2 * np.pi, (-1, 0, 0))]) def test_from_axes_angles(axis, angle, expected_axis): ax = AxAngle.from_axes_angles(axis, angle) assert np.allclose(ax.axis.data, expected_axis) assert np.allclose(ax.angle.data, abs(angle)) @pytest.mark.parametrize('rotation, expected', [(Rotation([1, 0, 0, 0]), [0, 0, 0]), (Rotation([0, 1, 0, 0]), [np.pi, 0, 0])]) def test_from_rotation(rotation, expected): axangle = AxAngle.from_rotation(rotation) assert np.allclose(axangle.data, expected)
import pytest import numpy as np from texpy.vector.neo_euler import Rodrigues from texpy.quaternion.rotation import Rotation @pytest.mark.parametrize('rotation, expected', [ (Rotation([1, 0, 0, 0]), [0, 0, 0]), (Rotation([0.9239, 0.2209, 0.2209, 0.2209]), [0.2391, 0.2391, 0.2391]), ]) def test_from_rotation(rotation, expected): rodrigues = Rodrigues.from_rotation(rotation) assert np.allclose(rodrigues.data, expected, atol=1e-4) @pytest.mark.parametrize('rodrigues, expected', [ (Rodrigues([0.2391, 0.2391, 0.2391]), np.pi / 4), ]) def test_angle(rodrigues, expected): angle = rodrigues.angle assert np.allclose(angle.data, expected, atol=1e-3)