Beispiel #1
0
def test_multiple_getter_with_conversion():
    # test N successive coordinate conversions
    N = 500

    # get list of available coordinate systems
    coords = Coordinates()
    systems = coords._systems()

    # get reference points in cartesian coordinate system
    points = [
        'positive_x', 'positive_y', 'positive_z', 'negative_x', 'negative_y',
        'negative_z'
    ]
    pts = np.array([systems['cart']['right'][point] for point in points])

    # init the system
    coords.set_cart(pts[:, 0], pts[:, 1], pts[:, 2])

    # list of domains
    domains = list(systems)

    for ii in range(N):
        # randomly select a coordinate system
        domain = domains[np.random.randint(len(domains))]
        conventions = list(systems[domain])
        convention = conventions[np.random.randint(len(conventions))]
        # convert points to selected system
        pts = eval(f"coords.get_{domain}('{convention}', convert=True)")
        # get the reference
        ref = np.array(
            [systems[domain][convention][point] for point in points])
        # check
        npt.assert_allclose(pts, ref, atol=1e-15)
        # print
        print(f"Tolerance met in iteration {ii}")
Beispiel #2
0
def test_coordinates_init_val_and_weights():
    # correct number of weights
    coords = Coordinates([1, 2], 0, 0, weights=[.5, .5])
    assert isinstance(coords, Coordinates)

    # incorrect number of weights
    with raises(AssertionError):
        Coordinates([1, 2], 0, 0, weights=.5)
Beispiel #3
0
def test_coordinates_init_val_no_convention_no_unit():
    # get list of available coordinate systems
    coords = Coordinates()
    systems = coords._systems()

    # test constructor with all systems, units, and convention=None
    for domain in systems:
        Coordinates(0, 0, 0, domain)
Beispiel #4
0
def test_systems():
    # get class instance
    coords = Coordinates()

    # test all four possible calls
    coords.systems()
    coords.systems(brief=True)
    coords.systems('all')
    coords.systems('all', brief=True)
Beispiel #5
0
def test_csize():
    # 0 points
    coords = Coordinates()
    assert coords.csize == 0
    # two points
    coords = Coordinates([1, 0], 1, 1)
    assert coords.csize == 2
    # 6 points in two dimensions
    coords = Coordinates([[1, 2, 3], [4, 5, 6]], 1, 1)
    assert coords.csize == 6
Beispiel #6
0
def test_cdim():
    # empty
    coords = Coordinates()
    assert coords.cdim == 0
    # 2D points
    coords = Coordinates([1, 0], 1, 1)
    assert coords.cdim == 1
    # 3D points
    coords = Coordinates([[1, 2, 3], [4, 5, 6]], 1, 1)
    assert coords.cdim == 2
Beispiel #7
0
def test_cshape():
    # empty
    coords = Coordinates()
    assert coords.cshape == (0, )
    # 2D points
    coords = Coordinates([1, 0], [1, 1], [0, 1])
    assert coords.cshape == (2, )
    # 3D points
    coords = Coordinates([[1, 2, 3], [4, 5, 6]], 1, 1)
    assert coords.cshape == (2, 3)
Beispiel #8
0
def test_coordinates_init_val_no_convention():
    # get list of available coordinate systems
    coords = Coordinates()
    systems = coords._systems()

    # test constructor with all systems, units, and convention=None
    for domain in systems:
        convention = list(systems[domain])[0]
        for unit in systems[domain][convention]['units']:
            Coordinates(0, 0, 0, domain, unit=unit[0][0:3])
Beispiel #9
0
def test_coordinates_init_val_and_system():
    # get list of available coordinate systems
    coords = Coordinates()
    systems = coords._systems()

    # test constructor with all systems
    for domain in systems:
        for convention in systems[domain]:
            for unit in systems[domain][convention]['units']:
                Coordinates(0, 0, 0, domain, convention, unit[0][0:3])
