示例#1
0
    def test_icp_exact(self):
        """Ensure that ICP is exact for corresponding inputs"""
        # Note that we do not bother to test the non-unique matching since we
        # know it provides very poor results.
        np.random.seed(0)

        # First test using unique matching, which should work
        for i in range(2, 6):
            num_points = 2**i

            points = np.random.rand(num_points, 3)
            rotation = from_axis_angle([0.3, 0.3, 0.3], 0.3)
            translation = np.random.rand(1, 3)

            transformed_points = rotate(rotation, points) + translation

            q, t, indices = mapping.icp(points,
                                        transformed_points,
                                        return_indices=True)
            q = from_matrix(q)

            # In the case of just two points, the mapping is not unique,
            # so we don't check the mapping itself, just the result.
            if i > 1:
                self.assertTrue(
                    np.logical_or(
                        np.allclose(rotation, q),
                        np.allclose(rotation, -q),
                    ))
                self.assertTrue(np.allclose(translation, t))
            self.assertTrue(
                np.allclose(transformed_points,
                            rotate(q, points[indices]) + t))
示例#2
0
    def test_icp_mismatched(self):
        """See how ICP works for non-corresponding inputs. Have set some
        reasonable threshold for testing purposes."""
        np.random.seed(0)

        # First test using unique matching, which should work
        for i in range(2, 6):
            num_points = 2**i

            points = np.random.rand(num_points, 3)
            rotation = from_axis_angle([0.3, 0.3, 0.3], 0.3)
            translation = np.random.rand(1, 3)

            permutation = np.random.permutation(num_points)
            transformed_points = rotate(rotation,
                                        points[permutation]) + translation

            q, t, indices = mapping.icp(points,
                                        transformed_points,
                                        return_indices=True)
            q = from_matrix(q)

            deltas = transformed_points - (rotate(q, points[indices]) + t)
            norms = np.linalg.norm(deltas, axis=-1)
            # This is purely a heuristic, since we can't guarantee exact matches
            self.assertTrue(np.mean(norms) < 0.5)
def render(
    args, grid_size=256, output_size=256, draw_x: float = 10, draw_y: float = 10
):
    pipeline = args.scene.selected_pipeline
    if not pipeline:
        return
    data = pipeline.compute(args.frame)
    view_orientation = rowan.from_matrix(args.viewport.viewMatrix[:, :3])
    dp = freud.diffraction.DiffractionPattern(
        grid_size=grid_size,
        output_size=output_size,
    )
    dp.compute(
        system=data,
        view_orientation=view_orientation,
        zoom=1,
        peak_width=1,
    )
    buf = dp.to_image(cmap="afmhot", vmax=np.max(dp.diffraction))
    width, height, bytes_per_pixel = buf.shape
    img = PySide2.QtGui.QImage(
        buf,
        width,
        height,
        width * bytes_per_pixel,
        PySide2.QtGui.QImage.Format_RGBA8888,
    )
    # Paint QImage onto viewport canvas
    args.painter.drawImage(draw_x, draw_y, img)
示例#4
0
    def test_kabsch(self):
        """Perform a rotation and ensure that we can recover it"""
        np.random.seed(0)

        for i in range(1, 12):
            num_points = 2**i

            points = np.random.rand(num_points, 3)
            rotation = random.rand(1)
            translation = np.random.rand(1, 3)

            transformed_points = rotate(rotation, points) + translation

            R, t = mapping.kabsch(points, transformed_points)
            q = from_matrix(R)

            # In the case of just two points, the mapping is not unique,
            # so we don't check the mapping itself, just the result.
            if i > 1:
                self.assertTrue(
                    np.logical_or(
                        np.allclose(rotation, q),
                        np.allclose(rotation, -q),
                    ))
                self.assertTrue(np.allclose(translation, t))
            self.assertTrue(
                np.allclose(transformed_points,
                            rotate(q, points) + t))
