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 15 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
79 changes: 79 additions & 0 deletions openeo_processes_dask/process_implementations/cubes/resample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import logging
from typing import Union

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

from openeo_processes_dask.process_implementations.data_model import RasterCube

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: Union[str, int] = None,
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
resolution: Union[str, int] = None,
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
method: str = "near",
align: str = "upper-left",
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
):
"""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."""

if align == "upper-left":
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
logging.warning("Warning: align parameter is unused by current implementation.")

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

elif method not in resample_methods_list:
raise Exception(
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
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("bands", "t", "y", "x")
SerRichard marked this conversation as resolved.
Show resolved Hide resolved

if not projection:
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
projection = data_cp.rio.crs

try:
projection = CRS(projection)
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
except CRSError as e:
raise CRSError(f"{projection} Can not be parsed to CRS.")
SerRichard marked this conversation as resolved.
Show resolved Hide resolved

if not resolution:
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
resolution = resolution_from_affine(data_cp.geobox.affine).x

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

if "longitude" in reprojected.dims:
SerRichard marked this conversation as resolved.
Show resolved Hide resolved
reprojected = reprojected.rename({"longitude": "x"})

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

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

# Undo odc specific re-ordering.
reprojected = reprojected.transpose(*data.dims)

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

except ImportError:
dask = None
import math
SerRichard marked this conversation as resolved.
Show resolved Hide resolved

from xarray.core.duck_array_ops import isnull as xr_isnull

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ xgboost = { version = "^1.5.1", optional = true }
rioxarray = { version = ">=0.12.0,<1", optional = true }
odc-algo = { version = "==0.2.3", optional = true }
openeo-pg-parser-networkx = { version = ">=2023.5.1", optional = true }
odc-geo = { version = "^0.3.2", optional = true }
odc-geo = { version = "^0.4.0", optional = true }

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
Expand Down
60 changes: 60 additions & 0 deletions tests/test_resample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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",
)

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.geobox.affine).x == output_res
assert resolution_from_affine(output_cube.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