Example #1
0
    def fundamental_sector(self):
        from orix.vector.neo_euler import AxAngle
        from orix.vector.spherical_region import SphericalRegion
        symmetry = self.antipodal
        symmetry = symmetry[symmetry.angle > 0]
        axes, order = symmetry.get_highest_order_axis()
        if order > 6:
            return Vector3d.empty()
        axis = Vector3d.zvector().get_nearest(axes, inclusive=True)
        r = Rotation.from_neo_euler(
            AxAngle.from_axes_angles(axis, 2 * np.pi / order))

        diads = symmetry.diads
        nearest_diad = axis.get_nearest(diads)
        if nearest_diad.size == 0:
            nearest_diad = axis.perpendicular

        n1 = axis.cross(nearest_diad).unit
        n2 = -(r * n1)
        next_diad = r * nearest_diad
        n = Vector3d.stack((n1, n2)).flatten()
        sr = SphericalRegion(n.unique())
        inside = symmetry[symmetry.axis < sr]
        if inside.size == 0:
            return sr
        axes, order = inside.get_highest_order_axis()
        axis = axis.get_nearest(axes)
        r = Rotation.from_neo_euler(
            AxAngle.from_axes_angles(axis, 2 * np.pi / order))
        nearest_diad = next_diad
        n1 = axis.cross(nearest_diad).unit
        n2 = -(r * n1)
        n = Vector3d(np.concatenate((n.data, n1.data, n2.data)))
        sr = SphericalRegion(n.unique())
        return sr
Example #2
0
    def get_plot_data(self):
        """
        Produces suitable Rotations for the construction of a wireframe for self
        """
        from orix.vector import Vector3d

        # gets a grid of vector directions
        theta = np.linspace(0, 2 * np.pi - EPSILON, 361)
        rho = np.linspace(0, np.pi - EPSILON, 181)
        theta, rho = np.meshgrid(theta, rho)
        g = Vector3d.from_polar(rho, theta)

        # get the cell vector normal norms
        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
        omega = 2 * np.arctan(np.where(x != 0, x**-1, np.pi))

        # keeps the smallest allowed angle
        omega[omega < 0] = np.pi
        omega = np.min(omega, axis=0)
        r = Rotation.from_neo_euler(AxAngle.from_axes_angles(g.unit, omega))
        return r
Example #3
0
def detector2sample(
    sample_tilt: float,
    detector_tilt: float,
    convention: Optional[str] = None,
) -> Rotation:
    """Rotation U_S to align detector frame D with sample frame S.

    Parameters
    ----------
    sample_tilt
        Sample tilt in degrees.
    detector_tilt
        Detector tilt in degrees.
    convention
        Which sample reference frame to use, either the one used by EDAX
        TSL (default), "tsl", or the one used by Bruker, "bruker".

    Returns
    -------
    Rotation
    """
    # Rotation about sample (microscope) X axis
    tilt = -np.deg2rad((sample_tilt - 90) - detector_tilt)
    ax_angle = neo_euler.AxAngle.from_axes_angles(Vector3d.xvector(), tilt)
    r = Rotation.from_neo_euler(ax_angle)

    if convention != "bruker":
        # Followed by a 90 degree rotation about the sample Z axis,
        # if the TSL sample reference frame is used
        ax_angle_bruker2tsl = neo_euler.AxAngle.from_axes_angles(
            Vector3d.zvector(), np.pi / 2)
        r = Rotation.from_neo_euler(ax_angle_bruker2tsl) * r

    return r.to_matrix()[0]
Example #4
0
    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
Example #5
0
 def get_plot_data(self):
     from orix.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
Example #6
0
    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 orix.quaternion.rotation import Rotation
        from orix.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
Example #7
0
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 detector2sample(sample_tilt: float, detector_tilt: float) -> Rotation:
    """Rotation U_S to align detector frame D with sample frame S.

    Parameters
    ----------
    sample_tilt
        Sample tilt in degrees.
    detector_tilt
        Detector tilt in degrees.

    Returns
    -------
    Rotation
    """
    x_axis = Vector3d.xvector()
    tilt = -np.deg2rad((sample_tilt - 90) - detector_tilt)
    ax_angle = neo_euler.AxAngle.from_axes_angles(x_axis, tilt)
    return Rotation.from_neo_euler(ax_angle).to_matrix()[0]
def get_grid_around_beam_direction(beam_rotation,
                                   resolution,
                                   angular_range=(0, 360)):
    """
    Creates a rotation list of rotations for which the rotation is about given beam direction

    Parameters
    ----------
    beam_rotation : tuple
        A desired beam direction as a rotation (rzxz eulers), usually found via get_rotation_from_z_to_direction

    resolution : float
        The resolution of the grid (degrees)

    angular_range : tuple
        The minimum (included) and maximum (excluded) rotation around the beam direction to be included

    Returns
    -------
    rotation_list : list of tuples

    Example
    -------
    >>> from diffsims.generators.zap_map_generator import get_rotation_from_z_to_direction
    >>> beam_rotation = get_rotation_from_z_to_direction(structure,[1,1,1])
    >>> grid = get_grid_around_beam_direction(beam_rotation,1)
    """
    z = np.deg2rad(np.asarray(beam_rotation))
    beam_rotation = Rotation.from_euler(z,
                                        convention="bunge",
                                        direction="crystal2lab")

    angles = np.deg2rad(
        np.arange(start=angular_range[0],
                  stop=angular_range[1],
                  step=resolution))
    axes = np.repeat([[0, 0, 1]], angles.shape[0], axis=0)
    in_plane_rotation = Rotation.from_neo_euler(
        AxAngle.from_axes_angles(axes, angles))

    orix_grid = beam_rotation * in_plane_rotation
    rotation_list = get_list_from_orix(orix_grid, rounding=2)
    return rotation_list
Example #10
0
def r_tsl2bruker():
    """A rotation from the TSL to Bruker crystal reference frame."""
    return Rotation.from_neo_euler(
        neo_euler.AxAngle.from_axes_angles(Vector3d.zvector(), np.pi / 2))