示例#5
0
    def test_from_matrix(self):

        self.assertTrue(np.all(rowan.from_matrix(np.eye(3)) == one))

        with self.assertRaises(ValueError):
            self.assertTrue(np.allclose(rowan.from_matrix(2 * np.eye(3))))

        mat = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]])

        self.assertTrue(
            np.logical_or(np.allclose(rowan.from_matrix(mat), half),
                          np.allclose(rowan.from_matrix(mat), -half)))

        mat = np.array([[0, 1, 0], [0, 0, -1], [-1, 0, 0]])
        v = np.copy(half)
        v[3] *= -1
        self.assertTrue(np.allclose(rowan.from_matrix(mat), v))
示例#6
0
 def test_to_from_matrix(self):
     # The equality is only guaranteed up to a sign
     converted = rowan.from_matrix(rowan.to_matrix(input1))
     self.assertTrue(
         np.all(
             np.logical_or(
                 np.isclose(input1 - converted, 0),
                 np.isclose(input1 + converted, 0),
             )))
示例#7
0
 def test_to_from_matrix(self):
     """Test conversion from a quaternion to a matrix and back."""
     # The equality is only guaranteed up to a sign
     converted = rowan.from_matrix(rowan.to_matrix(input1))
     self.assertTrue(
         np.all(
             np.logical_or(
                 np.isclose(input1 - converted, 0),
                 np.isclose(input1 + converted, 0),
             )))
示例#8
0
文件: Scene.py 项目: mkhorton/plato
 def rotation(self):
     camera = self._backend_objects['camera']
     norm_out = np.array(camera.position)
     norm_out /= np.linalg.norm(norm_out)
     norm_up = np.array(camera.up)
     norm_up -= np.dot(norm_up, norm_out) * norm_out
     norm_up /= np.linalg.norm(norm_up)
     norm_right = np.cross(norm_up, norm_out)
     rotation_matrix = np.array([norm_right, norm_up, norm_out]).T
     result = rowan.from_matrix(rotation_matrix, require_orthogonal=False)
     result = rowan.conjugate(result)
     return result
def render(
    args,
    bins: Tuple[int] = (200, 200),
    mode: str = "bod",
    neighbors: dict = {"r_max": 1.4},
    image_size: int = 200,
    draw_x: float = 10,
    draw_y: float = 10,
):
    """Render a bond order diagram that rotates with the view.

    Args:
        args:
            OVITO viewport modifier arguments.
        bins:
            Passed to freud.environment.BondOrder.
        mode:
            Passed to freud.environment.BondOrder.
        neighbors:
            Passed to freud.environment.BondOrder.compute. It is recommended
            to use a cutoff distance at the first trough of the radial
            distribution function g(r). See
            https://freud.readthedocs.io/en/latest/topics/querying.html for
            more information.
        image_size:
            Rendered size of the bond order diagram.
        draw_x:
            X coordinate of the top-left corner of the drawn image.
        draw_y:
            Y coordinate of the top-left corner of the drawn image.

    """
    pipeline = args.scene.selected_pipeline
    if not pipeline:
        return
    data = pipeline.compute(args.frame)
    view_orientation = rowan.from_matrix(args.viewport.viewMatrix[:, :3])
    bod = freud.environment.BondOrder(bins, mode)
    bod.compute(system=data, neighbors=neighbors)
    view = to_view(bod, view_orientation, image_size)
    buf = to_image(view, cmap="afmhot")
    width, height, bytes_per_pixel = buf.shape
    img = PySide2.QtGui.QImage(
        buf,
        width,
        height,
        width * bytes_per_pixel,
        PySide2.QtGui.QImage.Format_RGBA8888,
    )
    # Paint QImage onto viewport canvas
    args.painter.drawImage(draw_x, draw_y, img)
示例#10
0
    def ref_quaternion(self):
        '''Return quaternion for rotating data into occlusal plane.'''
        if self._quaternion is None:
            # 1) start by translating the space so origin sensor is at the origin
            REF = self.ref_translation
            MS = self.sensor_mean_coords(self._molar) + self.ref_translation

            # 2) now find the rotation matrix to the occlusal coordinate system
            z = np.cross(REF, MS)  # z is perpendicular to ms and ref vectors
            z = z / np.linalg.norm(z)

            y = np.cross(MS, z)        # y is perpendicular to z and ms
            y = y / np.linalg.norm(y)

            x = np.cross(y, z)
            x = x / np.linalg.norm(x)

            m = np.array([x, y, z])    # rotation matrix directly
            self._quaternion = rowan.from_matrix(m)
        return self._quaternion