Beispiel #10
0
def test_getitem():
    # test without weights
    coords = Coordinates([1, 2], 0, 0)
    new = coords[0]
    assert isinstance(new, Coordinates)
    assert (new.get_cart().flatten() == np.array([1, 0, 0])).all()

    # test with weights
    coords = Coordinates([1, 2], 0, 0, weights=[.1, .9])
    new = coords[0]
    assert isinstance(new, Coordinates)
    assert (new.get_cart().flatten() == np.array([1, 0, 0])).all()
    assert new.weights.flatten() == np.array(.1)

    # test with 3D array
    coords = Coordinates([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6]], 0, 0)
    new = coords[0:1]
    assert isinstance(new, Coordinates)
    assert new.cshape == (1, 5)

    # test if sliced object stays untouched
    coords = Coordinates([0, 1], [0, 1], [0, 1])
    new = coords[0]
    new.set_cart(2, 2, 2)
    assert coords.cshape == (2, )
    npt.assert_allclose(coords.get_cart()[0], np.array([0, 0, 0]))
Beispiel #11
0
def test_show():
    coords = Coordinates([-1, 0, 1], 0, 0)
    # show without mask
    coords.show()
    # show with mask as list
    coords.show([1, 0, 1])
    # show with mask as ndarray
    coords.show(np.array([1, 0, 1], dtype=bool))
    # test assertion
    with raises(AssertionError):
        coords.show(np.array([1, 0], dtype=bool))
Beispiel #12
0
def test___eq___differInUnit_notEqual():
    coordinates = Coordinates([1, 1], [1, 1], [1, 1],
                              convention='top_colat',
                              domain='sph',
                              unit='rad')
    actual = Coordinates([1, 1], [1, 1], [1, 1],
                         convention='top_colat',
                         domain='sph',
                         unit='deg')
    is_equal = coordinates == actual
    assert not is_equal
Beispiel #13
0
def test_setter_and_getter_with():
    # get list of available coordinate systems
    coords = Coordinates()
    systems = coords._systems()
    # test points contained in system definitions
    points = [
        'positive_x', 'positive_y', 'positive_z', 'negative_x', 'negative_y',
        'negative_z'
    ]

    # test setter and getter with all systems and default unit
    for domain_in in list(systems):
        for convention_in in list(systems[domain_in]):
            for domain_out in list(systems):
                for convention_out in list(systems[domain_out]):
                    for point in points:
                        # for debugging
                        print(f"{domain_in}({convention_in}) -> "
                              f"{domain_out}({convention_out}): {point}")
                        # in and out points
                        p_in = systems[domain_in][convention_in][point]
                        p_out = systems[domain_out][convention_out][point]
                        # empty object
                        c = Coordinates()
                        # --- set point ---
                        eval(f"c.set_{domain_in}(p_in[0], p_in[1], p_in[2], \
                             '{convention_in}')")
                        # check point
                        p = c._points
                        npt.assert_allclose(p.flatten(), p_in, atol=1e-15)
                        # --- test without conversion ---
                        p = eval(f"c.get_{domain_out}('{convention_out}')")
                        # check internal and returned point
                        npt.assert_allclose(c._points.flatten(),
                                            p_in,
                                            atol=1e-15)
                        npt.assert_allclose(p.flatten(), p_out, atol=1e-15)
                        # check if system was converted
                        assert c._system["domain"] == domain_in
                        assert c._system["convention"] == convention_in
                        # --- test with conversion ---
                        p = eval(f"c.get_{domain_out}('{convention_out}', \
                                 convert=True)")
                        # check point
                        npt.assert_allclose(p.flatten(), p_out, atol=1e-15)
                        # check if system was converted
                        assert c._system["domain"] == domain_out
                        assert c._system["convention"] == convention_out
Beispiel #14
0
def sph_icosahedron(radius=1.):
    """
    Generate a sampling from the center points of the twenty icosahedron faces.

    Parameters
    ----------
    radius : number, optional
        Radius of the sampling grid. The default is 1.

    Returns
    -------
    sampling : Coordinates
        Sampling positions as Coordinate object

    """
    gamma_R_r = np.arccos(np.cos(np.pi / 3) / np.sin(np.pi / 5))
    gamma_R_rho = np.arccos(1 / (np.tan(np.pi / 5) * np.tan(np.pi / 3)))

    theta = np.tile(
        np.array([
            np.pi - gamma_R_rho, np.pi - gamma_R_rho - 2 * gamma_R_r,
            2 * gamma_R_r + gamma_R_rho, gamma_R_rho
        ]), 5)
    theta = np.sort(theta)
    phi = np.arange(0, 2 * np.pi, 2 * np.pi / 5)
    phi = np.concatenate((np.tile(phi, 2), np.tile(phi + np.pi / 5, 2)))

    rad = radius * np.ones(20)
    sampling = Coordinates(phi,
                           theta,
                           rad,
                           domain='sph',
                           convention='top_colat',
                           comment='icosahedral spherical sampling grid')
    return sampling
