def test_init(): build_rtree(dtype=np.float32) build_rtree(dtype=np.float64) with pytest.raises(ValueError): build_rtree(np.int8) with pytest.raises(ValueError): mesh = pyinterp.RTree() mesh.__setstate__((1, )) with pytest.raises(ValueError): pyinterp.RTree(ndims=1)
def _spatial_interp(z_model: da.Array, x_model: da.Array, y_model: da.Array, x_sat: np.ndarray, y_sat: np.ndarray) -> np.ndarray: """Spatial interpolation of the SSH on the selected maps. Args: z_model (numpy.ndarray): model SSH x_model (numpy.ndarray): model longitude y_model (numpy.ndarray): model latitude x_sat (numpy.ndarray): satellite longitude y_sat (numpy.ndarray): satellite latitude Returns: numpy.ndarray: interpolated SSH in space. """ mesh = pyinterp.RTree() mesh.packing( np.vstack((x_model.compute(), y_model.compute())).T, z_model.compute()) z, _ = mesh.radial_basis_function( np.vstack((x_sat, y_sat)).T.astype("float32"), within=True, k=11, rbf="thin_plate", num_threads=1, ) return z.astype("float32")
def load_data(): ds = xr.load_dataset(GRID) z = ds.mss.T x, y = np.meshgrid(ds.lon.values, ds.lat.values, indexing='ij') mesh = pyinterp.RTree() mesh.packing(np.vstack((x.flatten(), y.flatten())).T, z.values.flatten()) return mesh
def build_rtree(dtype): lon = np.arange(-180, 180, 10, dtype=dtype) lat = np.arange(-90, 90, 10, dtype=dtype) lon, lat = np.meshgrid(lon, lat) data = lon * 0 mesh = pyinterp.RTree(dtype=dtype) assert isinstance(mesh, pyinterp.RTree) assert len(mesh) == 0 assert not bool(mesh) mesh.packing(np.vstack((lon.flatten(), lat.flatten())).T, data.flatten()) assert len(mesh) == len(lon.flatten()) assert bool(mesh) (x_min, y_min, z_min), (x_max, y_max, z_max) = mesh.bounds() assert x_min == -180 assert y_min == -90.0 assert x_max == 180.0 assert y_max == 80 assert 0 == pytest.approx(z_min, abs=1e-6 if dtype == np.float64 else 0.5) assert 0 == pytest.approx(z_max, abs=1e-6 if dtype == np.float64 else 0.5) mesh.clear() assert len(mesh) == 0 assert not bool(mesh) mesh.insert(np.vstack((lon.flatten(), lat.flatten())).T, data.flatten()) assert len(mesh) == len(lon.flatten()) assert isinstance(pickle.loads(pickle.dumps(mesh)), pyinterp.RTree)
def init(self, dtype): lon = np.arange(-180, 180, 10, dtype=dtype) lat = np.arange(-90, 90, 10, dtype=dtype) lon, lat = np.meshgrid(lon, lat) data = lon * 0 mesh = pyinterp.RTree(dtype=dtype) self.assertIsInstance(mesh, pyinterp.RTree) self.assertEqual(len(mesh), 0) self.assertFalse(bool(mesh)) mesh.packing( np.vstack((lon.flatten(), lat.flatten())).T, data.flatten()) self.assertEqual(len(mesh), len(lon.flatten())) self.assertTrue(bool(mesh)) (x_min, y_min, z_min), (x_max, y_max, z_max) = mesh.bounds() self.assertEqual(x_min, -180) self.assertEqual(y_min, -90.0) self.assertEqual(x_max, 180.0) self.assertEqual(y_max, 80) self.assertAlmostEqual(z_min, 0, delta=1e-6 if dtype == np.float64 else 0.5) self.assertAlmostEqual(z_max, 0, delta=1e-6 if dtype == np.float64 else 0.5) mesh.clear() self.assertEqual(len(mesh), 0) self.assertFalse(bool(mesh)) mesh.insert( np.vstack((lon.flatten(), lat.flatten())).T, data.flatten()) self.assertEqual(len(mesh), len(lon.flatten())) self.assertIsInstance(pickle.loads(pickle.dumps(mesh)), pyinterp.RTree)
def _spatial_interp( z_model: da.Array, x_model: da.Array, y_model: da.Array, x_sat: np.ndarray, y_sat: np.ndarray, ) -> np.ndarray: """Spatial interpolation of SSH from NATL60 model. Args: z_model (da.Array): SSH model x_model (da.Array): longitude model y_model (da.Array): latitude model x_sat (np.ndarray): longitude satellite y_sat (np.ndarray): latitude satellite Returns: np.ndarray: SSH satellite """ mesh = pyinterp.RTree(dtype=np.dtype("float32")) start_time = time.time() ssh = z_model.compute() defined = ~np.isnan(ssh) ssh = ssh[defined] lon = x_model[defined].compute() lat = y_model[defined].compute() # The tree is built and the interpolation is calculated coordinates = np.vstack((lon, lat)).T del lon, lat LOGGER.debug( "loaded %d MB in %.2fs", (coordinates.nbytes + ssh.nbytes) // 1024**2, time.time() - start_time, ) start_time = time.time() mesh.packing(coordinates, ssh) del coordinates, ssh LOGGER.debug("mesh build in %.2fs", time.time() - start_time) start_time = time.time() z_sat, _ = mesh.radial_basis_function( np.vstack((x_sat, y_sat)).T.astype("float32"), within=True, k=11, radius=8000, rbf="thin_plate", num_threads=1, ) LOGGER.debug("interpolation done in %.2fs", time.time() - start_time) del mesh return z_sat.astype("float32")
def _spatial_interp(z_model: da.array, x_model: da.array, y_model: da.array, x_sat: np.ndarray, y_sat: np.ndarray): mesh = pyinterp.RTree(dtype="float32") x, y, z = (), (), () start_time = time.time() for face in range(13): x_face = x_model[face, :].compute() y_face = y_model[face, :].compute() # We test if the face covers the satellite positions. ix0, ix1 = x_face.min(), x_face.max() iy0, iy1 = y_face.min(), y_face.max() box = pyinterp.geodetic.Box2D(pyinterp.geodetic.Point2D(ix0, iy0), pyinterp.geodetic.Point2D(ix1, iy1)) mask = box.covered_by(x_sat, y_sat) if not np.any(mask == 1): continue del box, mask # The undefined values are filtered z_face = z_model[face, :].compute() defined = ~np.isnan(z_face) x += (x_face[defined].flatten(), ) y += (y_face[defined].flatten(), ) z += (z_face[defined].flatten(), ) # The tree is built and the interpolation is calculated x = np.concatenate(x) y = np.concatenate(y) coordinates = np.vstack((x, y)).T del x, y z = np.concatenate(z) LOGGER.debug("loaded %d MB in %.2fs", (coordinates.nbytes + z.nbytes) // 1024**2, time.time() - start_time) start_time = time.time() mesh.packing(coordinates, z) LOGGER.debug("mesh build in %.2fs", time.time() - start_time) del coordinates, z start_time = time.time() z, _ = mesh.radial_basis_function(np.vstack( (x_sat, y_sat)).T.astype("float32"), within=True, k=11, radius=55000, rbf="thin_plate", num_threads=1) LOGGER.debug("interpolation done in %.2fs", time.time() - start_time) del mesh return z.astype("float32")
def test_init(self): self.init(dtype=np.float32) self.init(dtype=np.float64) with self.assertRaises(ValueError): self.init(np.int8) with self.assertRaises(ValueError): mesh = pyinterp.RTree() mesh.__setstate__((1, ))
def hinterp(ds, var, coords=None): """ This is needs proper documentation: https://numpydoc.readthedocs.io/en/latest/format.html """ import pyinterp #create Tree object mesh = pyinterp.RTree() #L = ds.dims['x_r'] # NL: assigned but not used #M = ds.dims['y_r'] #N = ds.dims['s_r'] z_r = get_z(ds) #coords = np.array([coords]) # where I know the values z_r = get_z(ds) vslice = [] #lon_r = np.tile(ds.lon_r.values,ds.dims['s_r']).reshape(ds.dims['s_r'], ds.dims['y_r'], ds.dims['x_r']) lon_r = (np.tile(ds.lon_r.values, (ds.dims['s_r'], 1, 1)).reshape(ds.dims['s_r'], ds.dims['y_r'], ds.dims['x_r'])) lat_r = (np.tile(ds.lat_r.values, (ds.dims['s_r'], 1, 1)).reshape(ds.dims['s_r'], ds.dims['y_r'], ds.dims['x_r'])) z_r = get_z(ds) mesh.packing( np.vstack((lon_r.flatten(), lat_r.flatten(), z_r.values.flatten())).T, var.values.flatten()) # where I want the values zcoord = np.zeros_like(ds.lon_r.values) zcoord[:] = coords vslice, neighbors = mesh.inverse_distance_weighting( np.vstack((ds.lon_r.values.flatten(), ds.lat_r.values.flatten(), zcoord.flatten())).T, within=True) # Extrapolation is forbidden) # The undefined values must be set to nan. print(ds.mask_rho.values) #mask=np.where(ds.mask_rho.values==1.,) # NL: assigned but not used vslice[int(ds.mask_rho.values)] = float("nan") vslice = xr.DataArray(np.asarray( vslice.reshape(ds.dims['y_r'], ds.dims['x_r'])), dims=('x_r', 'y_r')) yslice = ds.lat_r xslice = ds.lon_r return [xslice, yslice, vslice]
def _spatial_interp_2D(z_model: da.array, x_model: da.array, y_model: da.array, x_sat: np.ndarray, y_sat: np.ndarray): mesh = pyinterp.RTree(dtype="float32") x, y, z = (), (), () start_time = time.time() x_face = x_model.compute() y_face = y_model.compute() # We test if the face covers the satellite positions. ix0, ix1 = x_face.min().values, x_face.max().values iy0, iy1 = y_face.min().values, y_face.max().values box = pyinterp.geodetic.Box2D(pyinterp.geodetic.Point2D(ix0, iy0), pyinterp.geodetic.Point2D(ix1, iy1)) mask = box.covered_by(x_sat, y_sat) if not np.any(mask == 1): print("no covers") del box, mask # The undefined values are filtered z_face = z_model.compute() defined = ~np.isnan(z_face) # The tree is built and the interpolation is calculated x = x_face.values[defined] y = y_face.values[defined] coordinates = np.vstack((x, y)).T del x, y z = z_face.values[defined] LOGGER.info("loaded %d MB in %.2fs", (coordinates.nbytes + z.nbytes) // 1024**2, time.time() - start_time) start_time = time.time() mesh.packing(coordinates, z) LOGGER.info("mesh build in %.2fs", time.time() - start_time) del coordinates, z start_time = time.time() z, _ = mesh.inverse_distance_weighting(np.vstack( (x_sat, y_sat)).T.astype("float32"), within=True, k=11, radius=8000, num_threads=1) LOGGER.debug("interpolation done in %.2fs", time.time() - start_time) del mesh return z.astype("float32")
def _rtree(ds: xr.Dataset, index: np.uint64) -> pyinterp.RTree: """Constructs the interpolator.""" ssh = ds.variables["elev"].isel(dict(time=index)).values # Filter out NaN values. mask = ~np.isnan(ssh) lon = ds.variables["SCHISM_hgrid_node_x"].values[mask] lat = ds.variables["SCHISM_hgrid_node_y"].values[mask] ssh = ssh[mask] coordinates = np.vstack((lon, lat)).T mesh = pyinterp.RTree(dtype=np.dtype("float32")) mesh.packing(coordinates, ssh) return mesh
def interp_low(da, df, **kwargs): """ low level part that interpolate the field https://pangeo-pyinterp.readthedocs.io/en/latest/generated/pyinterp.RTree.inverse_distance_weighting.html#pyinterp.RTree.inverse_distance_weighting """ mesh = pyinterp.RTree() mesh.packing( np.vstack((da.XC.values.flatten(), da.YC.values.flatten())).T, da.values.flatten(), ) dkwargs = dict(within=True, radius=None, k=8, num_threads=0) # num_threads=0 uses all cpus, set to 1 if you don"t want this dkwargs.update(**kwargs) idw_eta, neighbors = mesh.inverse_distance_weighting( np.vstack((df["lon"], df["lat"])).T, **dkwargs) df_out = df["trajectory"].to_frame() df_out.loc[:, da.name + "_interpolated"] = idw_eta[:] return df_out
The interpolation of this object is based on a :py:class:`R*Tree <pyinterp.RTree>` structure. To begin with, we start by building this object. By default, this object considers the WGS-84 geodetic coordinate system. But you can define another one using the class :py:class:`System <pyinterp.geodetic.System>`. """ import numpy import cartopy.crs import cartopy.mpl.ticker import intake import matplotlib.pyplot #%% import pyinterp mesh = pyinterp.RTree() #%% # Then, we will insert points into the tree. The class allows you to add points # using two algorithms. The first one, called :py:meth:`packing # <pyinterp.RTree.packing>`, will enable you to enter the values in the tree at # once. This mechanism is the recommended solution to create an optimized # in-memory structure, both in terms of construction time and queries. When this # is not possible, you can insert new information into the tree as you go along # using the :py:meth:`insert <pyinterp.RTree.insert>` method. cat_url = "https://raw.githubusercontent.com/pangeo-data/pangeo-datastore" \ "/master/intake-catalogs/ocean/llc4320.yaml" cat = intake.open_catalog(cat_url) #%% # Grid subsampling (orginal volume is too huge for this example)