示例#11
0
    def get_basis_vectors(self,
                          base_positions,
                          base_type=[],
                          base_quaternions=None,
                          is_complete=False,
                          apply_orientation=False):
        """Get the basis vectors for the defined crystall structure.

        :param base_positions:
            N by 3 np array of the Wyckoff postions
        :type base_positions:
            np.ndarray
        :param base_type:
            a list of string for particle type name
        :type base_type:
            list
        :param base_quaternions:
            N by 4 np array of quaternions, default None
        :type base_quaternions:
            np.ndarray
        :param is_complete:
            bool value to indicate if the positions are complete postions in a unitcell
        :type is_complete:
            bool
        :param apply_orientations:
            bool value to indicate if the space group symmetry should be applied to orientatioin
        :type apply_orientations:
            bool
        :return:
            basis_vectors
        :rtype:
            np.ndarray
        """

        # check input accuracy
        if not isinstance(base_positions, np.ndarray) or len(base_positions.shape) == 1 \
           or base_positions.shape[1] != 3:
            raise ValueError(
                'base_positions must be an numpy array of shape Nx3')
        if apply_orientation:
            if not isinstance(base_quaternions, np.ndarray) or len(base_quaternions.shape) == 1 \
               or base_quaternions.shape[1] != 4:
                raise ValueError(
                    'base_quaternions must be an numpy array of shape Nx4')
        if len(base_type):
            if not isinstance(base_type, list) or len(base_type) != base_positions.shape[0] \
               or not all(isinstance(i, str) for i in base_type):
                raise ValueError(
                    'base_type must contain a list of type name the same length'
                    'as the number of basis positions')
        else:
            base_type = ['A'] * base_positions.shape[0]

        threshold = 1e-6
        reflection_exist = False
        for i in range(0, len(self.rotations)):
            # Generate the new set of positions from the base
            pos = wrap(self.rotations[i].dot(base_positions.T).T +
                       self.translations[i])
            if apply_orientation:
                if np.linalg.det(self.rotations[i]) == 1:
                    quat_rotate = rowan.from_matrix(self.rotations[i],
                                                    require_orthogonal=False)
                    quat = rowan.multiply(quat_rotate, base_quaternions)
                else:
                    quat = base_quaternions
                    reflection_exist = True

            if i == 0:
                positions = pos
                type_list = copy.deepcopy(base_type)
                if apply_orientation:
                    quaternions = quat
            else:
                pos_comparisons = pos - positions[:, np.newaxis, :]
                norms = np.linalg.norm(pos_comparisons, axis=2)
                comps = np.all(norms > threshold, axis=0)
                positions = np.append(positions, pos[comps], axis=0)
                type_list += [x for x, y in zip(base_type, comps) if y]
                if apply_orientation:
                    quaternions = np.append(quaternions, quat[comps], axis=0)
                    if norms.min() < threshold:
                        print(
                            'Orientation quaterions may have multiple values for the same '
                            'particle postion under the symmetry operation for this space group '
                            'and is not well defined, only the first occurance is used.'
                        )
        if reflection_exist:
            print(
                'Warning: reflection operation is included in this space group, '
                'and is ignored for quaternion calculation.')

        if is_complete and len(positions) != len(base_positions):
            raise ValueError(
                'the complete basis postions vector does not match the space group '
                'chosen. More positions are generated based on the symmetry operation '
                'within the provided space group')

        if apply_orientation:
            return wrap(positions), type_list, quaternions
        else:
            return wrap(positions), type_list
示例#12
0
refl_wgt = calc_XRDreflWeights(structure, hkls, rad='CuKa')
refl_wgt = {0: 1.0, 1: 1.0, 2: 1.0}

omega = np.radians(np.arange(0, 365, 5))
""" symmetry after """

hkls = normalize(np.array(hkls))

symOps = genSym(crystalSym)
symOps = np.unique(np.swapaxes(symOps, 2, 0), axis=0)
""" only use proper rotations """
""" complicated, simplify? """

