def test_esmpy_normalisation(): """ Integration test for :meth:`~esmf_regrid.esmf_regridder.Regridder`. Checks against ESMF to ensure results are consistent. """ src_data = np.array( [ [1.0, 1.0], [1.0, 0.0], [1.0, 0.0], ], ) src_mask = np.array( [ [True, False], [False, False], [False, False], ] ) src_array = ma.array(src_data, mask=src_mask) lon, lat, lon_bounds, lat_bounds = make_grid_args(2, 3) src_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) src_esmpy_grid = src_grid._make_esmf_grid() src_esmpy_grid.add_item(ESMF.GridItem.MASK, staggerloc=ESMF.StaggerLoc.CENTER) src_esmpy_grid.mask[0][...] = src_mask src_field = ESMF.Field(src_esmpy_grid) src_field.data[...] = src_data lon, lat, lon_bounds, lat_bounds = make_grid_args(3, 2) tgt_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) tgt_field = tgt_grid.make_esmf_field() regridder = Regridder(src_grid, tgt_grid) regridding_kwargs = { "ignore_degenerate": True, "regrid_method": ESMF.RegridMethod.CONSERVE, "unmapped_action": ESMF.UnmappedAction.IGNORE, "factors": True, "src_mask_values": [1], } esmpy_fracarea_regridder = ESMF.Regrid( src_field, tgt_field, norm_type=ESMF.NormType.FRACAREA, **regridding_kwargs ) esmpy_dstarea_regridder = ESMF.Regrid( src_field, tgt_field, norm_type=ESMF.NormType.DSTAREA, **regridding_kwargs ) tgt_field_dstarea = esmpy_dstarea_regridder(src_field, tgt_field) result_esmpy_dstarea = tgt_field_dstarea.data result_dstarea = regridder.regrid(src_array, norm_type="dstarea") assert ma.allclose(result_esmpy_dstarea, result_dstarea) tgt_field_fracarea = esmpy_fracarea_regridder(src_field, tgt_field) result_esmpy_fracarea = tgt_field_fracarea.data result_fracarea = regridder.regrid(src_array, norm_type="fracarea") assert ma.allclose(result_esmpy_fracarea, result_fracarea)
def _regrid_rectilinear_to_rectilinear__prepare(src_grid_cube, tgt_grid_cube): tgt_x = tgt_grid_cube.coord(axis="x") tgt_y = tgt_grid_cube.coord(axis="y") src_x = src_grid_cube.coord(axis="x") src_y = src_grid_cube.coord(axis="y") if len(src_x.shape) == 1: grid_x_dim = src_grid_cube.coord_dims(src_x)[0] grid_y_dim = src_grid_cube.coord_dims(src_y)[0] else: grid_y_dim, grid_x_dim = src_grid_cube.coord_dims(src_x) srcinfo = _cube_to_GridInfo(src_grid_cube) tgtinfo = _cube_to_GridInfo(tgt_grid_cube) regridder = Regridder(srcinfo, tgtinfo) regrid_info = RegridInfo( x_dim=grid_x_dim, y_dim=grid_y_dim, x_coord=tgt_x, y_coord=tgt_y, regridder=regridder, ) return regrid_info
def test_global_grid(): """Test conversion of a global grid.""" n_lons = 6 n_lats = 5 lon_bounds = (-180, 180) lat_bounds = (-90, 90) cube = _grid_cube( n_lons, n_lats, lon_bounds, lat_bounds, circular=True, coord_system=GeogCS(EARTH_RADIUS), ) gridinfo = _cube_to_GridInfo(cube) # Ensure conversion to ESMF works without error _ = gridinfo.make_esmf_field() # The following test ensures there are no overlapping cells. # This catches geometric/topological abnormalities that would arise from, # for example: switching lat/lon values, using euclidean coords vs spherical. rg = Regridder(gridinfo, gridinfo) expected_weights = scipy.sparse.identity(n_lats * n_lons) assert np.array_equal(expected_weights.todense(), rg.weight_matrix.todense()) assert gridinfo.crs == GeogCS(EARTH_RADIUS).as_cartopy_crs()
def _regrid_rectilinear_to_unstructured__prepare( src_grid_cube, target_mesh_cube, method, precomputed_weights=None, resolution=None, ): """ First (setup) part of 'regrid_rectilinear_to_unstructured'. Check inputs and calculate the sparse regrid matrix and related info. The 'regrid info' returned can be re-used over many 2d slices. """ grid_x = src_grid_cube.coord(axis="x") grid_y = src_grid_cube.coord(axis="y") mesh = target_mesh_cube.mesh location = target_mesh_cube.location if mesh is None: raise ValueError("The given cube is not defined on a mesh.") if method == "conservative": if location != "face": raise ValueError( f"Conservative regridding requires a target cube located on " f"the face of a cube, target cube had the {location} location." ) center = False elif method == "bilinear": if location not in ["face", "node"]: raise ValueError( f"Bilinear regridding requires a target cube with a node " f"or face location, target cube had the {location} location." ) if location == "face" and None in mesh.face_coords: raise ValueError( "Bilinear regridding requires a target cube on a face location to have " "a face center." ) center = True else: raise ValueError( f"method must be either 'bilinear' or 'conservative', got '{method}'." ) assert mesh is not None if grid_x.ndim == 1: (grid_x_dim,) = src_grid_cube.coord_dims(grid_x) (grid_y_dim,) = src_grid_cube.coord_dims(grid_y) else: grid_y_dim, grid_x_dim = src_grid_cube.coord_dims(grid_x) meshinfo = _mesh_to_MeshInfo(mesh, location) gridinfo = _cube_to_GridInfo(src_grid_cube, center=center, resolution=resolution) regridder = Regridder( gridinfo, meshinfo, method=method, precomputed_weights=precomputed_weights ) regrid_info = (grid_x_dim, grid_y_dim, grid_x, grid_y, mesh, location, regridder) return regrid_info
def test_Regridder_init_fail(): """Basic test for :meth:`~esmf_regrid.esmf_regridder.Regridder.__init__`.""" lon, lat, lon_bounds, lat_bounds = make_grid_args(2, 3) src_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) lon, lat, lon_bounds, lat_bounds = make_grid_args(3, 2) tgt_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) with pytest.raises(ValueError): _ = Regridder(src_grid, tgt_grid, method="other")
def test_large_mesh_validity(): """Test validity of objects derived from a large gridlike Mesh.""" mesh = _gridlike_mesh(40, 20) meshinfo = _mesh_to_MeshInfo(mesh, location="face") # Ensure conversion to ESMF works without error. _ = meshinfo.make_esmf_field() # The following test ensures there are no overlapping cells. # This catches geometric/topological abnormalities that would arise from, # for example: switching lat/lon values, using euclidean coords vs spherical. rg = Regridder(meshinfo, meshinfo) expected_weights = scipy.sparse.identity(meshinfo.size) assert np.allclose(expected_weights.todense(), rg.weight_matrix.todense())
def test_Regridder_init(): """Basic test for :meth:`~esmf_regrid.esmf_regridder.Regridder.__init__`.""" lon, lat, lon_bounds, lat_bounds = make_grid_args(2, 3) src_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) lon, lat, lon_bounds, lat_bounds = make_grid_args(3, 2) tgt_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) rg = Regridder(src_grid, tgt_grid) result = rg.weight_matrix expected = _expected_weights() assert np.allclose(result.toarray(), expected.toarray())
def test_curvilinear_grid(): """Test conversion of a curvilinear global grid.""" n_lons = 6 n_lats = 5 lon_bounds = (-180, 180) lat_bounds = (-90, 90) cube = _curvilinear_cube( n_lons, n_lats, lon_bounds, lat_bounds, coord_system=GeogCS(EARTH_RADIUS), ) gridinfo = _cube_to_GridInfo(cube) # Ensure conversion to ESMF works without error _ = gridinfo.make_esmf_field() # The following test ensures there are no overlapping cells. # This catches geometric/topological abnormalities that would arise from, # for example: switching lat/lon values, using euclidean coords vs spherical. rg = Regridder(gridinfo, gridinfo) expected_weights = scipy.sparse.identity(n_lats * n_lons) assert np.array_equal(expected_weights.todense(), rg.weight_matrix.todense()) assert gridinfo.crs == GeogCS(EARTH_RADIUS).as_cartopy_crs() # While curvilinear coords do not have the "circular" attribute, the code # allows "circular" to be True when setting the core regridder directly. # This describes an ESMF object which is topologically different, but ought # to be geometrically equivalent to the non-circular case. circular_gridinfo = _cube_to_GridInfo(cube) circular_gridinfo.circular = True rg_circular = Regridder(circular_gridinfo, gridinfo) assert np.allclose(expected_weights.todense(), rg_circular.weight_matrix.todense())
def test_local_grid(): """Test conversion of a local grid.""" n_lons = 6 n_lats = 5 lon_bounds = (-20, 20) lat_bounds = (20, 60) cube = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds) gridinfo = _cube_to_GridInfo(cube) # Ensure conversion to ESMF works without error _ = gridinfo.make_esmf_field() # The following test ensures there are no overlapping cells. # Note that this test fails when longitude is circular. rg = Regridder(gridinfo, gridinfo) expected_weights = scipy.sparse.identity(n_lats * n_lons) assert np.array_equal(expected_weights.todense(), rg.weight_matrix.todense())
def test_expanded_lons_with_mesh(): """ Basic test for regridding with :meth:`~esmf_regrid.esmf_regridder.RefinedGridInfo.make_esmf_field`. Mirrors the tests in :func:`~esmf_regrid.tests.unit.experimental.unstructured_regrid.test_MeshInfo.test_regrid_with_mesh` but with slightly different expected values due to increased accuracy. """ mesh_args = _make_small_mesh_args() mesh = MeshInfo(*mesh_args) grid_args = make_grid_args(2, 3) grid = RefinedGridInfo(*grid_args[2:4], resolution=4) mesh_to_grid_regridder = Regridder(mesh, grid) mesh_input = np.array([3, 2]) grid_output = mesh_to_grid_regridder.regrid(mesh_input) expected_grid_output = np.array([ [2.671534474734418, 3.0], [2.088765949748455, 2.922517356506756], [2.0, 2.340882413622917], ]) assert ma.allclose(expected_grid_output, grid_output) grid_to_mesh_regridder = Regridder(grid, mesh) grid_input = np.array([[0, 0], [1, 0], [2, 1]]) mesh_output = grid_to_mesh_regridder.regrid(grid_input) expected_mesh_output = np.array([0.14117205318254747, 1.1976140197893996]) assert ma.allclose(expected_mesh_output, mesh_output) def _give_extra_dims(array): result = np.stack([array, array + 1]) result = np.stack([result, result + 10, result + 100]) return result extra_dim_mesh_input = _give_extra_dims(mesh_input) extra_dim_grid_output = mesh_to_grid_regridder.regrid(extra_dim_mesh_input) extra_dim_expected_grid_output = _give_extra_dims(expected_grid_output) assert ma.allclose(extra_dim_expected_grid_output, extra_dim_grid_output) extra_dim_grid_input = _give_extra_dims(grid_input) extra_dim_mesh_output = grid_to_mesh_regridder.regrid(extra_dim_grid_input) extra_dim_expected_mesh_output = _give_extra_dims(expected_mesh_output) assert ma.allclose(extra_dim_expected_mesh_output, extra_dim_mesh_output)
def test_grid_with_scalars(): """Test conversion of a grid with scalar coords.""" n_lons = 1 n_lats = 5 lon_bounds = (-20, 20) lat_bounds = (20, 60) cube = _grid_cube(n_lons, n_lats, lon_bounds, lat_bounds) # Convert longitude to a scalar cube = cube[:, 0] assert len(cube.shape) == 1 gridinfo = _cube_to_GridInfo(cube) # Ensure conversion to ESMF works without error _ = gridinfo.make_esmf_field() # The following test ensures there are no overlapping cells. rg = Regridder(gridinfo, gridinfo) expected_weights = scipy.sparse.identity(n_lats * n_lons) assert np.array_equal(expected_weights.todense(), rg.weight_matrix.todense())
def test_regrid_with_mesh(): """Basic test for regridding with :meth:`~esmf_regrid.esmf_regridder.GridInfo.make_esmf_field`.""" mesh_args = _make_small_mesh_args() mesh = MeshInfo(*mesh_args) grid_args = make_grid_args(2, 3) grid = GridInfo(*grid_args) mesh_to_grid_regridder = Regridder(mesh, grid) mesh_input = np.array([3, 2]) grid_output = mesh_to_grid_regridder.regrid(mesh_input) expected_grid_output = np.array([ [2.671294712940605, 3.0], [2.0885553467353097, 2.9222786250561574], [2.0, 2.3397940801753307], ]) assert ma.allclose(expected_grid_output, grid_output) grid_to_mesh_regridder = Regridder(grid, mesh) grid_input = np.array([[0, 0], [1, 0], [2, 1]]) mesh_output = grid_to_mesh_regridder.regrid(grid_input) expected_mesh_output = np.array([0.1408245341331448, 1.19732762534643]) assert ma.allclose(expected_mesh_output, mesh_output) def _give_extra_dims(array): result = np.stack([array, array + 1]) result = np.stack([result, result + 10, result + 100]) return result extra_dim_mesh_input = _give_extra_dims(mesh_input) extra_dim_grid_output = mesh_to_grid_regridder.regrid(extra_dim_mesh_input) extra_dim_expected_grid_output = _give_extra_dims(expected_grid_output) assert ma.allclose(extra_dim_expected_grid_output, extra_dim_grid_output) extra_dim_grid_input = _give_extra_dims(grid_input) extra_dim_mesh_output = grid_to_mesh_regridder.regrid(extra_dim_grid_input) extra_dim_expected_mesh_output = _give_extra_dims(expected_mesh_output) assert ma.allclose(extra_dim_expected_mesh_output, extra_dim_mesh_output)
def _regrid_rectilinear_to_rectilinear__prepare(src_grid_cube, tgt_grid_cube): tgt_x, tgt_y = get_xy_dim_coords(tgt_grid_cube) src_x, src_y = get_xy_dim_coords(src_grid_cube) grid_x_dim = src_grid_cube.coord_dims(src_x)[0] grid_y_dim = src_grid_cube.coord_dims(src_y)[0] srcinfo = _cube_to_GridInfo(src_grid_cube) tgtinfo = _cube_to_GridInfo(tgt_grid_cube) regridder = Regridder(srcinfo, tgtinfo) regrid_info = RegridInfo( x_dim=grid_x_dim, y_dim=grid_y_dim, x_coord=tgt_x, y_coord=tgt_y, regridder=regridder, ) return regrid_info
def test_expanded_lats_with_mesh(): """Basic test for regridding with :meth:`~esmf_regrid.esmf_regridder.RefinedGridInfo.make_esmf_field`.""" mesh_args = _make_small_mesh_args() mesh = MeshInfo(*mesh_args) grid = RefinedGridInfo(np.array([0, 5, 10]), np.array([-90, 90]), resolution=4) mesh_to_grid_regridder = Regridder(mesh, grid) mesh_input = np.array([3, 2]) grid_output = mesh_to_grid_regridder.regrid(mesh_input) expected_grid_output = np.array([ [2.2024695514629724, 2.4336888097502642], ]) assert ma.allclose(expected_grid_output, grid_output) grid_to_mesh_regridder = Regridder(grid, mesh) grid_input = np.array([[1, 2]]) mesh_output = grid_to_mesh_regridder.regrid(grid_input) expected_mesh_output = np.array([1.7480791292591336, 1.496070008348207]) assert ma.allclose(expected_mesh_output, mesh_output) def _give_extra_dims(array): result = np.stack([array, array + 1]) result = np.stack([result, result + 10, result + 100]) return result extra_dim_mesh_input = _give_extra_dims(mesh_input) extra_dim_grid_output = mesh_to_grid_regridder.regrid(extra_dim_mesh_input) extra_dim_expected_grid_output = _give_extra_dims(expected_grid_output) assert ma.allclose(extra_dim_expected_grid_output, extra_dim_grid_output) extra_dim_grid_input = _give_extra_dims(grid_input) extra_dim_mesh_output = grid_to_mesh_regridder.regrid(extra_dim_grid_input) extra_dim_expected_mesh_output = _give_extra_dims(expected_mesh_output) assert ma.allclose(extra_dim_expected_mesh_output, extra_dim_mesh_output)
def test_regrid_bilinear_with_mesh(): """Basic test for regridding with :meth:`~esmf_regrid.esmf_regridder.GridInfo.make_esmf_field`.""" # We create a mesh with the following shape: # 20 ,+ ,+ 4 # / | with nodes: / | # 10 +' ,+ 1 +' ,+ 3 # | / | | / | # 0 +---+ 0 +---+ 2 # 0 10 mesh_args = _make_small_mesh_args() elem_coords = np.array([[5, 0], [5, 10]]) node_mesh = MeshInfo(*mesh_args, location="node") face_mesh = MeshInfo(*mesh_args, elem_coords=elem_coords, location="face") # We create a grid with the following shape: # 20/3 +---+ # | | # 10/3 +---+ # | | # 0 +---+ # 0 10 grid_args = [ar * 2 for ar in make_grid_args(2, 3)] grid = GridInfo(*grid_args, center=True) mesh_to_grid_regridder = Regridder(node_mesh, grid, method="bilinear") mesh_input = np.arange(5) grid_output = mesh_to_grid_regridder.regrid(mesh_input) # For a flat surface, we would expect the fractional part of these values # to be either 1/3 or 2/3. Since the actual surface lies on a sphere, and # due to the way ESMF calculates these values, the expected output is # slightly different. It's worth noting that the finer the resolution, the # closer these numbers are. Since the grids/meshes lie on coarse steps of # about 10 degrees, we can expect most cases to behave more similarly to # bilinear regridders on flat surfaces. expected_grid_output = np.array([ [0.0, 2.0], [0.6662902773937054, 2.6662902773105808], [-1, 3.333709722689418], ]) expected_grid_mask = np.array([[0, 0], [0, 0], [1, 0]]) expected_grid_output = ma.array(expected_grid_output, mask=expected_grid_mask) assert ma.allclose(expected_grid_output, grid_output) grid_to_mesh_regridder = Regridder(grid, node_mesh, method="bilinear") grid_input = np.array([[0, 0], [1, 0], [2, 1]]) mesh_output = grid_to_mesh_regridder.regrid(grid_input) expected_mesh_output = ma.array([0.0, 1.5, 0.0, 0.5, -1], mask=[0, 0, 0, 0, 1]) assert ma.allclose(expected_mesh_output, mesh_output) grid_to_face_mesh_regridder = Regridder(grid, face_mesh, method="bilinear") grid_input_2 = np.array([[0, 0], [1, 0], [4, 1]]) face_mesh_output = grid_to_face_mesh_regridder.regrid(grid_input_2) expected_face_mesh_output = np.array([0.0, 1.4888258584989558]) assert ma.allclose(expected_face_mesh_output, face_mesh_output) def _give_extra_dims(array): result = np.stack([array, array + 1]) result = np.stack([result, result + 10, result + 100]) return result extra_dim_mesh_input = _give_extra_dims(mesh_input) extra_dim_grid_output = mesh_to_grid_regridder.regrid(extra_dim_mesh_input) extra_dim_expected_grid_output = _give_extra_dims(expected_grid_output) assert ma.allclose(extra_dim_expected_grid_output, extra_dim_grid_output) extra_dim_grid_input = _give_extra_dims(grid_input) extra_dim_mesh_output = grid_to_mesh_regridder.regrid(extra_dim_grid_input) extra_dim_expected_mesh_output = _give_extra_dims(expected_mesh_output) assert ma.allclose(extra_dim_expected_mesh_output, extra_dim_mesh_output)
def test_Regridder_regrid(): """Basic test for :meth:`~esmf_regrid.esmf_regridder.Regridder.regrid`.""" lon, lat, lon_bounds, lat_bounds = make_grid_args(2, 3) src_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) lon, lat, lon_bounds, lat_bounds = make_grid_args(3, 2) tgt_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) # Set up the regridder with precomputed weights. rg = Regridder(src_grid, tgt_grid, precomputed_weights=_expected_weights()) src_array = np.array([[1.0, 1.0], [1.0, 0.0], [1.0, 0.0]]) src_masked = ma.array(src_array, mask=np.array([[1, 0], [0, 0], [0, 0]])) # Regrid with unmasked data. result_nomask = rg.regrid(src_array) expected_nomask = ma.array([ [1.0, 0.8336393373988409, 0.6674194025656824], [1.0, 0.4999999999999997, 0.0], ]) assert ma.allclose(result_nomask, expected_nomask) # Regrid with an masked array with no masked points. result_ma_nomask = rg.regrid(ma.array(src_array)) assert ma.allclose(result_ma_nomask, expected_nomask) # Regrid with a fully masked array. result_fullmask = rg.regrid(ma.array(src_array, mask=True)) expected_fulmask = ma.array(np.zeros([2, 3]), mask=True) assert ma.allclose(result_fullmask, expected_fulmask) # Regrid with a masked array containing a masked point. result_withmask = rg.regrid(src_masked) expected_withmask = ma.array([ [0.9999999999999999, 0.7503444126612077, 0.6674194025656824], [1.0, 0.4999999999999997, 0.0], ]) assert ma.allclose(result_withmask, expected_withmask) # Regrid while setting mdtol. result_half_mdtol = rg.regrid(src_masked, mdtol=0.5) expected_half_mdtol = ma.array(expected_withmask, mask=np.array([[1, 0, 1], [0, 0, 0]])) assert ma.allclose(result_half_mdtol, expected_half_mdtol) # Regrid with norm_type="dstarea". result_dstarea = rg.regrid(src_masked, norm_type="dstarea") expected_dstarea = ma.array([ [0.3325805974343169, 0.4999999999999999, 0.6674194025656823], [0.9999999999999998, 0.499931367542066, 0.0], ]) assert ma.allclose(result_dstarea, expected_dstarea) def _give_extra_dims(array): result = np.stack([array, array + 1]) result = np.stack([result, result + 10, result + 100]) return result # Regrid with multiple extra dimensions. extra_dim_src = _give_extra_dims(src_array) extra_dim_expected = _give_extra_dims(expected_nomask) extra_dim_result = rg.regrid(extra_dim_src) assert ma.allclose(extra_dim_result, extra_dim_expected) # Regrid extra dimensions with different masks. mixed_mask_src = ma.stack([src_array, src_masked]) mixed_mask_expected = np.stack([expected_nomask, expected_withmask]) mixed_mask_result = rg.regrid(mixed_mask_src) assert ma.allclose(mixed_mask_result, mixed_mask_expected) assert src_array.T.shape != src_array.shape with pytest.raises(ValueError): _ = rg.regrid(src_array.T) with pytest.raises(ValueError): _ = rg.regrid(src_masked, norm_type="INVALID")
def test_Regridder_init_small(): """ Simplified test for :meth:`~esmf_regrid.esmf_regridder.Regridder.regrid`. This test is designed to be simple enough to generate predictable weights. With predictable weights it is easier to check that the weights are associated with the correct indices. """ # The following ASCII visualisation describes the source and target grids # and the indices which ESMF assigns to their cells. # Analysis of the weights dict returned by ESMF confirms that this is # indeed the indexing which ESMF assigns these grids. # # 30 +---+---+ +-------+ # | 3 | 6 | | | # 20 +---+---+ | 2 | # | 2 | 5 | | | # 10 +---+---+ +-------+ # | 1 | 4 | | 1 | # 0 +---+---+ +-------+ # 0 10 20 0 20 def _get_points(bounds): points = (bounds[:-1] + bounds[1:]) / 2 return points lon_bounds = np.array([0, 10, 20]) lat_bounds = np.array([0, 10, 20, 30]) lon, lat = _get_points(lon_bounds), _get_points(lat_bounds) src_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) assert src_grid.shape == (3, 2) assert src_grid._index_offset() == 1 lon_bounds = np.array([0, 20]) lat_bounds = np.array([0, 10, 30]) lon, lat = _get_points(lon_bounds), _get_points(lat_bounds) tgt_grid = GridInfo(lon, lat, lon_bounds, lat_bounds) assert tgt_grid.shape == (2, 1) assert tgt_grid._index_offset() == 1 rg = Regridder(src_grid, tgt_grid) result = rg.weight_matrix weights_dict = {} weights_dict["row_dst"] = ( np.array([1, 1, 1, 1, 2, 2, 2, 2], dtype=np.int32) - src_grid._index_offset()) weights_dict["col_src"] = ( np.array([1, 2, 4, 5, 2, 3, 5, 6], dtype=np.int32) - tgt_grid._index_offset()) # The following weights are calculated from grids on a sphere with great circles # defining the lines. Because of this, weights are not exactly the same as they # would be in euclidean geometry and there are some small additional weights # where the cells would not ordinarily overlap in a euclidean grid. weights_dict["weights"] = np.array([ 0.4962897, 0.0037103, # Small weight due to using great circle lines 0.4962897, 0.0037103, # Small weight due to using great circle lines 0.25484249, 0.24076863, 0.25484249, 0.24076863, ]) expected_weights = scipy.sparse.csr_matrix( (weights_dict["weights"], (weights_dict["row_dst"], weights_dict["col_src"]))) assert np.allclose(result.toarray(), expected_weights.toarray())