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

feat: Implementation of resample_spatial to reproject values #103

Merged
merged 34 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d186134
basic implementation of resample_spatial to reproject values
SerRichard May 4, 2023
8d474fb
update function to handle spatial resampling as well as reprojection
SerRichard May 12, 2023
87680cc
fix from pre commit
SerRichard May 15, 2023
c4c7723
pre commit fix
SerRichard May 15, 2023
48931e9
pre commit file edits
SerRichard May 24, 2023
dde83c0
accept reformatting
SerRichard May 24, 2023
1f749e3
resolving conflics and reformatted
SerRichard May 24, 2023
92562d5
add reformatting
SerRichard May 25, 2023
830ee60
add reformat
SerRichard May 25, 2023
aeecb07
accept reformats
SerRichard May 25, 2023
5b034ed
accept reformatting
SerRichard May 25, 2023
0fd1d14
drop broken import
SerRichard May 25, 2023
6b5496c
accept reformatting
SerRichard May 25, 2023
f510654
accept reformatting
SerRichard Jun 5, 2023
4191013
fixed broken tests
SerRichard Jun 5, 2023
ea2efbe
add comment
Jun 6, 2023
f457719
add negative test case
Jun 6, 2023
a8e565b
resolve locally
SerRichard Jun 22, 2023
bb1a177
resolve conf
SerRichard Jun 22, 2023
b0b1563
Merge branch 'main' of github.com:Open-EO/openeo-processes-dask into …
SerRichard Jun 30, 2023
4473660
try merge from main to fix tests and change crs function
SerRichard Jun 30, 2023
7ef18ba
Merge branch 'main' into DP-277-add-resample-spatial
SerRichard Jul 21, 2023
78b0b70
resolve conflicts with main, fix odc geo version, fix imports
SerRichard Aug 14, 2023
83be538
resolve conf
SerRichard Aug 14, 2023
e1c4947
Merge branch 'main' into DP-277-add-resample-spatial
Aug 14, 2023
c3c0638
Update openeo_processes_dask/process_implementations/cubes/resample.py
SerRichard Aug 17, 2023
dc9a4ff
Update openeo_processes_dask/process_implementations/cubes/resample.py
SerRichard Aug 17, 2023
6ce40e7
Update openeo_processes_dask/process_implementations/cubes/resample.py
SerRichard Aug 17, 2023
4132fea
Update openeo_processes_dask/process_implementations/cubes/resample.py
SerRichard Aug 17, 2023
251f8e8
comments updates
SerRichard Aug 17, 2023
9ee6e29
Merge branch 'DP-277-add-resample-spatial' of github.com:Open-EO/open…
SerRichard Aug 17, 2023
3e08f66
import typing optional
SerRichard Aug 17, 2023
8dff319
fix tessts
SerRichard Aug 17, 2023
57af9be
bump process specs
Aug 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions openeo_processes_dask/process_implementations/cubes/resample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import logging
from typing import Optional, Union

import odc.geo.xr
from odc.geo.geobox import resolution_from_affine
from pyproj.crs import CRS, CRSError

from openeo_processes_dask.process_implementations.data_model import RasterCube
from openeo_processes_dask.process_implementations.exceptions import OpenEOException

logger = logging.getLogger(__name__)

resample_methods_list = [
"near",
"bilinear",
"cubic",
"cubicspline",
"lanczos",
"average",
"mode",
"max",
"min",
"med",
"q1",
"q3",
]


def resample_spatial(
data: RasterCube,
projection: Optional[Union[str, int]] = None,
resolution: int = 0,
method: str = "near",
):
"""Resamples the spatial dimensions (x,y) of the data cube to a specified resolution and/or warps the data cube to the target projection. At least resolution or projection must be specified."""

# Assert resampling method is correct.
if method == "near":
method = "nearest"

elif method not in resample_methods_list:
raise OpenEOException(
f'Selected resampling method "{method}" is not available! Please select one of '
f"[{', '.join(resample_methods_list)}]"
)

# Re-order, this is specifically done for odc reproject
data_cp = data.transpose(
data.openeo.band_dims[0],
data.openeo.temporal_dims[0],
data.openeo.y_dim,
data.openeo.x_dim,
)