proper = np.where(np.linalg.det(symOps) == 1)  #proper orthogonal
quatSymOps = quat.from_matrix(symOps[proper])
quatSymOps = np.tile(quatSymOps[:, :, np.newaxis], (1, 1, len(omega)))
quatSymOps = quatSymOps.transpose((2, 0, 1))

sliceIndex = range(omega.shape[0])
""" gen quats from bunge grid """

bungeAngs = np.zeros((np.product(od.phi1cen.shape), 3))

for ii, i in enumerate(np.ndindex(od.phi1cen.shape)):

    bungeAngs[ii, :] = np.array((od.phi1cen[i], od.Phicen[i], od.phi2cen[i]))

qgrid = eu2quat(bungeAngs).T

# %%
    point_group_rotation_matrix_dict[num] = {'rotations': rotations}

with open('point_group_rotation_matrix_dict.pickle', 'wb') as f:
    pickle.dump(point_group_rotation_matrix_dict, f)

point_group_list = [
    '1', '-1', '2', 'm', '2/m', '222', 'mm2', 'mmm', '4', '-4', '4/m', '422',
    '4mm', '-42m', '4/mmm', '3', '-3', '32', '3m', '-3m', '6', '-6', '6/m',
    '622', '6mm', '-6m2', '6/mmm', '23', 'm-3', '432', '-43m', 'm-3m'
]

num = range(1, 33)
point_group_name_dict = dict(zip(num, point_group_list))

with open('point_group_name_mapping.json', 'w') as f:
    json.dump(point_group_name_dict, f)

point_group_quat_dict = {}
for key, item in point_group_rotation_matrix_dict.items():
    quats = []
    n = item['rotations'].shape[0]
    for i in range(0, n):
        qtemp = rowan.from_matrix(item['rotations'][i, :, :],
                                  require_orthogonal=False)
        quats.append(qtemp.tolist())

    point_group_quat_dict[key] = quats

with open('point_group_quat_dict.json', 'w') as f:
    json.dump(point_group_quat_dict, f)
