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) """ beam_rotation = np.deg2rad(beam_rotation) axangle = euler2axangle(beam_rotation[0], beam_rotation[1], beam_rotation[2], "rzxz") rotation_list = None raise NotImplementedError("This functionality will be (re)added in future") return rotation_list
def test_euler_axes(): # Test there and back with all axis specs aba_perms = [(v[0], v[1], v[0]) for v in permutations('xyz', 2)] axis_perms = list(permutations('xyz', 3)) + aba_perms for (a, b, c), mat in zip(euler_tuples, euler_mats): for rs, axes in product('rs', axis_perms): ax_spec = rs + ''.join(axes) conventioned = [EulerFuncs(ax_spec)] if ax_spec in euler.__dict__: conventioned.append(euler.__dict__[ax_spec]) mat = euler2mat(a, b, c, ax_spec) a1, b1, c1 = mat2euler(mat, ax_spec) mat_again = euler2mat(a1, b1, c1, ax_spec) assert_almost_equal(mat, mat_again) quat = euler2quat(a, b, c, ax_spec) a1, b1, c1 = quat2euler(quat, ax_spec) mat_again = euler2mat(a1, b1, c1, ax_spec) assert_almost_equal(mat, mat_again) ax, angle = euler2axangle(a, b, c, ax_spec) a1, b1, c1 = axangle2euler(ax, angle, ax_spec) mat_again = euler2mat(a1, b1, c1, ax_spec) assert_almost_equal(mat, mat_again) for obj in conventioned: mat = obj.euler2mat(a, b, c) a1, b1, c1 = obj.mat2euler(mat) mat_again = obj.euler2mat(a1, b1, c1) assert_almost_equal(mat, mat_again) quat = obj.euler2quat(a, b, c) a1, b1, c1 = obj.quat2euler(quat) mat_again = obj.euler2mat(a1, b1, c1) assert_almost_equal(mat, mat_again) ax, angle = obj.euler2axangle(a, b, c) a1, b1, c1 = obj.axangle2euler(ax, angle) mat_again = obj.euler2mat(a1, b1, c1) assert_almost_equal(mat, mat_again)
def to_AxAngle(self): """ Converts an Euler object to an AxAngle object Returns ------- axangle : diffsims.AxAngle object """ self._check_data() self.data = np.deg2rad(self.data) # for the transform operation if self.axis_convention == 'rzxz' or self.axis_convention =='szxz': stored_axangle = vectorised_euler2axangle(self.data, axes=self.axis_convention) stored_axangle = vectorised_axangle_to_correct_range(stored_axangle) else: # This is very slow from transforms3d.euler import euler2axangle stored_axangle = np.ones((self.data.shape[0], 4)) for i, row in enumerate(self.data): temp_vect, temp_angle = euler2axangle(row[0], row[1], row[2], self.axis_convention) temp_vect, temp_angle = convert_axangle_to_correct_range(temp_vect, temp_angle) for j in [0, 1, 2]: stored_axangle[i, j] = temp_vect[j] stored_axangle[i, 3] = temp_angle # in radians! self.data = np.rad2deg(self.data) # leaves our eulers safe and sound return AxAngle(stored_axangle)
def test_euler_axes(): # Test there and back with all axis specs aba_perms = [(v[0], v[1], v[0]) for v in permutations('xyz', 2)] axis_perms = list(permutations('xyz', 3)) + aba_perms for (a, b, c), mat in zip(euler_tuples, euler_mats): for rs, axes in product('rs', axis_perms): ax_spec = rs + ''.join(axes) conventioned = [EulerFuncs(ax_spec)] if ax_spec in euler.__dict__: conventioned.append(euler.__dict__[ax_spec]) mat = euler2mat(a, b, c, ax_spec) a1, b1, c1 = mat2euler(mat, ax_spec) mat_again = euler2mat(a1, b1, c1, ax_spec) assert_almost_equal(mat, mat_again) quat = euler2quat(a, b, c, ax_spec) a1, b1, c1 = quat2euler(quat, ax_spec) mat_again = euler2mat(a1, b1, c1, ax_spec) assert_almost_equal(mat, mat_again) ax, angle = euler2axangle(a, b, c, ax_spec) a1, b1, c1 = axangle2euler(ax, angle, ax_spec) mat_again = euler2mat(a1, b1, c1, ax_spec) assert_almost_equal(mat, mat_again) for obj in conventioned: mat = obj.euler2mat(a, b, c) a1, b1, c1 = obj.mat2euler(mat) mat_again = obj.euler2mat(a1, b1, c1) assert_almost_equal(mat, mat_again) quat = obj.euler2quat(a, b, c) a1, b1, c1 = obj.quat2euler(quat) mat_again = obj.euler2mat(a1, b1, c1) assert_almost_equal(mat, mat_again) ax, angle = obj.euler2axangle(a, b, c) a1, b1, c1 = obj.axangle2euler(ax, angle) mat_again = obj.euler2mat(a1, b1, c1) assert_almost_equal(mat, mat_again)
def euler2em(ea): ''' :param ea: rotation in euler angles (3,) :return: rotation in expo-map (3,) ''' from transforms3d.euler import euler2axangle axis, theta = euler2axangle(*ea) return np.array(axis * theta)
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) """ beam_rotation = np.deg2rad(beam_rotation) axangle = euler2axangle(beam_rotation[0], beam_rotation[1], beam_rotation[2], 'rzxz') euler_szxz = axangle2euler(axangle[0], axangle[1], 'szxz') # convert to szxz rotation_alpha, rotation_beta = np.rad2deg(euler_szxz[0]), np.rad2deg( euler_szxz[1]) # see _create_advanced_linearly_spaced_array_in_rzxz for details steps_gamma = int( np.ceil((angular_range[1] - angular_range[0]) / resolution)) alpha = np.asarray([rotation_alpha]) beta = np.asarray([rotation_beta]) gamma = np.linspace(angular_range[0], angular_range[1], num=steps_gamma, endpoint=False) z = np.asarray(list(product(alpha, beta, gamma))) raw_grid = Euler( z, axis_convention='szxz' ) # we make use of an uncommon euler angle set here for speed grid_rzxz = raw_grid.to_AxAngle().to_Euler(axis_convention='rzxz') rotation_list = grid_rzxz.to_rotation_list(round_to=2) return rotation_list
def test_axis_angle_from_rpy(self, roll, pitch, yaw): axis2, angle2 = euler2axangle(roll, pitch, yaw) assume(abs(angle2) > SMALL_NUMBER) axis, angle = spw.axis_angle_from_rpy(roll, pitch, yaw) angle = float(angle) axis = np.array(axis).astype(float).T[0] if angle < 0: angle = -angle axis = [-x for x in axis] if angle2 < 0: angle2 = -angle2 axis2 *= -1 compare_axis_angle(angle, axis, angle2, axis2)
def create_sample(edc, structure, angle_start, angle_change): dps = [] for orientation in create_pair(angle_start, angle_change): axis, angle = euler2axangle(orientation[0], orientation[1], orientation[2], 'rzxz') rotation = RotationTransformation(axis, angle, angle_in_radians=True) rotated_structure = rotation.apply_transformation(structure) data = edc.calculate_ed_data( rotated_structure, reciprocal_radius=0.9, #avoiding a reflection issue with_direct_beam=False) dps.append(data.as_signal(2 * half_side_length, 0.025, 1).data) dp = pxm.ElectronDiffraction([dps[0:2], dps[2:]]) dp.set_diffraction_calibration(1 / half_side_length) return dp
def test_axis_angle_from_rpy(self, roll, pitch, yaw): axis2, angle2 = euler2axangle(roll, pitch, yaw) assume(abs(angle2) > SMALL_NUMBER) axis = w.compile_and_execute( lambda r, p, y: w.axis_angle_from_rpy(r, p, y)[0], [roll, pitch, yaw]) angle = w.compile_and_execute( lambda r, p, y: w.axis_angle_from_rpy(r, p, y)[1], [roll, pitch, yaw]) if angle < 0: angle = -angle axis = [-x for x in axis] if angle2 < 0: angle2 = -angle2 axis2 *= -1 compare_axis_angle(angle, axis, angle2, axis2)
def draw(self): axis, theta = _euler.euler2axangle(self.pqr.x, self.pqr.y, self.pqr.z) axis = _vp.vector(axis[0], axis[1], axis[2]) up = _vp.rotate(_vp.vector(0,1,0), theta, axis) self.body.pos = self.xyz self.top.pos = self.xyz + up*_size self.prop1.pos = self.xyz + _vp.rotate(_vp.vector(1.3*_size,0,0), theta, axis) self.prop2.pos = self.xyz + _vp.rotate(_vp.vector(0,0,1.3*_size), theta, axis) self.prop3.pos = self.xyz + _vp.rotate(_vp.vector(-1.3*_size,0,0), theta, axis) self.prop4.pos = self.xyz + _vp.rotate(_vp.vector(0,0,-1.3*_size), theta, axis) self.prop1.axis = up self.prop2.axis = up self.prop3.axis = up self.prop4.axis = up if _follow_drone: canvas.center = self.xyz canvas.caption = 'time = %0.1f, pos = (%0.1f, %0.1f, %0.1f), energy = %0.1f' % (time, self.xyz.x, self.xyz.y, self.xyz.z, self.energy)
def _euler2axangle_signal(euler): """Converts an Euler triple into the axis-angle representation. Parameters ---------- euler : np.array() Euler angles for a rotation. Returns ------- asangle : np.array() Axis-angle representation of the rotation. """ euler = euler[ 0] # TODO: euler is a 1-element ndarray(dtype=object) with a tuple return np.rad2deg(euler2axangle(euler[0], euler[1], euler[2])[1])
def update(self, dt): # forces axis, theta = _euler.euler2axangle(self.pqr.x, self.pqr.y, self.pqr.z) axis = _vp.vector(axis[0], axis[1], axis[2]) up = _vp.rotate(_vp.vector(0,1,0), theta, axis) a = _vp.vector(0, -_gravity, 0) a = a + (self.thrust1+self.thrust2+self.thrust3+self.thrust4)/self.mass * up + self.wind/self.mass a = a - (_lin_drag_coef * _vp.mag(self.xyz_dot)**2)/self.mass * self.xyz_dot self.xyz_dot = self.xyz_dot + a * dt # torques (ignoring propeller torques) cg = self.cgpos * up tpos1 = _vp.rotate(_vp.vector(1.3*_size,0,0), theta, axis) tpos2 = _vp.rotate(_vp.vector(0,0,1.3*_size), theta, axis) tpos3 = _vp.rotate(_vp.vector(-1.3*_size,0,0), theta, axis) tpos4 = _vp.rotate(_vp.vector(0,0,-1.3*_size), theta, axis) torque = _vp.cross(cg, _vp.vector(0, -_gravity, 0)) torque = torque + _vp.cross(tpos1, self.thrust1 * up) torque = torque + _vp.cross(tpos2, self.thrust2 * up) torque = torque + _vp.cross(tpos3, self.thrust3 * up) torque = torque + _vp.cross(tpos4, self.thrust4 * up) torque = torque - _rot_drag_coef * self.pqr_dot aa = torque/self.inertia if _vp.mag(aa) > 0: aai, aaj, aak = _euler.axangle2euler((aa.x, aa.y, aa.z), _vp.mag(aa)) aa = _vp.vector(aai, aaj, aak) self.pqr_dot = self.pqr_dot + aa * dt else: self.pqr_dot = _vp.vector(0,0,0) # ground interaction if self.xyz.y <= 0: self.xyz.y = 0 if self.xyz_dot.y <= 0: self.xyz_dot.x = self.xyz_dot.x * _ground_friction self.xyz_dot.y = 0 self.xyz_dot.z = self.xyz_dot.z * _ground_friction self.pqr_dot = self.pqr_dot * _ground_friction # energy update self.energy += _power_coef * (self.thrust1**1.5 + self.thrust2**1.5 + self.thrust3**1.5 + self.thrust4**1.5) * dt # time update self.xyz += self.xyz_dot * dt self.pqr += self.pqr_dot * dt # callback if self.updated is not None: self.updated(self) self.draw()
def _euler2axangle_signal(euler): """ Find the magnitude of a rotation""" return np.array(euler2axangle(euler[0], euler[1], euler[2])[1])
def euler2axangle_signal(euler): return np.array(euler2axangle(euler[0], euler[1], euler[2])[1])
def get_diffraction_library(self, structure_library, calibration, reciprocal_radius, representation='euler'): """Calculates a dictionary of diffraction data for a library of crystal structures and orientations. Each structure in the structure library is rotated to each associated orientation and the diffraction pattern is calculated each time. Parameters ---------- structure_library : dict Dictionary of structures and associated orientations (represented as Euler angles or axis-angle pairs) for which electron diffraction is to be simulated. calibration : float The calibration of experimental data to be correlated with the library, in reciprocal Angstroms per pixel. reciprocal_radius : float The maximum g-vector magnitude to be included in the simulations. representation : 'euler' or 'axis-angle' The representation in which the orientations are provided. If 'euler' the zxz convention is taken and values are in radians, if 'axis-angle' the rotational angle is in degrees. Returns ------- diffraction_library : dict of :class:`DiffractionSimulation` Mapping of crystal structure and orientation to diffraction data objects. """ # Define DiffractionLibrary object to contain results diffraction_library = DiffractionLibrary() # The electron diffraction calculator to do simulations diffractor = self.electron_diffraction_calculator # Iterate through phases in library. for key in structure_library.keys(): phase_diffraction_library = dict() structure = structure_library[key][0] orientations = structure_library[key][1] # Iterate through orientations of each phase. for orientation in tqdm(orientations, leave=False): if representation=='axis-angle': axis = [orientation[0], orientation[1], orientation[2]] angle = orientation[3] / 180 * pi if representation=='euler': axis, angle = euler2axangle(orientation[0], orientation[1], orientation[2], 'rzxz') # Apply rotation to the structure rotation = RotationTransformation(axis, angle, angle_in_radians=True) rotated_structure = rotation.apply_transformation(structure) # Calculate electron diffraction for rotated structure data = diffractor.calculate_ed_data(rotated_structure, reciprocal_radius) # Calibrate simulation data.calibration = calibration # Construct diffraction simulation library. phase_diffraction_library[tuple(orientation)] = data diffraction_library[key] = phase_diffraction_library return diffraction_library
def euler_from_as(self, roll, pitch, yaw): rot_vec_as, theta = euler.euler2axangle(roll, pitch, yaw) rot_vec = self.vel3d_from_as(rot_vec_as) r, p, y = euler.axangle2euler(rot_vec, theta) return r, p, y
def get_diffraction_library(self, structure_library, calibration, reciprocal_radius, half_shape, representation='euler', with_direct_beam=True): """Calculates a dictionary of diffraction data for a library of crystal structures and orientations. Each structure in the structure library is rotated to each associated orientation and the diffraction pattern is calculated each time. Parameters ---------- structure_library : dict Dictionary of structures and associated orientations (represented as Euler angles or axis-angle pairs) for which electron diffraction is to be simulated. calibration : float The calibration of experimental data to be correlated with the library, in reciprocal Angstroms per pixel. reciprocal_radius : float The maximum g-vector magnitude to be included in the simulations. representation : 'euler' or 'axis-angle' The representation in which the orientations are provided. If 'euler' the zxz convention is taken and values are in radians, if 'axis-angle' the rotational angle is in degrees. half_shape: tuple The half shape of the target patterns, for 144x144 use (72,72) etc Returns ------- diffraction_library : dict of :class:`DiffractionSimulation` Mapping of crystal structure and orientation to diffraction data objects. """ # Define DiffractionLibrary object to contain results diffraction_library = DiffractionLibrary() # The electron diffraction calculator to do simulations diffractor = self.electron_diffraction_calculator # Iterate through phases in library. for key in structure_library.keys(): phase_diffraction_library = dict() structure = structure_library[key][0] orientations = structure_library[key][1] # Iterate through orientations of each phase. for orientation in tqdm(orientations, leave=False): if representation == 'axis-angle': axis = [orientation[0], orientation[1], orientation[2]] angle = orientation[3] / 180 * pi if representation == 'euler': axis, angle = euler2axangle(orientation[0], orientation[1], orientation[2], 'rzxz') # Apply rotation to the structure rotation = RotationTransformation(axis, angle, angle_in_radians=True) rotated_structure = rotation.apply_transformation(structure) # Calculate electron diffraction for rotated structure data = diffractor.calculate_ed_data(rotated_structure, reciprocal_radius, with_direct_beam) # Calibrate simulation data.calibration = calibration pattern_intensities = data.intensities pixel_coordinates = np.rint( data.calibrated_coordinates[:, :2] + half_shape).astype(int) # Construct diffraction simulation library, removing those that contain no peaks if len(pattern_intensities) > 0: phase_diffraction_library[tuple(orientation)] = \ {'Sim':data,'intensities':pattern_intensities, \ 'pixel_coords':pixel_coordinates, \ 'pattern_norm': np.sqrt(np.dot(pattern_intensities,pattern_intensities))} diffraction_library[key] = phase_diffraction_library return diffraction_library
# This file is part of diffsims. # # diffsims is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # diffsims is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with diffsims. If not, see <http://www.gnu.org/licenses/>. """ These utils provide vectorised implementations of conversions as described in the package transforms3d. Currently avaliable are: euler2quat quat2axangle euler2axangle (via chaining of the above) axangle2mat mat2euler axangle2euler (via chaining of the above) It also provides two implementations (one vectorised) that convert axis-angles pairs to the correct angular ranges
def exp_map(v): vec, angle = euler.euler2axangle(*map(convert, v)) return angle * vec