Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate AreaDefinition 'rotation' argument #496

Merged
merged 3 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 4 additions & 17 deletions pyresample/area_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ def _create_area_def_from_dict(area_name, params):
'upper_right_xy', 'units'])
params['resolution'] = _capture_subarguments(params, 'resolution', ['resolution', 'dx', 'dy', 'units'])
params['radius'] = _capture_subarguments(params, 'radius', ['radius', 'dx', 'dy', 'units'])
params['rotation'] = _capture_subarguments(params, 'rotation', ['rotation', 'units'])
area_def = create_area_def(**params)
return area_def

Expand Down Expand Up @@ -332,19 +331,11 @@ def _create_area(area_id, area_content):
config = config_obj.dict()
config['REGION'] = area_id

try:
string_types = basestring
except NameError:
string_types = str
if not isinstance(config['NAME'], string_types):
if not isinstance(config['NAME'], str):
config['NAME'] = ', '.join(config['NAME'])

config['XSIZE'] = int(config['XSIZE'])
config['YSIZE'] = int(config['YSIZE'])
if 'ROTATION' in config.keys():
config['ROTATION'] = float(config['ROTATION'])
else:
config['ROTATION'] = 0
config['AREA_EXTENT'][0] = config['AREA_EXTENT'][0].replace('(', '')
config['AREA_EXTENT'][3] = config['AREA_EXTENT'][3].replace(')', '')

Expand All @@ -354,10 +345,10 @@ def _create_area(area_id, area_content):
config['PCS_DEF'] = _get_proj4_args(config['PCS_DEF'])
return create_area_def(config['REGION'], config['PCS_DEF'], description=config['NAME'], proj_id=config['PCS_ID'],
shape=(config['YSIZE'], config['XSIZE']), area_extent=config['AREA_EXTENT'],
rotation=config['ROTATION'])
)


def get_area_def(area_id, area_name, proj_id, proj4_args, width, height, area_extent, rotation=0):
def get_area_def(area_id, area_name, proj_id, proj4_args, width, height, area_extent):
"""Construct AreaDefinition object from arguments.

Parameters
Expand All @@ -374,8 +365,6 @@ def get_area_def(area_id, area_name, proj_id, proj4_args, width, height, area_ex
Number of pixel in x dimension
height : int
Number of pixel in y dimension
rotation: float
Rotation in degrees (negative is cw)
area_extent : list | tuple
Area extent as a list of ints (LL_x, LL_y, UR_x, UR_y)

Expand Down Expand Up @@ -445,8 +434,6 @@ def create_area_def(area_id, projection, width=None, height=None, area_extent=No
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
Expand Down Expand Up @@ -550,7 +537,7 @@ def _make_area(
return AreaDefinition(area_id, description, proj_id, projection, width, height, area_extent, **kwargs)

return DynamicAreaDefinition(area_id=area_id, description=description, projection=projection, width=width,
height=height, area_extent=area_extent, rotation=kwargs.get('rotation'),
height=height, area_extent=area_extent,
resolution=resolution, optimize_projection=optimize_projection)


Expand Down
57 changes: 7 additions & 50 deletions pyresample/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1006,14 +1006,12 @@ class DynamicAreaDefinition(object):
or a scalar if pixel_size_x == pixel_size_y.
optimize_projection:
Whether the projection parameters have to be optimized.
rotation:
Rotation in degrees (negative is cw)

"""

