def test_get_bounding_corners_dask(self): """Test finding surrounding bounding corners.""" import dask.array as da from pyresample.bilinear.xarr import (_get_input_xy_dask, _get_bounding_corners_dask) from pyresample._spatial_mp import Proj from pyresample import CHUNK_SIZE proj = Proj(self.target_def.proj_str) out_x, out_y = self.target_def.get_proj_coords(chunks=CHUNK_SIZE) out_x = da.ravel(out_x) out_y = da.ravel(out_y) in_x, in_y = _get_input_xy_dask(self.source_def, proj, da.from_array(self.valid_input_index), da.from_array(self.index_array)) pt_1, pt_2, pt_3, pt_4, ia_ = _get_bounding_corners_dask( in_x, in_y, out_x, out_y, self.neighbours, da.from_array(self.index_array)) self.assertTrue(pt_1.shape == pt_2.shape == pt_3.shape == pt_4.shape == (self.target_def.size, 2)) self.assertTrue(ia_.shape == (self.target_def.size, 4)) # Check which of the locations has four valid X/Y pairs by # finding where there are non-NaN values res = da.sum(pt_1 + pt_2 + pt_3 + pt_4, axis=1).compute() self.assertEqual(np.sum(~np.isnan(res)), 10)
def test_get_corner_dask(self): """Test finding the closest corners.""" import dask.array as da from pyresample.bilinear.xarr import (_get_corner_dask, _get_input_xy_dask) from pyresample import CHUNK_SIZE from pyresample._spatial_mp import Proj proj = Proj(self.target_def.proj_str) in_x, in_y = _get_input_xy_dask(self.source_def, proj, da.from_array(self.valid_input_index), da.from_array(self.index_array)) out_x, out_y = self.target_def.get_proj_coords(chunks=CHUNK_SIZE) out_x = da.ravel(out_x) out_y = da.ravel(out_y) # Some copy&paste from the code to get the input out_x_tile = np.reshape(np.tile(out_x, self.neighbours), (self.neighbours, out_x.size)).T out_y_tile = np.reshape(np.tile(out_y, self.neighbours), (self.neighbours, out_y.size)).T x_diff = out_x_tile - in_x y_diff = out_y_tile - in_y stride = np.arange(x_diff.shape[0]) # Use lower left source pixels for testing valid = (x_diff > 0) & (y_diff > 0) x_3, y_3, idx_3 = _get_corner_dask(stride, valid, in_x, in_y, da.from_array(self.index_array)) self.assertTrue( x_3.shape == y_3.shape == idx_3.shape == (self.target_def.size, )) # Four locations have no data to the lower left of them (the # bottom row of the area self.assertEqual(np.sum(np.isnan(x_3.compute())), 4)
def test_get_output_xy(self): """Test calculation of output xy-coordinates.""" from pyresample.bilinear import _get_output_xy from pyresample._spatial_mp import Proj proj = Proj(self.target_def.proj_str) out_x, out_y = _get_output_xy(self.target_def, proj) self.assertTrue(out_x.all()) self.assertTrue(out_y.all())
def __init__(self, target_area, source_lons, source_lats): self.target_area = target_area self.source_lons = source_lons self.source_lats = source_lats self.prj = Proj(self.target_area.proj_dict) self.x_idxs = None self.y_idxs = None self.idxs = None self._get_indices() self.counts = None
def test_get_input_xy(self): """Test calculation of input xy-coordinates.""" from pyresample.bilinear import _get_input_xy from pyresample._spatial_mp import Proj proj = Proj(self.target_def.proj_str) in_x, in_y = _get_input_xy(self.swath_def, proj, self.input_idxs, self.idx_ref) self.assertTrue(in_x.all()) self.assertTrue(in_y.all())
def test_get_bounding_corners(self): proj = Proj(self.target_def.proj_str) out_x, out_y = bil._get_output_xy(self.target_def, proj) in_x, in_y = bil._get_input_xy(self.swath_def, proj, self.input_idxs, self.idx_ref) res = bil._get_bounding_corners(in_x, in_y, out_x, out_y, self.neighbours, self.idx_ref) for i in range(len(res) - 1): pt_ = res[i] for j in range(2): # Only the sixth output location has four valid corners self.assertTrue(np.isfinite(pt_[5, j]))
def test_get_input_xy(self): """Test computation of input X and Y coordinates in target proj.""" from pyresample.bilinear.xarr import _get_input_xy from pyresample._spatial_mp import Proj proj = Proj(self.target_def.proj_str) in_x, in_y = _get_input_xy(self.source_def, proj, self._valid_input_index, self._index_array) self.assertTrue(in_x.shape, (self.target_def.size, 32)) self.assertTrue(in_y.shape, (self.target_def.size, 32)) self.assertTrue(in_x.all()) self.assertTrue(in_y.all())
def _convert_units(var, name, units, p, proj_dict, inverse=False, center=None): """Converts units from lon/lat to projection coordinates (meters). If `inverse` it True then the inverse calculation is done. """ from pyproj import transform from pyresample._spatial_mp import Proj if var is None: return None if isinstance(var, DataArray): units = var.units var = tuple(var.data.tolist()) if p.is_latlong() and not ('deg' == units or 'degrees' == units): raise ValueError( 'latlon/latlong projection cannot take {0} as units: {1}'.format( units, name)) # Check if units are an angle. is_angle = ('deg' == units or 'degrees' == units) if ('deg' in units) and not is_angle: logging.warning('units provided to {0} are incorrect: {1}'.format( name, units)) # Convert from var projection units to projection units given by projection from user. if not is_angle: if units == 'meters' or units == 'metres': units = 'm' if proj_dict.get('units', 'm') != units: tmp_proj_dict = proj_dict.copy() tmp_proj_dict['units'] = units var = transform(Proj(tmp_proj_dict, preserve_units=True), p, *var) if name == 'center': var = _round_poles(var, units, p) # Return either degrees or meters depending on if the inverse is true or not. # Don't convert if inverse is True: Want degrees. # Converts list-like from degrees to meters. if is_angle and not inverse: if name in ('radius', 'resolution'): var = _distance_from_center_forward(var, center, p) else: var = p(*var, errcheck=True) # Don't convert if inverse is False: Want meters. elif not is_angle and inverse: # Converts list-like from meters to degrees. var = p(*var, inverse=True, errcheck=True) if name in ['radius', 'resolution']: var = (abs(var[0]), abs(var[1])) return var
def test_get_bounding_corners(self): """Test calculation of bounding corners.""" from pyresample.bilinear import (_get_output_xy, _get_input_xy, _get_bounding_corners) from pyresample._spatial_mp import Proj proj = Proj(self.target_def.proj_str) out_x, out_y = _get_output_xy(self.target_def, proj) in_x, in_y = _get_input_xy(self.swath_def, proj, self.input_idxs, self.idx_ref) res = _get_bounding_corners(in_x, in_y, out_x, out_y, self.neighbours, self.idx_ref) for i in range(len(res) - 1): pt_ = res[i] for j in range(2): # Only the sixth output location has four valid corners self.assertTrue(np.isfinite(pt_[5, j]))
def test_get_four_closest_corners(self): """Test calculation of bounding corners.""" from pyresample.bilinear import (_get_output_xy, _get_input_xy, _get_four_closest_corners) from pyresample._spatial_mp import Proj proj = Proj(self.target_def.proj_str) out_x, out_y = _get_output_xy(self.target_def) in_x, in_y = _get_input_xy(self.source_def, proj, self.input_idxs, self.idx_ref) (pt_1, pt_2, pt_3, pt_4), ia_ = _get_four_closest_corners(in_x, in_y, out_x, out_y, self._neighbours, self.idx_ref) self.assertTrue(pt_1.shape == pt_2.shape == pt_3.shape == pt_4.shape == (self.target_def.size, 2)) self.assertTrue(ia_.shape == (self.target_def.size, 4)) # Check which of the locations has four valid X/Y pairs by # finding where there are non-NaN values res = np.sum(pt_1 + pt_2 + pt_3 + pt_4, axis=1) self.assertEqual(np.sum(~np.isnan(res)), 10)
def create_area_def(area_id, projection, width=None, height=None, area_extent=None, shape=None, upper_left_extent=None, center=None, resolution=None, radius=None, units=None, **kwargs): """Takes data the user knows and tries to make an area definition from what can be found. Parameters ---------- area_id : str ID of area projection : dict or str Projection parameters as a proj4_dict or proj4_string description : str, optional Description/name of area. Defaults to area_id proj_id : str, optional ID of projection (deprecated) units : str, optional Units that provided arguments should be interpreted as. This can be one of 'deg', 'degrees', 'meters', 'metres', and any parameter supported by the `cs2cs -lu <https://proj4.org/apps/cs2cs.html#cmdoption-cs2cs-lu>`_ command. Units are determined in the following priority: 1. units expressed with each variable through a DataArray's attrs attribute. 2. units passed to ``units`` 3. units used in ``projection`` 4. meters width : str, optional Number of pixels in the x direction height : str, optional Number of pixels in the y direction area_extent : list, optional Area extent as a list (lower_left_x, lower_left_y, upper_right_x, upper_right_y) shape : list, optional Number of pixels in the y and x direction (height, width) upper_left_extent : list, optional Upper left corner of upper left pixel (x, y) center : list, optional Center of projection (x, y) resolution : list or float, optional Size of pixels: (dx, dy) radius : list or float, optional Length from the center to the edges of the projection (dx, dy) rotation: float, optional rotation in degrees(negative is cw) nprocs : int, optional Number of processor cores to be used lons : numpy array, optional Grid lons lats : numpy array, optional Grid lats optimize_projection: Whether the projection parameters have to be optimized for a DynamicAreaDefinition. Returns ------- AreaDefinition or DynamicAreaDefinition : AreaDefinition or DynamicAreaDefinition If shape and area_extent are found, an AreaDefinition object is returned. If only shape or area_extent can be found, a DynamicAreaDefinition object is returned Raises ------ ValueError: If neither shape nor area_extent could be found Notes ----- * ``resolution`` and ``radius`` can be specified with one value if dx == dy * If ``resolution`` and ``radius`` are provided as angles, center must be given or findable. In such a case, they represent [projection x distance from center[0] to center[0]+dx, projection y distance from center[1] to center[1]+dy] """ from pyresample._spatial_mp import Proj description = kwargs.pop('description', area_id) proj_id = kwargs.pop('proj_id', None) # Get a proj4_dict from either a proj4_dict or a proj4_string. proj_dict = _get_proj_data(projection) try: p = Proj(proj_dict, preserve_units=True) except RuntimeError: return _make_area(area_id, description, proj_id, proj_dict, shape, area_extent, **kwargs) # If no units are provided, try to get units used in proj_dict. If still none are provided, use meters. if units is None: units = proj_dict.get('units', 'm' if not p.is_latlong() else 'degrees') # Allow height and width to be provided for more consistency across functions in pyresample. if height is not None or width is not None: shape = _validate_variable(shape, (height, width), 'shape', ['height', 'width']) # Makes sure list-like objects are list-like, have the right shape, and contain only numbers. center = _verify_list('center', center, 2) radius = _verify_list('radius', radius, 2) upper_left_extent = _verify_list('upper_left_extent', upper_left_extent, 2) resolution = _verify_list('resolution', resolution, 2) shape = _verify_list('shape', shape, 2) area_extent = _verify_list('area_extent', area_extent, 4) # Converts from lat/lon to projection coordinates (x,y) if not in projection coordinates. Returns tuples. center = _convert_units(center, 'center', units, p, proj_dict) upper_left_extent = _convert_units(upper_left_extent, 'upper_left_extent', units, p, proj_dict) if area_extent is not None: # convert area extent, pass as (X, Y) area_extent_ll = area_extent[:2] area_extent_ur = area_extent[2:] area_extent_ll = _convert_units(area_extent_ll, 'area_extent', units, p, proj_dict) area_extent_ur = _convert_units(area_extent_ur, 'area_extent', units, p, proj_dict) area_extent = area_extent_ll + area_extent_ur # Fills in missing information to attempt to create an area definition. if area_extent is None or shape is None: area_extent, shape = _extrapolate_information(area_extent, shape, center, radius, resolution, upper_left_extent, units, p, proj_dict) return _make_area(area_id, description, proj_id, proj_dict, shape, area_extent, **kwargs)
def test_get_output_xy(self): proj = Proj(self.target_def.proj_str) out_x, out_y = bil._get_output_xy(self.target_def, proj) self.assertTrue(out_x.all()) self.assertTrue(out_y.all())
def _get_input_xy(self): return _get_input_xy(self._source_geo_def, Proj(self._target_geo_def.proj_str), self._valid_input_index, self._index_array)
def get_bil_info(source_geo_def, target_area_def, radius=50e3, neighbours=32, nprocs=1, masked=False, reduce_data=True, segments=None, epsilon=0): """Calculate information needed for bilinear resampling. source_geo_def : object Geometry definition of source data target_area_def : object Geometry definition of target area radius : float, optional Cut-off distance in meters neighbours : int, optional Number of neighbours to consider for each grid point when searching the closest corner points nprocs : int, optional Number of processor cores to be used for getting neighbour info masked : bool, optional If true, return masked arrays, else return np.nan values for invalid points (default) reduce_data : bool, optional Perform initial coarse reduction of source dataset in order to reduce execution time segments : int or None Number of segments to use when resampling. If set to None an estimate will be calculated epsilon : float, optional Allowed uncertainty in meters. Increasing uncertainty reduces execution time Returns ------- t__ : numpy array Vertical fractional distances from corner to the new points s__ : numpy array Horizontal fractional distances from corner to the new points input_idxs : numpy array Valid indices in the input data idx_arr : numpy array Mapping array from valid source points to target points """ # Check source_geo_def # if isinstance(source_geo_def, tuple): # from pyresample.geometry import SwathDefinition # lons, lats = _mask_coordinates(source_geo_def[0], source_geo_def[1]) # source_geo_def = SwathDefinition(lons, lats) # Calculate neighbour information with warnings.catch_warnings(): warnings.simplefilter("ignore") (input_idxs, output_idxs, idx_ref, dists) = \ kd_tree.get_neighbour_info(source_geo_def, target_area_def, radius, neighbours=neighbours, nprocs=nprocs, reduce_data=reduce_data, segments=segments, epsilon=epsilon) del output_idxs, dists # Reduce index reference input_size = input_idxs.sum() index_mask = (idx_ref == input_size) idx_ref = np.where(index_mask, 0, idx_ref) # Get output projection as pyproj object proj = Proj(target_area_def.proj_str) # Get output x/y coordinates out_x, out_y = _get_output_xy(target_area_def, proj) # Get input x/y coordinates in_x, in_y = _get_input_xy(source_geo_def, proj, input_idxs, idx_ref) # Get the four closest corner points around each output location pt_1, pt_2, pt_3, pt_4, idx_ref = \ _get_bounding_corners(in_x, in_y, out_x, out_y, neighbours, idx_ref) # Calculate vertical and horizontal fractional distances t and s t__, s__ = _get_ts(pt_1, pt_2, pt_3, pt_4, out_x, out_y) # Mask NaN values if masked: mask = np.isnan(t__) | np.isnan(s__) t__ = np.ma.masked_where(mask, t__) s__ = np.ma.masked_where(mask, s__) return t__, s__, input_idxs, idx_ref
def test_get_input_xy(self): proj = Proj(self.target_def.proj_str) in_x, in_y = bil._get_output_xy(self.swath_def, proj) self.assertTrue(in_x.all()) self.assertTrue(in_y.all())
def get_bil_info(self): """Return neighbour info. Returns ------- t__ : numpy array Vertical fractional distances from corner to the new points s__ : numpy array Horizontal fractional distances from corner to the new points input_idxs : numpy array Valid indices in the input data idx_arr : numpy array Mapping array from valid source points to target points """ if self.source_geo_def.size < self.neighbours: warnings.warn('Searching for %s neighbours in %s data points' % (self.neighbours, self.source_geo_def.size)) # Create kd-tree valid_input_idx, resample_kdtree = self._create_resample_kdtree() # This is a numpy array self.valid_input_index = valid_input_idx if resample_kdtree.n == 0: # Handle if all input data is reduced away bilinear_t, bilinear_s, valid_input_index, index_array = \ _create_empty_bil_info(self.source_geo_def, self.target_geo_def) self.bilinear_t = bilinear_t self.bilinear_s = bilinear_s self.valid_input_index = valid_input_idx self.index_array = index_array return bilinear_t, bilinear_s, valid_input_index, index_array target_lons, target_lats = self.target_geo_def.get_lonlats() valid_output_idx = ((target_lons >= -180) & (target_lons <= 180) & (target_lats <= 90) & (target_lats >= -90)) index_array, distance_array = self._query_resample_kdtree( resample_kdtree, target_lons, target_lats, valid_output_idx) # Reduce index reference input_size = da.sum(self.valid_input_index) index_mask = index_array == input_size index_array = da.where(index_mask, 0, index_array) # Get output projection as pyproj object proj = Proj(self.target_geo_def.proj_str) # Get output x/y coordinates out_x, out_y = _get_output_xy_dask(self.target_geo_def, proj) # Get input x/y coordinates in_x, in_y = _get_input_xy_dask(self.source_geo_def, proj, self.valid_input_index, index_array) # Get the four closest corner points around each output location pt_1, pt_2, pt_3, pt_4, index_array = \ _get_bounding_corners_dask(in_x, in_y, out_x, out_y, self.neighbours, index_array) # Calculate vertical and horizontal fractional distances t and s t__, s__ = _get_ts_dask(pt_1, pt_2, pt_3, pt_4, out_x, out_y) self.bilinear_t, self.bilinear_s = t__, s__ self.valid_output_index = valid_output_idx self.index_array = index_array self.distance_array = distance_array return (self.bilinear_t, self.bilinear_s, self.valid_input_index, self.index_array)