Beispiel #15
0
def sph_equal_area(n_points, radius=1.):
    """Sampling based on partitioning into faces with equal area [1]_.

    Parameters
    ----------
    n_points : int
        Number of points corresponding to the number of partitions of the
        sphere.
    radius : number, optional
        radius of the sampling grid in meters. The default is 1.

    Returns
    -------
    sampling : Coordinates
        Sampling positions as Coordinate object

    References
    ----------
    .. [1]  P. Leopardi, “A partition of the unit sphere into regions of equal
            area and small diameter,” Electronic Transactions on Numerical
            Analysis, vol. 25, no. 12, pp. 309–327, 2006.

    """

    point_set = external.eq_point_set(2, n_points)
    sampling = Coordinates(point_set[0] * radius,
                           point_set[1] * radius,
                           point_set[2] * radius,
                           domain='cart',
                           convention='right',
                           comment='Equal area partitioning of the sphere.')

    return sampling
Beispiel #16
0
def sphericalvoronoi():
    """ SphericalVoronoi object.
    """
    points = np.array(
        [[0, 0, 1], [0, 0, -1], [1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]])
    sampling = Coordinates(points[:, 0], points[:, 1], points[:, 2])
    return SphericalVoronoi(sampling)
Beispiel #17
0
def test_coordinate_names():
    # check if units agree across coordinates that appear more than once

    # get all coordinate systems
    c = Coordinates()
    systems = c._systems()

    # get unique list of coordinates and their properties
    coords = {}
    # loop across domains and conventions
    for domain in systems:
        for convention in systems[domain]:
            # loop across coordinates
            for cc, coord in enumerate(
                    systems[domain][convention]['coordinates']):
                # units of the current coordinate
                cur_units = [
                    u[cc] for u in systems[domain][convention]['units']
                ]
                # add coordinate to coords
                if coord not in coords:
                    coords[coord] = {}
                    coords[coord]['domain'] = [domain]
                    coords[coord]['convention'] = [convention]
                    coords[coord]['units'] = [cur_units]
                else:
                    coords[coord]['domain'].append(domain)
                    coords[coord]['convention'].append(convention)
                    coords[coord]['units'].append(cur_units)

    # check if units agree across coordinates that appear more than once
    for coord in coords:
        # get unique first entry
        units = coords[coord]['units'].copy()
        units_ref, idx = np.unique(units[0], True)
        units_ref = units_ref[idx]
        for cc in range(1, len(units)):
            # get nex entry for comparison
            units_test, idx = np.unique(units[cc], True)
            units_test = units_test[idx]
            # compare
            assert all(units_ref == units_test), \
                f"'{coord}' has units {units_ref} in "\
                f"{coords[coord]['domain'][0]} "\
                f"({coords[coord]['convention'][0]}) but units {units_test} "\
                f"in {coords[coord]['domain'][cc]} "\
                f"({coords[coord]['convention'][cc]})"