if projection is None:
projection = data_cp.rio.crs

Check warning on line 56 in openeo_processes_dask/process_implementations/cubes/resample.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/cubes/resample.py#L56

Added line #L56 was not covered by tests

try:
projection = CRS.from_user_input(projection)
except CRSError as e:
raise CRSError(

Check warning on line 61 in openeo_processes_dask/process_implementations/cubes/resample.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/cubes/resample.py#L60-L61

Added lines #L60 - L61 were not covered by tests
f"Provided projection string: '{projection}' can not be parsed to CRS."
) from e

if resolution == 0:
resolution = resolution_from_affine(data_cp.odc.geobox.affine).x

Check warning on line 66 in openeo_processes_dask/process_implementations/cubes/resample.py

View check run for this annotation

Codecov / codecov/patch

openeo_processes_dask/process_implementations/cubes/resample.py#L66

Added line #L66 was not covered by tests

reprojected = data_cp.odc.reproject(
how=projection, resolution=resolution, resampling=method
)

if "longitude" in reprojected.dims and "x" in data.dims:
reprojected = reprojected.rename({"longitude": "x"})

if "latitude" in reprojected.dims and "y" in data.dims:
reprojected = reprojected.rename({"latitude": "y"})

reprojected.attrs["crs"] = data_cp.rio.crs

return reprojected
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
try:
import dask

except ImportError:
dask = None

Expand Down
2 changes: 1 addition & 1 deletion openeo_processes_dask/specs/openeo-processes
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ dask-geopandas = { version = ">=0.2.0,<1", optional = true }
xgboost = { version = "^1.5.1", optional = true }
rioxarray = { version = ">=0.12.0,<1", optional = true }
openeo-pg-parser-networkx = { version = ">=2023.5.1", optional = true }
odc-geo = { version = ">=0.3.2,<1", optional = true }
odc-geo = { version = ">=0.4.1,<1", optional = true }
stac_validator = { version = ">=3.3.1", optional = true }
stackstac = { version = ">=0.4.3", optional = true }
pystac_client = { version = ">=0.6.1", optional = true }
Expand Down
65 changes: 65 additions & 0 deletions tests/test_resample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import numpy as np
import pytest
from odc.geo.geobox import resolution_from_affine
from pyproj.crs import CRS

from openeo_processes_dask.process_implementations.cubes.resample import (
resample_spatial,
)
from tests.general_checks import general_output_checks
from tests.mockdata import create_fake_rastercube


@pytest.mark.parametrize(
"output_crs",
[
3587,
"32633",
"+proj=aeqd +lat_0=53 +lon_0=24 +x_0=5837287.81977 +y_0=2121415.69617 +datum=WGS84 +units=m +no_defs",
"4326",
],
)
@pytest.mark.parametrize("output_res", [5, 30, 60])
@pytest.mark.parametrize("size", [(30, 30, 20, 4)])
@pytest.mark.parametrize("dtype", [np.float32])
def test_resample_spatial(
output_crs, output_res, temporal_interval, bounding_box, random_raster_data
):
"""Test to ensure resolution gets changed correctly."""
input_cube = create_fake_rastercube(
data=random_raster_data,
spatial_extent=bounding_box,
temporal_extent=temporal_interval,
bands=["B02", "B03", "B04", "B08"],
backend="dask",
)

with pytest.raises(Exception):
output_cube = resample_spatial(
data=input_cube, projection=output_crs, resolution=output_res, method="bad"
)

output_cube = resample_spatial(
data=input_cube, projection=output_crs, resolution=output_res
)

general_output_checks(
input_cube=input_cube,
output_cube=output_cube,
verify_attrs=False,
verify_crs=False,
)

assert output_cube.odc.spatial_dims == ("y", "x")
assert output_cube.rio.crs == CRS.from_user_input(output_crs)

if output_crs != "4326":
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
assert resolution_from_affine(output_cube.odc.geobox.affine).x == output_res
assert resolution_from_affine(output_cube.odc.geobox.affine).y == -output_res

if output_cube.rio.crs.is_geographic:
assert min(output_cube.x) >= -180
assert max(output_cube.x) <= 180

assert min(output_cube.y) >= -90
assert max(output_cube.y) <= 90
Loading