示例#14
0
    def test_zero_beta(self):
        """Check cases where beta is 0."""
        # Since the Euler calculations are all done using matrices, it's easier
        # to construct the test cases by directly using matrices as well. We
        # assume gamma is 0 since, due to gimbal lock, only either alpha+gamma
        # or alpha-gamma is a relevant parameter, and we just scan the other
        # possible values. The actual function is defined such that gamma will
        # always be zero in those cases. We define the matrices using lambda
        # functions to support sweeping a range of values for alpha and beta,
        # specifically to test cases where signs flip e.g. cos(0) vs cos(pi).
        # These sign flips lead to changes in the rotation angles that must be
        # tested.
        mats_euler_intrinsic = [
            ('xzx', 'intrinsic', lambda alpha, beta:
             [[np.cos(beta), 0, 0],
              [0, np.cos(beta) * np.cos(alpha), -np.sin(alpha)],
              [0, np.cos(beta) * np.sin(alpha),
               np.cos(alpha)]]),
            ('xyx', 'intrinsic', lambda alpha, beta:
             [[np.cos(beta), 0, 0],
              [0, np.cos(alpha), -np.cos(beta) * np.sin(alpha)],
              [0, np.sin(alpha),
               np.cos(beta) * np.cos(alpha)]]),
            ('yxy', 'intrinsic', lambda alpha, beta:
             [[np.cos(alpha), 0,
               np.cos(beta) * np.sin(alpha)], [0, np.cos(beta), 0],
              [-np.sin(alpha), 0,
               np.cos(beta) * np.cos(alpha)]]),
            ('yzy', 'intrinsic', lambda alpha, beta:
             [[np.cos(beta) * np.cos(alpha), 0,
               np.sin(alpha)], [0, np.cos(beta), 0],
              [-np.cos(beta) * np.sin(alpha), 0,
               np.cos(alpha)]]),
            ('zyz', 'intrinsic', lambda alpha, beta: [[
                np.cos(beta) * np.cos(alpha), -np.sin(alpha), 0
            ], [np.cos(beta) * np.sin(alpha),
                np.cos(beta), 0], [0, 0, np.cos(beta)]]),
            ('zxz', 'intrinsic', lambda alpha, beta:
             [[np.cos(alpha), -np.cos(beta) * np.sin(alpha), 0],
              [np.sin(alpha), np.cos(beta) * np.cos(beta), 0],
              [0, 0, np.cos(beta)]]),
        ]

        mats_tb_intrinsic = [
            ('xzy', 'intrinsic', lambda alpha, beta: [[0, -np.sin(
                beta), 0], [np.sin(beta) * np.cos(alpha), 0, -np.sin(
                    alpha)], [np.sin(beta) * np.sin(alpha), 0,
                              np.cos(alpha)]]),
            ('xyz', 'intrinsic',
             lambda alpha, beta: [[0, 0, np.sin(
                 beta)], [np.sin(beta) * np.sin(alpha),
                          np.cos(alpha), 0
                          ], [-np.sin(beta) * np.cos(alpha),
                              np.sin(alpha), 0]]),
            ('yxz', 'intrinsic', lambda alpha, beta:
             [[np.cos(alpha), np.sin(beta) * np.sin(alpha), 0],
              [0, 0, -np.sin(beta)],
              [-np.sin(alpha), np.sin(beta) * np.cos(alpha), 0]]),
            ('yzx', 'intrinsic', lambda alpha, beta:
             [[0, -np.sin(beta) * np.cos(alpha),
               np.sin(alpha)], [np.sin(beta), 0, 0],
              [0, np.sin(beta) * np.sin(alpha),
               np.cos(alpha)]]),
            ('zyx', 'intrinsic', lambda alpha, beta: [[
                0, -np.sin(alpha),
                np.sin(beta) * np.cos(alpha)
            ], [0, np.cos(alpha),
                np.sin(beta) * np.sin(alpha)], [-np.sin(beta), 0, 0]]),
            ('zxy', 'intrinsic', lambda alpha, beta: [[
                np.cos(alpha), 0,
                np.sin(beta) * np.sin(alpha)
            ], [np.sin(alpha), 0, -np.sin(beta) * np.cos(alpha)], [0, -1, 0]]),
        ]

        # Extrinsic rotations can be tested identically to intrinsic rotations
        # in the case of proper Euler angles.
        mats_euler_extrinsic = [(m[0], 'extrinsic', m[2])
                                for m in mats_euler_intrinsic]

        # For Tait-Bryan angles, extrinsic rotations axis order must be
        # reversed (since axes 1 and 3 are not identical), but more
        # importantly, due to the sum/difference of alpha and gamma that
        # arises, we need to test the negative of alpha to catch the dangerous
        # cases. In practice we get the same results since we're sweeping alpha
        # values in the tests below, but it's useful to set this up precisely.
        mats_tb_extrinsic = [(m[0][::-1], 'extrinsic', lambda alpha, beta: m[2]
                              (-alpha, beta)) for m in mats_tb_intrinsic]

        # Since angle representations may not be unique, checking that
        # quaternions are equal may not work. Instead we perform rotations and
        # check that they are identical.  For simplicity, we rotate the
        # simplest vector with all 3 components (otherwise tests won't catch
        # the problem because there's no component to rotate).
        test_vector = [1, 1, 1]

        mats_intrinsic = (mats_euler_intrinsic, mats_tb_intrinsic)
        mats_extrinsic = (mats_euler_extrinsic, mats_tb_extrinsic)

        # The beta angles are different for proper Euler angles and Tait-Bryan
        # angles because the relevant beta terms will be sines and cosines,
        # respectively.
        all_betas = ((0, np.pi), (np.pi / 2, -np.pi / 2))
        alphas = (0, np.pi / 2, np.pi, 3 * np.pi / 2)

        for mats in (mats_intrinsic, mats_extrinsic):
            for betas, mat_set in zip(all_betas, mats):
                for convention, axis_type, mat_func in mat_set:
                    quaternions = []
                    for beta in betas:
                        for alpha in alphas:
                            mat = mat_func(alpha, beta)
                            if np.linalg.det(mat) == -1:
                                # Some of these will be improper rotations.
                                continue
                            quat = rowan.from_matrix(mat)
                            quaternions.append(quat)
                            euler = rowan.to_euler(quat, convention, axis_type)
                            converted = rowan.from_euler(*euler,
                                                         convention=convention,
                                                         axis_type=axis_type)
                            correct_rotation = rowan.rotate(quat, test_vector)
                            test_rotation = rowan.rotate(
                                converted, test_vector)
                            self.assertTrue(np.allclose(correct_rotation,
                                                        test_rotation,
                                                        atol=1e-6),
                                            msg="""
                                       Failed for convention {},
                                       axis type {},
                                       alpha = {},
                                       beta = {}.
                                       Expected quaternion: {}.
                                       Calculated: {}.
                                       Expected vector: {}.
                                       Calculated vector: {}.""".format(
                                                convention, axis_type, alpha,
                                                beta, quat, converted,
                                                correct_rotation,
                                                test_rotation))

                    # For completeness, also test with broadcasting.
                    quaternions = np.asarray(quaternions).reshape(-1, 4)
                    all_euler = rowan.to_euler(quaternions, convention,
                                               axis_type)
                    converted = rowan.from_euler(all_euler[...,
                                                           0], all_euler[...,
                                                                         1],
                                                 all_euler[..., 2], convention,
                                                 axis_type)
                    self.assertTrue(
                        np.allclose(rowan.rotate(quaternions, test_vector),
                                    rowan.rotate(converted, test_vector),
                                    atol=1e-6))