Beispiel #18
0
def test_sph_voronoi():
    dihedral = 2 * np.arcsin(np.cos(np.pi / 3) / np.sin(np.pi / 5))
    R = np.tan(np.pi / 3) * np.tan(dihedral / 2)
    rho = np.cos(np.pi / 5) / np.sin(np.pi / 10)

    theta1 = np.arccos(
        (np.cos(np.pi / 5) / np.sin(np.pi / 5)) / np.tan(np.pi / 3))

    a2 = 2 * np.arccos(rho / R)

    theta2 = theta1 + a2
    theta3 = np.pi - theta2
    theta4 = np.pi - theta1

    phi1 = 0
    phi2 = 2 * np.pi / 3
    phi3 = 4 * np.pi / 3

    theta = np.concatenate((np.tile(theta1, 3), np.tile(theta2, 3),
                            np.tile(theta3, 3), np.tile(theta4, 3)))
    phi = np.tile(
        np.array([
            phi1, phi2, phi3, phi1 + np.pi / 3, phi2 + np.pi / 3,
            phi3 + np.pi / 3
        ]), 2)
    rad = np.ones(np.size(theta))

    s = Coordinates(phi, theta, rad, domain='sph', convention='top_colat')

    verts = np.array([[8.72677996e-01, -3.56822090e-01, 3.33333333e-01],
                      [3.33333333e-01, -5.77350269e-01, 7.45355992e-01],
                      [7.45355992e-01, -5.77350269e-01, -3.33333333e-01],
                      [8.72677996e-01, 3.56822090e-01, 3.33333333e-01],
                      [-8.72677996e-01, -3.56822090e-01, -3.33333333e-01],
                      [-1.27322004e-01, -9.34172359e-01, 3.33333333e-01],
                      [-7.45355992e-01, -5.77350269e-01, 3.33333333e-01],
                      [1.27322004e-01, -9.34172359e-01, -3.33333333e-01],
                      [-3.33333333e-01, -5.77350269e-01, -7.45355992e-01],
                      [-8.72677996e-01, 3.56822090e-01, -3.33333333e-01],
                      [0.00000000e+00, 0.00000000e+00, -1.00000000e+00],
                      [6.66666667e-01, -1.91105568e-16, -7.45355992e-01],
                      [7.45355992e-01, 5.77350269e-01, -3.33333333e-01],
                      [-3.33333333e-01, 5.77350269e-01, -7.45355992e-01],
                      [1.27322004e-01, 9.34172359e-01, -3.33333333e-01],
                      [-6.66666667e-01, 2.46373130e-16, 7.45355992e-01],
                      [0.00000000e+00, 0.00000000e+00, 1.00000000e+00],
                      [3.33333333e-01, 5.77350269e-01, 7.45355992e-01],
                      [-1.27322004e-01, 9.34172359e-01, 3.33333333e-01],
                      [-7.45355992e-01, 5.77350269e-01, 3.33333333e-01]])

    sv = spatial.SphericalVoronoi(s)
    np.testing.assert_allclose(np.sort(np.sum(verts, axis=-1)),
                               np.sort(np.sum(sv.vertices, axis=-1)),
                               atol=1e-6,
                               rtol=1e-6)
Beispiel #19
0
def test_coordinates_init_val():

    # test input: scalar
    c1 = 1
    # test input: 2 element vectors
    c2 = [1, 2]  # list
    c3 = np.asarray(c2)  # flat np.array
    c4 = np.atleast_2d(c2)  # row vector np.array
    c5 = np.transpose(c4)  # column vector np.array
    # test input: 3 element vector
    c6 = [1, 2, 3]
    # test input: 2D matrix
    c7 = np.array([[1, 2, 3], [1, 2, 3]])
    # test input: 3D matrix
    c8 = np.array([[[1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3]]])

    # tests that have to path
    # input scalar coordinate
    Coordinates(c1, c1, c1)
    # input list of coordinates
    Coordinates(c2, c2, c2)
    # input scalar and lists
    Coordinates(c1, c2, c2)
    # input flat np.arrays
    Coordinates(c3, c3, c3)
    # input non flat vectors
    Coordinates(c3, c4, c5)
    # input 2D data
    Coordinates(c1, c1, c7)
    # input 3D data
    Coordinates(c1, c1, c8)

    # tests that have to fail
    with raises(AssertionError):
        Coordinates(c2, c2, c6)
    with raises(AssertionError):
        Coordinates(c6, c6, c7)
    with raises(AssertionError):
        Coordinates(c2, c2, c8)
def test_orientations_from_view_up():
    """Create `Orientations` from view and up vectors."""
    # test with single view and up vectors
    view = [1, 0, 0]
    up = [0, 1, 0]
    Orientations.from_view_up(view, up)
    # test with multiple view and up vectors
    views = [[1, 0, 0], [0, 0, 1]]
    ups = [[0, 1, 0], [0, 1, 0]]
    Orientations.from_view_up(views, ups)
    # provided as ndarrays
    views = np.atleast_2d(views).astype(np.float64)
    ups = np.atleast_2d(ups).astype(np.float64)
    Orientations.from_view_up(views, ups)
    # provided as Coordinates
    views = Coordinates(views[:, 0], views[:, 1], views[:, 2])
    ups = Coordinates(ups[:, 0], ups[:, 1], ups[:, 2])
    Orientations.from_view_up(views, ups)
    # view and up counts not matching
    views = [[1, 0, 0], [0, 0, 1]]
    ups = [[0, 1, 0]]
    Orientations.from_view_up(views, ups)
