def get_beam_directions_grid(crystal_system, resolution, mesh="spherified_cube_edge"): """Produces an array of beam directions, within the stereographic triangle of the relevant crystal system. The way the array is constructed is based on different methods of meshing the sphere [Cajaravelli2015]_ and can be specified through the `mesh` argument. Parameters ---------- crystal_system : str Allowed are: 'cubic','hexagonal','trigonal','tetragonal', 'orthorhombic','monoclinic','triclinic' resolution : float An angle in degrees representing the worst-case angular distance to a first nearest neighbor grid point. mesh : str Type of meshing of the sphere that defines how the grid is created. Options are: uv_sphere, normalized_cube, spherified_cube_corner (default), spherified_cube_edge, icosahedral, random. Returns ------- rotation_list : list of tuples """ if mesh == "uv_sphere": points_in_cartesians = get_uv_sphere_mesh_vertices(resolution) elif mesh == "spherified_cube_corner": points_in_cartesians = get_cube_mesh_vertices( resolution, grid_type="spherified_corner") elif mesh == "icosahedral": points_in_cartesians = get_icosahedral_mesh_vertices(resolution) elif mesh == "normalized_cube" or mesh == "spherified_cube_edge": # special case: hexagon is a very small slice and 001 point can # be isolated. Hence we increase resolution to ensure minimum angle. if crystal_system == "hexagonal": resolution = resolution / np.sqrt(2) if mesh == "normalized_cube": points_in_cartesians = get_cube_mesh_vertices( resolution, grid_type="normalized") else: points_in_cartesians = get_cube_mesh_vertices( resolution, grid_type="spherified_edge") elif mesh == "random": points_in_cartesians = get_random_sphere_vertices(resolution) else: raise NotImplementedError( f"The mesh {mesh} is not recognized. " f"Please use: uv_sphere, normalized_cube, " f"spherified_cube_edge, " f"spherified_cube_corner, icosahedral, random") # crop to stereographic triangle which depends on crystal system epsilon = -1e-13 if crystal_system == "triclinic": return beam_directions_grid_to_euler(points_in_cartesians) if crystal_system == "monoclinic": points_in_cartesian = points_in_cartesians[ np.dot(np.array([0, 0, 1]), points_in_cartesians.T) >= epsilon] points_in_cartesian = points_in_cartesians[ np.dot(np.array([1, 0, 0]), points_in_cartesians.T) >= epsilon] return beam_directions_grid_to_euler(points_in_cartesian) # for all other systems, determine it from the triangle vertices corners = crystal_system_dictionary[crystal_system] a, b, c = corners[0], corners[1], corners[2] if len(a) == 4: a, b, c = uvtw_to_uvw(a), uvtw_to_uvw(b), uvtw_to_uvw(c) # eliminates those points that lie outside of the stereographic triangle points_in_cartesians = points_in_cartesians[ np.dot(np.cross(a, b), c) * np.dot(np.cross(a, b), points_in_cartesians.T) >= epsilon] points_in_cartesians = points_in_cartesians[ np.dot(np.cross(b, c), a) * np.dot(np.cross(b, c), points_in_cartesians.T) >= epsilon] points_in_cartesians = points_in_cartesians[ np.dot(np.cross(c, a), b) * np.dot(np.cross(c, a), points_in_cartesians.T) >= epsilon] angle_grid = beam_directions_grid_to_euler(points_in_cartesians) return angle_grid
def test_uvtw_to_uvw(uvtw, uvw): val = uvtw_to_uvw(uvtw) np.testing.assert_almost_equal(val, uvw)