def __init__(self, area_id=None, description=None, projection=None,
width=None, height=None, area_extent=None,
resolution=None, optimize_projection=False, rotation=None):
resolution=None, optimize_projection=False):
"""Initialize the DynamicAreaDefinition."""
self.area_id = area_id
self.description = description
Expand All @@ -1025,7 +1023,6 @@ def __init__(self, area_id=None, description=None, projection=None,
if isinstance(resolution, (int, float)):
resolution = (resolution, resolution)
self.resolution = resolution
self.rotation = rotation
self._projection = projection

# check if non-dict projections are valid
Expand Down Expand Up @@ -1209,7 +1206,7 @@ def freeze(self, lonslats=None, resolution=None, shape=None, proj_info=None,
area_extent, width, height = self.compute_domain(corners, resolution, shape, projection)
return AreaDefinition(self.area_id, self.description, '',
projection, width, height,
area_extent, self.rotation)
area_extent)

def _compute_bound_centers(self, proj_dict, lonslats, antimeridian_mode):
from pyresample.utils.proj4 import DaskFriendlyTransformer
Expand Down Expand Up @@ -1437,8 +1434,6 @@ class AreaDefinition(_ProjectionDefinition):
y dimension in number of pixels, aka number of grid rows
area_extent : list
Area extent as a list (lower_left_x, lower_left_y, upper_right_x, upper_right_y)
rotation: float, optional
rotation in degrees (negative is clockwise)
nprocs : int, optional
Number of processor cores to be used for certain calculations

Expand All @@ -1456,8 +1451,6 @@ class AreaDefinition(_ProjectionDefinition):
x dimension in number of pixels, aka number of grid columns
height : int
y dimension in number of pixels, aka number of grid rows
rotation: float
rotation in degrees (negative is cw)
size : int
Number of points in grid
area_extent_ll : tuple
Expand Down Expand Up @@ -1489,7 +1482,7 @@ class AreaDefinition(_ProjectionDefinition):
"""

def __init__(self, area_id, description, proj_id, projection, width, height,
area_extent, rotation=None, nprocs=1, lons=None, lats=None,
area_extent, nprocs=1, lons=None, lats=None,
dtype=np.float64):
"""Initialize AreaDefinition."""
super(AreaDefinition, self).__init__(lons, lats, nprocs)
Expand All @@ -1499,10 +1492,6 @@ def __init__(self, area_id, description, proj_id, projection, width, height,
self.width = int(width)
self.height = int(height)
self.crop_offset = (0, 0)
try:
self.rotation = float(rotation)
except TypeError:
self.rotation = 0
if lons is not None:
if lons.shape != self.shape:
raise ValueError('Shape of lon lat grid must match '
Expand Down Expand Up @@ -1614,7 +1603,7 @@ def copy(self, **override_kwargs):
'width': self.width,
'height': self.height,
'area_extent': self.area_extent,
'rotation': self.rotation}
}
kwargs.update(override_kwargs)
return AreaDefinition(**kwargs)

Expand Down Expand Up @@ -1684,8 +1673,6 @@ def from_extent(cls, area_id, projection, shape, area_extent, units=None, **kwar
Description/name of area. Defaults to area_id
proj_id : str, optional
ID of projection
rotation: float, optional
rotation in degrees (negative is cw)
nprocs : int, optional
Number of processor cores to be used
lons : numpy array, optional
Expand Down Expand Up @@ -1733,8 +1720,6 @@ def from_circle(cls, area_id, projection, center, radius, shape=None, resolution
Description/name of area. Defaults to area_id
proj_id : str, optional
ID of projection
rotation: float, optional
rotation in degrees (negative is cw)
nprocs : int, optional
Number of processor cores to be used
lons : numpy array, optional
Expand Down Expand Up @@ -1789,8 +1774,6 @@ def from_area_of_interest(cls, area_id, projection, shape, center, resolution, u
Description/name of area. Defaults to area_id
proj_id : str, optional
ID of projection
rotation: float, optional
rotation in degrees (negative is cw)
nprocs : int, optional
Number of processor cores to be used
lons : numpy array, optional
Expand Down Expand Up @@ -1837,8 +1820,6 @@ def from_ul_corner(cls, area_id, projection, shape, upper_left_extent, resolutio
Description/name of area. Defaults to area_id
proj_id : str, optional
ID of projection
rotation: float, optional
rotation in degrees (negative is cw)
nprocs : int, optional
Number of processor cores to be used
lons : numpy array, optional
Expand Down Expand Up @@ -2009,7 +1990,6 @@ def create_areas_def_legacy(self):
fmt += "\tPCS_DEF:\t{proj_str}\n"
fmt += "\tXSIZE:\t{x_size}\n"
fmt += "\tYSIZE:\t{y_size}\n"
# fmt += "\tROTATION:\t{rotation}\n"
fmt += "\tAREA_EXTENT: {area_extent}\n}};\n"
area_def_str = fmt.format(name=self.description, area_id=self.area_id,
proj_str=proj_str, x_size=self.width,
Expand Down Expand Up @@ -2293,14 +2273,6 @@ def get_lonlat(self, row, col):
lon, lat = self.get_lonlats(nprocs=None, data_slice=(row, col))
return lon.item(), lat.item()

@staticmethod
def _do_rotation(xspan, yspan, rot_deg=0):
"""Apply a rotation factor to a matrix of points."""
rot_rad = np.radians(rot_deg)
rot_mat = np.array([[np.cos(rot_rad), np.sin(rot_rad)], [-np.sin(rot_rad), np.cos(rot_rad)]])
x, y = np.meshgrid(xspan, yspan)
return np.einsum('ji, mni -> jmn', rot_mat, np.dstack([x, y]))

def get_proj_vectors_dask(self, chunks=None, dtype=None):
"""Get projection vectors."""
warnings.warn("'get_proj_vectors_dask' is deprecated, please use "
Expand All @@ -2309,10 +2281,8 @@ def get_proj_vectors_dask(self, chunks=None, dtype=None):
chunks = CHUNK_SIZE # FUTURE: Use a global config object instead
return self.get_proj_vectors(dtype=dtype, chunks=chunks)

def _get_proj_vectors(self, dtype=None, check_rotation=True, chunks=None):
def _get_proj_vectors(self, dtype=None, chunks=None):
"""Get 1D projection coordinates."""
if check_rotation and self.rotation != 0:
warnings.warn("Projection vectors will not be accurate because rotation is not 0", RuntimeWarning)
if dtype is None:
dtype = self.dtype
x, y = _generate_1d_proj_vectors((0, self.width),
Expand Down Expand Up @@ -2374,8 +2344,6 @@ def get_proj_coords(self, data_slice=None, dtype=None, chunks=None):
Removed 'cache' keyword argument and add 'chunks' for creating
dask arrays.
"""
if self.rotation != 0 and chunks is not None:
raise ValueError("'rotation' is not supported with dask operations.")
if dtype is None:
dtype = self.dtype
y_slice, x_slice = self._get_yx_data_slice(data_slice)
Expand All @@ -2386,18 +2354,13 @@ def get_proj_coords(self, data_slice=None, dtype=None, chunks=None):
target_y = target_y[y_slice, x_slice]
return target_x, target_y

target_x, target_y = self._get_proj_vectors(dtype=dtype, check_rotation=False, chunks=chunks)
target_x, target_y = self._get_proj_vectors(dtype=dtype, chunks=chunks)
if y_slice is not None:
target_y = target_y[y_slice]
if x_slice is not None:
target_x = target_x[x_slice]

if self.rotation != 0:
res = self._do_rotation(target_x, target_y, self.rotation)
target_x, target_y = res[0, :, :], res[1, :, :]
else:
target_x, target_y = np.meshgrid(target_x, target_y)

target_x, target_y = np.meshgrid(target_x, target_y)
return target_x, target_y

@staticmethod
Expand Down Expand Up @@ -2438,17 +2401,11 @@ def _proj_coords_dask(self, chunks, dtype):
@property
def projection_x_coords(self):
"""Return projection X coordinates."""
if self.rotation != 0:
# rotation is only supported in 'get_proj_coords' right now
return self.get_proj_coords(data_slice=(0, slice(None)))[0].squeeze()
return self.get_proj_vectors()[0]

@property
def projection_y_coords(self):
"""Return projection Y coordinates."""
if self.rotation != 0:
# rotation is only supported in 'get_proj_coords' right now
return self.get_proj_coords(data_slice=(slice(None), 0))[1].squeeze()
return self.get_proj_vectors()[1]

@property
Expand Down
4 changes: 0 additions & 4 deletions pyresample/test/test_files/areas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ test_meters:
radius:
radius: 3309.9505528339496
units: mi
rotation: 45

test_degrees:
projection:
Expand Down Expand Up @@ -170,9 +169,6 @@ test_degrees:
dx: 49.4217406986
dy: 49.4217406986
units: degrees
rotation:
rotation: 45
units: degrees

ease_sh:
description: Antarctic EASE grid
Expand Down
1 change: 0 additions & 1 deletion pyresample/test/test_geometry/test_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,6 @@ def test_create_area_def_base_combinations(self, projection, center, units, crea
radius=essentials[1],
description=description,
units=units,
rotation=45,
)

should_fail = isinstance(center, str) or len(center) != 2
Expand Down
35 changes: 0 additions & 35 deletions pyresample/test/test_geometry_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

"""
import random
import unittest
from unittest.mock import MagicMock, patch

import dask
Expand Down Expand Up @@ -80,40 +79,6 @@ def test_base_type(self):
f"BaseDefinition did not maintain dtype of longitudes (in:{lons2_ints.dtype} out:{lons.dtype})"


class Test(unittest.TestCase):
"""Unit testing the geometry and geo_filter modules."""

def test_get_proj_coords_rotation(self):
"""Test basic get_proj_coords usage with rotation specified."""
from pyresample.geometry import AreaDefinition
area_id = 'test'
area_name = 'Test area with 2x2 pixels'
proj_id = 'test'
x_size = 10
y_size = 10
area_extent = [1000000, 0, 1050000, 50000]
proj_dict = {"proj": 'laea', 'lat_0': '60', 'lon_0': '0', 'a': '6371228.0', 'units': 'm'}
area_def = AreaDefinition(area_id, area_name, proj_id, proj_dict, x_size, y_size, area_extent, rotation=45)

xcoord, ycoord = area_def.get_proj_coords()
np.testing.assert_allclose(xcoord[0, :],
np.array([742462.120246, 745997.654152, 749533.188058, 753068.721964,
756604.25587, 760139.789776, 763675.323681, 767210.857587,
770746.391493, 774281.925399]))
np.testing.assert_allclose(ycoord[:, 0],
np.array([-675286.976033, -678822.509939, -682358.043845, -685893.577751,
-689429.111657, -692964.645563, -696500.179469, -700035.713375,
-703571.247281, -707106.781187]))

xcoord, ycoord = area_def.get_proj_coords(data_slice=(slice(None, None, 2), slice(None, None, 2)))
np.testing.assert_allclose(xcoord[0, :],
np.array([742462.120246, 749533.188058, 756604.25587, 763675.323681,
770746.391493]))
np.testing.assert_allclose(ycoord[:, 0],
np.array([-675286.976033, -682358.043845, -689429.111657, -696500.179469,
-703571.247281]))


def assert_np_dict_allclose(dict1, dict2):
"""Check allclose on dicts."""
assert set(dict1.keys()) == set(dict2.keys())
Expand Down