Beispiel #21
0
def test__systems():
    # get all coordinate systems
    coords = Coordinates()
    systems = coords._systems()

    # check object type
    assert isinstance(systems, dict)

    # check completeness of systems
    for domain in systems:
        for convention in systems[domain]:
            assert "description_short" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'description_short'"
            assert "coordinates" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'coordinates'"
            assert "units" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'units'"
            assert "description" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'description'"
            assert "positive_x" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'positive_x'"
            assert "positive_y" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'positive_y'"
            assert "negative_x" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'negative_'"
            assert "negative_y" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'negative_y'"
            assert "positive_z" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'positive_z'"
            assert "negative_z" in systems[domain][convention], \
                f"{domain} ({convention}) is missing entry 'negative_z'"
            for coord in systems[domain][convention]['coordinates']:
                assert coord in systems[domain][convention], \
                    f"{domain} ({convention}) is missing entry '{coord}'"
                assert systems[domain][convention][coord][0] in \
                    ["unbound", "bound", "cyclic"], \
                    f"{domain} ({convention}), {coord}[0] must be 'unbound', "\
                    "'bound', or 'cyclic'."
def test_orientations_show(views, ups, positions, orientations):
    """
    Visualize orientations via `Orientations.show()`
    with and without `positions`.
    """
    # default orientation
    Orientations().show()
    # single vectors no position
    view = [1, 0, 0]
    up = [0, 1, 0]
    orientation_single = Orientations.from_view_up(view, up)
    orientation_single.show()
    # with position
    position = Coordinates(0, 1, 0)
    orientation_single.show(position)

    # multiple vectors no position
    orientations.show()
    # with matching number of positions
    orientations.show(positions)

    # select what to show
    orientations.show(show_views=False)
    orientations.show(show_ups=False)
    orientations.show(show_rights=False)
    orientations.show(show_views=False, show_ups=False)
    orientations.show(show_views=False, show_rights=False)
    orientations.show(show_ups=False, show_rights=False)
    orientations.show(positions=positions, show_views=False, show_ups=False)

    # with positions provided as Coordinates
    positions = np.asarray(positions)
    positions = Coordinates(positions[:, 0], positions[:, 1], positions[:, 2])
    orientations.show(positions)
    # with non-matching positions
    positions = Coordinates(0, 1, 0)
    with raises(ValueError):
        orientations.show(positions)
Beispiel #23
0
def sph_dodecahedron(radius=1.):
    """Generate a sampling based on the center points of the twelve
    dodecahedron faces.

    Parameters
    ----------
    radius : number, optional
        Radius of the sampling grid. The default is 1.

    Returns
    -------
    sampling : Coordinates
        Sampling positions as Coordinate object

    """

    dihedral = 2 * np.arcsin(np.cos(np.pi / 3) / np.sin(np.pi / 5))
    R = np.tan(np.pi / 3) * np.tan(dihedral / 2)
    rho = np.cos(np.pi / 5) / np.sin(np.pi / 10)

    theta1 = np.arccos(
        (np.cos(np.pi / 5) / np.sin(np.pi / 5)) / np.tan(np.pi / 3))

    a2 = 2 * np.arccos(rho / R)

    theta2 = theta1 + a2
    theta3 = np.pi - theta2
    theta4 = np.pi - theta1

    phi1 = 0
    phi2 = 2 * np.pi / 3
    phi3 = 4 * np.pi / 3

    theta = np.concatenate((np.tile(theta1, 3), np.tile(theta2, 3),
                            np.tile(theta3, 3), np.tile(theta4, 3)))
    phi = np.tile(
        np.array([
            phi1, phi2, phi3, phi1 + np.pi / 3, phi2 + np.pi / 3,
            phi3 + np.pi / 3
        ]), 2)
    rad = radius * np.ones(np.size(theta))

    sampling = Coordinates(phi,
                           theta,
                           rad,
                           domain='sph',
                           convention='top_colat',
                           comment='dodecahedral sampling grid')
    return sampling
