|
| 1 | +import os |
| 2 | +import numpy as np |
| 3 | +import pytest |
| 4 | +import xarray as xr |
| 5 | +from pathlib import Path |
| 6 | +import uxarray as ux |
| 7 | +from uxarray.constants import ERROR_TOLERANCE |
| 8 | + |
| 9 | +current_path = Path(os.path.dirname(os.path.realpath(__file__))) |
| 10 | + |
| 11 | +# Sample grid file paths |
| 12 | +gridfile_CSne8 = current_path / "meshfiles" / "scrip" / "outCSne8" / "outCSne8.nc" |
| 13 | +gridfile_RLL1deg = current_path / "meshfiles" / "ugrid" / "outRLL1deg" / "outRLL1deg.ug" |
| 14 | +gridfile_RLL10deg_CSne4 = current_path / "meshfiles" / "ugrid" / "ov_RLL10deg_CSne4" / "ov_RLL10deg_CSne4.ug" |
| 15 | +gridfile_CSne30 = current_path / "meshfiles" / "ugrid" / "outCSne30" / "outCSne30.ug" |
| 16 | +gridfile_fesom = current_path / "meshfiles" / "ugrid" / "fesom" / "fesom.mesh.diag.nc" |
| 17 | +gridfile_geoflow = current_path / "meshfiles" / "ugrid" / "geoflow-small" / "grid.nc" |
| 18 | +gridfile_mpas = current_path / 'meshfiles' / "mpas" / "QU" / 'mesh.QU.1920km.151026.nc' |
| 19 | + |
| 20 | +grid_files = [gridfile_CSne8, |
| 21 | + gridfile_RLL1deg, |
| 22 | + gridfile_RLL10deg_CSne4, |
| 23 | + gridfile_CSne30, |
| 24 | + gridfile_fesom, |
| 25 | + gridfile_geoflow, |
| 26 | + gridfile_mpas] |
| 27 | + |
| 28 | +def test_construction(): |
| 29 | + """Tests the construction of the SpatialHash object""" |
| 30 | + for grid_file in grid_files: |
| 31 | + uxgrid = ux.open_grid(grid_file) |
| 32 | + face_ids, bcoords = uxgrid.get_spatial_hash().query([0.9, 1.8]) |
| 33 | + assert face_ids.shape[0] == bcoords.shape[0] |
| 34 | + |
| 35 | + |
| 36 | +def test_is_inside(): |
| 37 | + """Verifies simple test for points inside and outside an element.""" |
| 38 | + verts = [(0.0, 90.0), (-180, 0.0), (0.0, -90)] |
| 39 | + uxgrid = ux.open_grid(verts, latlon=True) |
| 40 | + # Verify that a point outside the element returns a face id of -1 |
| 41 | + face_ids, bcoords = uxgrid.get_spatial_hash().query([90.0, 0.0]) |
| 42 | + assert face_ids[0] == -1 |
| 43 | + # Verify that a point inside the element returns a face id of 0 |
| 44 | + face_ids, bcoords = uxgrid.get_spatial_hash().query([-90.0, 0.0]) |
| 45 | + |
| 46 | + assert face_ids[0] == 0 |
| 47 | + assert np.allclose(bcoords[0], [0.25, 0.5, 0.25], atol=1e-06) |
| 48 | + |
| 49 | + |
| 50 | +def test_query_on_vertex(): |
| 51 | + """Verifies correct values when a query is made exactly on a vertex""" |
| 52 | + verts = [(0.0, 90.0), (-180, 0.0), (0.0, -90)] |
| 53 | + uxgrid = ux.open_grid(verts, latlon=True) |
| 54 | + # Verify that a point outside the element returns a face id of -1 |
| 55 | + face_ids, bcoords = uxgrid.get_spatial_hash().query([0.0, 90.0]) |
| 56 | + assert face_ids[0] == 0 |
| 57 | + assert np.isclose(bcoords[0,0],1.0,atol=ERROR_TOLERANCE) |
| 58 | + assert np.isclose(bcoords[0,1],0.0,atol=ERROR_TOLERANCE) |
| 59 | + assert np.isclose(bcoords[0,2],0.0,atol=ERROR_TOLERANCE) |
| 60 | + |
| 61 | + |
| 62 | +def test_query_on_edge(): |
| 63 | + """Verifies correct values when a query is made exactly on an edge of a face""" |
| 64 | + verts = [(0.0, 90.0), (-180, 0.0), (0.0, -90)] |
| 65 | + uxgrid = ux.open_grid(verts, latlon=True) |
| 66 | + # Verify that a point outside the element returns a face id of -1 |
| 67 | + face_ids, bcoords = uxgrid.get_spatial_hash().query([0.0, 0.0]) |
| 68 | + assert face_ids[0] == 0 |
| 69 | + assert np.isclose(bcoords[0,0],0.5,atol=ERROR_TOLERANCE) |
| 70 | + assert np.isclose(bcoords[0,1],0.0,atol=ERROR_TOLERANCE) |
| 71 | + assert np.isclose(bcoords[0,2],0.5,atol=ERROR_TOLERANCE) |
| 72 | + |
| 73 | + |
| 74 | +def test_list_of_coords_simple(): |
| 75 | + """Verifies test using list of points inside and outside an element""" |
| 76 | + verts = [(0.0, 90.0), (-180, 0.0), (0.0, -90)] |
| 77 | + uxgrid = ux.open_grid(verts, latlon=True) |
| 78 | + |
| 79 | + coords = [[90.0, 0.0], [-90.0, 0.0]] |
| 80 | + face_ids, bcoords = uxgrid.get_spatial_hash().query(coords) |
| 81 | + assert face_ids[0] == -1 |
| 82 | + assert face_ids[1] == 0 |
| 83 | + assert np.allclose(bcoords[1], [0.25, 0.5, 0.25], atol=1e-06) |
| 84 | + |
| 85 | + |
| 86 | +def test_list_of_coords_fesom(): |
| 87 | + """Verifies test using list of points on the fesom grid""" |
| 88 | + uxgrid = ux.open_grid(gridfile_fesom) |
| 89 | + |
| 90 | + num_particles = 20 |
| 91 | + coords = np.zeros((num_particles,2)) |
| 92 | + x_min = 1.0 |
| 93 | + x_max = 3.0 |
| 94 | + y_min = 2.0 |
| 95 | + y_max = 10.0 |
| 96 | + for k in range(num_particles): |
| 97 | + coords[k,0] = np.deg2rad(np.random.uniform(x_min, x_max)) |
| 98 | + coords[k,1] = np.deg2rad(np.random.uniform(y_min, y_max)) |
| 99 | + face_ids, bcoords = uxgrid.get_spatial_hash().query(coords) |
| 100 | + assert len(face_ids) == num_particles |
| 101 | + assert bcoords.shape[0] == num_particles |
| 102 | + assert bcoords.shape[1] == 3 |
| 103 | + assert np.all(face_ids >= 0) # All particles should be inside an element |
| 104 | + |
| 105 | + |
| 106 | +def test_list_of_coords_mpas_dual(): |
| 107 | + """Verifies test using list of points on the dual MPAS grid""" |
| 108 | + uxgrid = ux.open_grid(gridfile_mpas, use_dual=True) |
| 109 | + |
| 110 | + num_particles = 20 |
| 111 | + coords = np.zeros((num_particles,2)) |
| 112 | + x_min = -40.0 |
| 113 | + x_max = 40.0 |
| 114 | + y_min = -20.0 |
| 115 | + y_max = 20.0 |
| 116 | + for k in range(num_particles): |
| 117 | + coords[k,0] = np.deg2rad(np.random.uniform(x_min, x_max)) |
| 118 | + coords[k,1] = np.deg2rad(np.random.uniform(y_min, y_max)) |
| 119 | + face_ids, bcoords = uxgrid.get_spatial_hash().query(coords) |
| 120 | + assert len(face_ids) == num_particles |
| 121 | + assert bcoords.shape[0] == num_particles |
| 122 | + assert bcoords.shape[1] == 3 # max sides of an element |
| 123 | + assert np.all(face_ids >= 0) # All particles should be inside an element |
| 124 | + |
| 125 | + |
| 126 | +def test_list_of_coords_mpas_primal(): |
| 127 | + """Verifies test using list of points on the primal MPAS grid""" |
| 128 | + uxgrid = ux.open_grid(gridfile_mpas, use_dual=False) |
| 129 | + |
| 130 | + num_particles = 20 |
| 131 | + coords = np.zeros((num_particles,2)) |
| 132 | + x_min = -40.0 |
| 133 | + x_max = 40.0 |
| 134 | + y_min = -20.0 |
| 135 | + y_max = 20.0 |
| 136 | + for k in range(num_particles): |
| 137 | + coords[k,0] = np.deg2rad(np.random.uniform(x_min, x_max)) |
| 138 | + coords[k,1] = np.deg2rad(np.random.uniform(y_min, y_max)) |
| 139 | + face_ids, bcoords = uxgrid.get_spatial_hash().query(coords) |
| 140 | + assert len(face_ids) == num_particles |
| 141 | + assert bcoords.shape[0] == num_particles |
| 142 | + assert bcoords.shape[1] == 6 # max sides of an element |
| 143 | + assert np.all(face_ids >= 0) # All particles should be inside an element |
0 commit comments