示例#15
0
def _regularize_box(position,
                    velocity,
                    orientation,
                    angmom,
                    box_matrix,
                    dtype=None,
                    dimensions=3):
    """Convert box into a right-handed coordinate frame with
    only upper triangular entries. Also convert corresponding
    positions and orientations."""
    # First use QR decomposition to compute the new basis
    Q, R = np.linalg.qr(box_matrix)
    Q = Q.astype(dtype)
    R = R.astype(dtype)

    if not np.allclose(Q[:dimensions, :dimensions], np.eye(dimensions)):
        # If Q is not the identity matrix, then we will be
        # changing data, so we have to copy. This only causes
        # actual failures for non-writeable GSD frames, but could
        # cause unexpected data corruption for other cases
        position = np.copy(position)
        if orientation is not None:
            orientation = np.copy(orientation)
        if velocity is not None:
            velocity = np.copy(velocity)
        if angmom is not None:
            angmom = np.copy(angmom)

        # Since we'll be performing a quaternion operation,
        # we have to ensure that Q is a pure rotation
        sign = np.linalg.det(Q)
        Q = Q * sign
        R = R * sign

        # First rotate positions, velocities.
        # Since they are vectors, we can use the matrix directly.
        # Conveniently, instead of transposing Q we can just reverse
        # the order of multiplication here
        position = position.dot(Q)
        if velocity is not None:
            velocity = velocity.dot(Q)

        # For orientations and angular momenta, we use the quaternion
        quat = rowan.from_matrix(Q.T)
        if orientation is not None:
            for i in range(orientation.shape[0]):
                orientation[i, :] = rowan.multiply(quat, orientation[i, :])
        if angmom is not None:
            for i in range(angmom.shape[0]):
                angmom[i, :] = rowan.multiply(quat, angmom[i, :])

        # Now we have to ensure that the box is right-handed. We
        # do this as a second step to avoid introducing reflections
        # into the rotation matrix before making the quaternion
        signs = np.diag(
            np.diag(np.where(R < 0, -np.ones(R.shape), np.ones(R.shape))))
        box = R.dot(signs)
        position = position.dot(signs)
        if velocity is not None:
            velocity = velocity.dot(signs)
    else:
        box = box_matrix

    # Construct the box
    Lx, Ly, Lz = np.diag(box).flatten().tolist()
    xy = box[0, 1] / Ly
    xz = box[0, 2] / Lz
    yz = box[1, 2] / Lz
    box = Box(Lx=Lx, Ly=Ly, Lz=Lz, xy=xy, xz=xz, yz=yz, dimensions=dimensions)
    return position, velocity, orientation, angmom, box