Beispiel #24
0
def test_weights_from_voronoi():
    s = Coordinates([0, 0, 1, -1, 0, 0], [0, 0, 0, 0, -1, 1],
                    [-1, 1, 0, 0, 0, 0],
                    domain='cart',
                    convention='right')

    # test with normalization
    weights = spatial.calculate_sph_voronoi_weights(s, normalize=True)
    desired = np.ones(6) / 6
    np.testing.assert_allclose(weights, desired)

    np.testing.assert_allclose(np.sum(weights), 1.)

    # test without normalization
    weights = spatial.calculate_sph_voronoi_weights(s, normalize=False)
    np.testing.assert_allclose(np.sum(weights), 4 * np.pi)
Beispiel #25
0
def test_get_nearest_sph():
    # test only 1D case since most of the code from self.get_nearest_k is used
    az = np.linspace(0, 40, 5)
    coords = Coordinates(az, 0, 1, 'sph', 'top_elev', 'deg')
    i, m = coords.get_nearest_sph(25, 0, 1, 5, 'sph', 'top_elev', 'deg')
    assert (i == np.array([2, 3])).all()
    assert (m == np.array([[0, 0, 1, 1, 0]], dtype=bool)).all()

    # test search with empty results
    i, m = coords.get_nearest_sph(25, 0, 1, 1, 'sph', 'top_elev', 'deg')
    assert len(i) == 0
    assert (m == np.array([[0, 0, 0, 0, 0]], dtype=bool)).all()

    # test out of range parameters
    with raises(AssertionError):
        coords.get_nearest_sph(1, 0, 0, -1)
    with raises(AssertionError):
        coords.get_nearest_sph(1, 0, 0, 181)
Beispiel #26
0
def cart_equidistant_cube(n_points):
    """Create a cuboid sampling with equidistant spacings in x, y, and z.
    The cube will have dimensions 1 x 1 x 1

    Parameters
    ----------
    n_points : int, tuple
        Number of points in the sampling. If a single value is given, the
        number of sampling positions will be the same in every axis. If a
        tuple is given, the number of points will be set as (n_x, n_y, n_z).

    Returns
    -------
    sampling : Coordinates
        Sampling positions as Coordinate object

    """
    if np.size(n_points) == 1:
        n_x = n_points
        n_y = n_points
        n_z = n_points
    elif np.size(n_points) == 3:
        n_x = n_points[0]
        n_y = n_points[1]
        n_z = n_points[2]
    else:
        raise ValueError("The number of points needs to be either an integer \
                or a tuple with 3 elements.")

    x = np.linspace(-1, 1, n_x)
    y = np.linspace(-1, 1, n_y)
    z = np.linspace(-1, 1, n_z)

    x_grid, y_grid, z_grid = np.meshgrid(x, y, z)

    sampling = Coordinates(x_grid.flatten(),
                           y_grid.flatten(),
                           z_grid.flatten(),
                           domain='cart',
                           comment='equidistant cuboid sampling grid')

    return sampling
Beispiel #27
0
def test_get_nearest_cart():
    # test only 1D case since most of the code from self.get_nearest_k is used
    x = np.arange(6)
    coords = Coordinates(x, 0, 0)
    i, m = coords.get_nearest_cart(2.5, 0, 0, 1.5)
    assert (i == np.array([1, 2, 3, 4])).all()
    assert (m == np.array([[0, 1, 1, 1, 1, 0]], dtype=bool)).all()

    # test search with empty results
    i, m = coords.get_nearest_cart(2.5, 0, 0, .1)
    assert len(i) == 0
    assert (m == np.array([[0, 0, 0, 0, 0, 0]], dtype=bool)).all()

    # test out of range parameters
    with raises(AssertionError):
        coords.get_nearest_cart(1, 0, 0, -1)
def test_orientations_from_view_up_show_coordinate_system_change(
        views, ups, positions):
    """
    Create `Orientations` from view and up vectors in the spherical domain
    as well as in the carteesian domain, and visualize both to compare them
    manually by eye.
    """
    # Carteesian: Visualize to manually validate orientations
    views = np.asarray(views)
    ups = np.asarray(ups)
    views = Coordinates(views[:, 0], views[:, 1], views[:, 2])
    ups = Coordinates(ups[:, 0], ups[:, 1], ups[:, 2])

    positions = np.asarray(positions)
    positions = Coordinates(positions[:, 0], positions[:, 1], positions[:, 2])
    orient_from_cart = Orientations.from_view_up(views, ups)
    orient_from_cart.show(positions)

    # Convert to spherical: And again visualize to manually validate
    views.get_sph(convert=True)
    ups.get_sph(convert=True)
    positions.get_sph(convert=True)

    orient_from_sph = Orientations.from_view_up(views, ups)
    orient_from_sph.show(positions)

    # Check if coordinate system has not been changed by orientations
    assert views._system['domain'] == 'sph', (
        "Coordinate system has been changed by Orientations.")
    assert ups._system['domain'] == 'sph', (
        "Coordinate system has been changed by Orientations.")
    assert positions._system['domain'] == 'sph', (
        "Coordinate system has been changed by Orientations.show().")
