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]))
def test_rotation(): # test with quaternion c = Coordinates(1, 0, 0) c.rotate('quat', [0, 0, 1 / np.sqrt(2), 1 / np.sqrt(2)]) npt.assert_allclose(c.get_cart().flatten(), [0, 1, 0], atol=1e-15) # test with matrix c = Coordinates(1, 0, 0) c.rotate('matrix', [[0, -1, 0], [1, 0, 0], [0, 0, 1]]) npt.assert_allclose(c.get_cart().flatten(), [0, 1, 0], atol=1e-15) # test with rotvec c = Coordinates(1, 0, 0) c.rotate('rotvec', [0, 0, 90]) npt.assert_allclose(c.get_cart().flatten(), [0, 1, 0], atol=1e-15) # test with euler c = Coordinates(1, 0, 0) c.rotate('z', 90) npt.assert_allclose(c.get_cart().flatten(), [0, 1, 0], atol=1e-15) # test with unknown type with raises(ValueError): c.rotate('urgh', 90) # test if cshape is preserved and inverse rotation works xyz = np.concatenate((np.ones((2, 4, 1)), np.zeros( (2, 4, 1)), np.zeros((2, 4, 1))), -1) c = Coordinates(xyz[..., 0], xyz[..., 1], xyz[..., 2]) c.rotate('z', 90) c.rotate('z', 90, inverse=True) npt.assert_allclose(c._points, xyz, atol=1e-15)
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().")
def test_get_slice(): # test only for self.cdim = 1. # self.get_slice uses KDTree, which is tested with N-dimensional arrays # in test_get_nearest_k() # cartesian grid d = np.linspace(-2, 2, 5) c = Coordinates(d, 0, 0) assert (c.get_slice('x', 'met', 0, 1) == np.array([0, 1, 1, 1, 0], dtype=bool)).all() c = Coordinates(0, d, 0) assert (c.get_slice('y', 'met', 0, 1) == np.array([0, 1, 1, 1, 0], dtype=bool)).all() c = Coordinates(0, 0, d) assert (c.get_slice('z', 'met', 0, 1) == np.array([0, 1, 1, 1, 0], dtype=bool)).all() # spherical grid d = [358, 359, 0, 1, 2] c = Coordinates(d, 0, 1, 'sph', 'top_elev', 'deg') # cyclic querry assert (c.get_slice('azimuth', 'deg', 0, 1) == np.array([0, 1, 1, 1, 0], dtype=bool)).all() # non-cyclic querry assert (c.get_slice('azimuth', 'deg', 1, 1) == np.array([0, 0, 1, 1, 1], dtype=bool)).all() # out of range querry with raises(AssertionError): c.get_slice('azimuth', 'deg', -1, 1)
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)
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)
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
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)
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])
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])
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
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
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
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
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}")
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
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)
def test_get_nearest_k(): # 1D cartesian, nearest point x = np.arange(6) coords = Coordinates(x, 0, 0) d, i, m = coords.get_nearest_k(1, 0, 0) assert d == 0. assert i == 1 assert (m == np.array([0, 1, 0, 0, 0, 0], dtype=bool)).all() # 1D spherical, nearest point d, i, m = coords.get_nearest_k(0, 0, 1, 1, 'sph', 'top_elev', 'deg') assert d == 0. assert i == 1 assert (m == np.array([0, 1, 0, 0, 0, 0], dtype=bool)).all() # 1D cartesian, two nearest points d, i, m = coords.get_nearest_k(1.2, 0, 0, 2) npt.assert_allclose(d, [.2, .8], atol=1e-15) assert (i == np.array([1, 2])).all() assert (m == np.array([0, 1, 1, 0, 0, 0], dtype=bool)).all() # 1D cartesian querry two points d, i, m = coords.get_nearest_k([1, 2], 0, 0) npt.assert_allclose(d, [0, 0], atol=1e-15) npt.assert_allclose(i, [1, 2]) assert (m == np.array([0, 1, 1, 0, 0, 0], dtype=bool)).all() # 2D cartesian, nearest point coords = Coordinates(x.reshape(2, 3), 0, 0) d, i, m = coords.get_nearest_k(1, 0, 0) assert d == 0. assert i == 1 assert (m == np.array([[0, 1, 0], [0, 0, 0]], dtype=bool)).all() # test with plot coords = Coordinates(x, 0, 0) coords.get_nearest_k(1, 0, 0, show=True) # test object with a single point coords = Coordinates(1, 0, 0) coords.get_nearest_k(1, 0, 0, show=True) # test out of range parameters with raises(AssertionError): coords.get_nearest_k(1, 0, 0, -1)
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)
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)
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))
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)
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)
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
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_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)
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]})"
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)
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