Beispiel #29
0
def sph_fliege(n_points=None, sh_order=None, radius=1.):
    """
    Return Fliege-Maier spherical sampling grid [1]_. See
    :ref:`Input Values<values>` for a list of
    possible values for `n_points`and `sh_order` or call `sph_fliege()`.

    Parameters
    ----------
    n_points : int, optional
        number of sampling points in the grid. Related to the spherical
        harmonic order by n_points = (sh_order + 1)**2. Either n_points or
        sh_order must be provided. The default is None.
    sh_order : int, optional
        maximum applicable spherical harmonic order. Related to the number of
        points by sh_order = np.sqrt(n_points) - 1. Either n_points or sh_order
        must be provided. The default is None.
    radius : number, optional
        radius of the sampling grid in meters. The default is 1.

    Returns
    -------
    sampling : Coordinates
        Sampling positions as Coordinate object

    Notes
    -----
    This implementation uses pre-calculated points from the SOFiA toolbox [2]_.


    .. _values:

    Input Values
    ------------
    +------------+------------+
    | `n_points` | `sh_order` |
    +============+============+
    | 4          | 1          |
    +------------+------------+
    | 9          | 2          |
    +------------+------------+
    | 16         | 3          |
    +------------+------------+
    | 25         | 4          |
    +------------+------------+
    | 36         | 5          |
    +------------+------------+
    | 49         | 6          |
    +------------+------------+
    | 64         | 7          |
    +------------+------------+
    | 81         | 8          |
    +------------+------------+
    | 100        | 9          |
    +------------+------------+
    | 121        | 10         |
    +------------+------------+
    | 144        | 11         |
    +------------+------------+
    | 169        | 12         |
    +------------+------------+
    | 196        | 13         |
    +------------+------------+
    | 225        | 14         |
    +------------+------------+
    | 256        | 15         |
    +------------+------------+
    | 289        | 16         |
    +------------+------------+
    | 324        | 17         |
    +------------+------------+
    | 361        | 18         |
    +------------+------------+
    | 400        | 19         |
    +------------+------------+
    | 441        | 20         |
    +------------+------------+
    | 484        | 21         |
    +------------+------------+
    | 529        | 22         |
    +------------+------------+
    | 576        | 23         |
    +------------+------------+
    | 625        | 24         |
    +------------+------------+
    | 676        | 25         |
    +------------+------------+
    | 729        | 26         |
    +------------+------------+
    | 784        | 27         |
    +------------+------------+
    | 841        | 28         |
    +------------+------------+
    | 900        | 29         |
    +------------+------------+

    References
    ----------
    .. [1] J. Fliege and U. Maier, "The distribution of points on the sphere
           and corresponding cubature formulae,” IMA J. Numerical Analysis,
           Vol. 19, pp. 317–334, Apr. 1999, doi: 10.1093/imanum/19.2.317.
    .. [2] https://audiogroup.web.th-koeln.de/SOFiA_wiki/DOWNLOAD.html

    """

    # possible values for n_points and sh_order
    points = np.array([
        4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289,
        324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900
    ],
                      dtype=int)

    orders = np.array(np.floor(np.sqrt(points) - 1), dtype=int)

    # list possible sh orders and number of points
    if n_points is None and sh_order is None:
        for o, d in zip(orders, points):
            print(f"SH order {o}, number of points {d}")

        return None

    # check input
    if n_points is not None and sh_order is not None:
        raise ValueError("Either n_points or sh_order must be None.")

    if sh_order is not None:
        # check if the order is available
        if sh_order not in orders:
            str_orders = [f"{o}" for o in orders]
            raise ValueError("Invalid spherical harmonic order 'sh_order'. \
                              Valid orders are: {}.".format(
                ', '.join(str_orders)))

        # assign n_points
        n_points = int(points[orders == sh_order])
    else:
        # check if n_points is available
        if n_points not in points:
            str_points = [f"{d}" for d in points]
            raise ValueError("Invalid number of points n_points. Valid points \
                            are: {}.".format(', '.join(str_points)))

        # assign sh_order
        sh_order = int(orders[points == n_points])

    # get the sampling points
    fliege = sio.loadmat(os.path.join(os.path.dirname(__file__), "external",
                                      "samplings_fliege.mat"),
                         variable_names=f"Fliege_{int(n_points)}")
    fliege = fliege[f"Fliege_{int(n_points)}"]

    # generate Coordinates object
    sampling = Coordinates(fliege[:, 0],
                           fliege[:, 1],
                           radius,
                           domain='sph',
                           convention='top_colat',
                           unit='rad',
                           sh_order=sh_order,
                           weights=fliege[:, 2],
                           comment='spherical Fliege sampling grid')

    # switch and invert coordinates in Cartesian representation to be
    # consistent with [1]
    xyz = sampling.get_cart(convention='right')
    sampling.set_cart(xyz[:, 1], xyz[:, 0], -xyz[:, 2])

    return sampling
Beispiel #30
0
def sph_lebedev(n_points=None, sh_order=None, radius=1.):
    """
    Return Lebedev spherical sampling grid [1]_. For a list of available values
    for `n_points`and `sh_order` call `sph_lebedev()`.

    Parameters
    ----------
    n_points : int, optional
        number of sampling points in the grid. Related to the spherical
        harmonic order by n_points = (sh_order + 1)**2. Either n_points or
        sh_order must be provided. The default is None.
    sh_order : int, optional
        maximum applicable spherical harmonic order. Related to the number of
        points by sh_order = np.sqrt(n_points) - 1. Either n_points or sh_order
        must be provided. The default is None.
    radius : number, optional
        radius of the sampling grid in meters. The default is 1.

    Returns
    -------
    sampling : Coordinates
        Sampling positions as Coordinate object

    Notes
    -----
    This implementation is based on Matlab Code written by Rob Parrish [2]_.

    References
    ----------
    .. [1] V.I. Lebedev, and D.N. Laikov
           "A quadrature formula for the sphere of the 131st
           algebraic order of accuracy"
           Doklady Mathematics, Vol. 59, No. 3, 1999, pp. 477-481.
    .. [2] https://de.mathworks.com/matlabcentral/fileexchange/27097-\
        getlebedevsphere

    """

    # possible degrees
    degrees = np.array([
        6, 14, 26, 38, 50, 74, 86, 110, 146, 170, 194, 230, 266, 302, 350, 434,
        590, 770, 974, 1202, 1454, 1730, 2030, 2354, 2702, 3074, 3470, 3890,
        4334, 4802, 5294, 5810
    ],
                       dtype=int)

    # corresponding spherical harmonic orders
    orders = np.array((np.floor(np.sqrt(degrees / 1.3) - 1)), dtype=int)

    # list possible sh orders and degrees
    if n_points is None and sh_order is None:
        print('Possible input values:')
        for o, d in zip(orders, degrees):
            print(f"SH order {o}, number of points {d}")

        return None

    # check input
    if n_points is not None and sh_order is not None:
        raise ValueError("Either n_points or sh_order must be None.")

    # check if the order is available
    if sh_order is not None:
        if sh_order not in orders:
            str_orders = [f"{o}" for o in orders]
            raise ValueError("Invalid spherical harmonic order 'sh_order'. \
                             Valid orders are: {}.".format(
                ', '.join(str_orders)))

        n_points = int(degrees[orders == sh_order])

    # check if n_points is available
    if n_points not in degrees:
        str_degrees = [f"{d}" for d in degrees]
        raise ValueError("Invalid number of points n_points. Valid degrees \
                         are: {}.".format(', '.join(str_degrees)))

    # calculate sh_order
    sh_order = int(orders[degrees == n_points])

    # get the samlpling
    leb = external.lebedev_sphere(n_points)

    # normalize the weights
    weights = leb["w"] / (4 * np.pi)

    # generate Coordinates object
    sampling = Coordinates(leb["x"] * radius,
                           leb["y"] * radius,
                           leb["z"] * radius,
                           sh_order=sh_order,
                           weights=weights,
                           comment='spherical Lebedev sampling grid')

    return sampling