Skip to content

Commit 010c214

Browse files
Eoepca test suite (#297)
* array concat handle axis * array append handle axis * fix array apply cases * update for tests * array test update * fix array apply test
1 parent eb3bdb1 commit 010c214

File tree

3 files changed

+65
-70
lines changed

3 files changed

+65
-70
lines changed

openeo_processes_dask/process_implementations/arrays.py

+33-6
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
]
5151

5252

53-
def get_labels(data, dimension="labels", axis=0):
53+
def get_labels(data, dimension="labels", axis=0, dim_labels=None):
5454
if isinstance(data, xr.DataArray):
5555
dimension = data.dims[0] if len(data.dims) == 1 else dimension
5656
if axis:
@@ -61,6 +61,8 @@ def get_labels(data, dimension="labels", axis=0):
6161
labels = []
6262
if isinstance(data, list):
6363
data = np.asarray(data)
64+
if not isinstance(dim_labels, type(None)):
65+
labels = dim_labels
6466
return labels, data
6567

6668

@@ -82,9 +84,7 @@ def array_element(
8284
raise ArrayElementParameterConflict(
8385
"The process `array_element` only allows that either the `index` or the `labels` parameter is set."
8486
)
85-
86-
if isinstance(data, xr.DataArray):
87-
dim_labels, data = get_labels(data, axis=axis)
87+
dim_labels, data = get_labels(data, axis=axis, dim_labels=dim_labels)
8888

8989
if label is not None:
9090
if len(dim_labels) == 0:
@@ -189,7 +189,7 @@ def modify(data):
189189
return modified
190190

191191

192-
def array_concat(array1: ArrayLike, array2: ArrayLike) -> ArrayLike:
192+
def array_concat(array1: ArrayLike, array2: ArrayLike, axis=None) -> ArrayLike:
193193
labels1, array1 = get_labels(array1)
194194
labels2, array2 = get_labels(array2)
195195

@@ -198,7 +198,21 @@ def array_concat(array1: ArrayLike, array2: ArrayLike) -> ArrayLike:
198198
"At least one label exists in both arrays and the conflict must be resolved before."
199199
)
200200

201-
concat = np.concatenate([array1, array2])
201+
if (len(array1.shape) - len(array2.shape)) == 1:
202+
if axis is None:
203+
s1 = np.array(list(array1.shape))
204+
s2 = list(array2.shape)
205+
s2.append(0)
206+
s2 = np.array(s2)
207+
208+
axis = np.argmax(s1 != s2)
209+
210+
array2 = np.expand_dims(array2, axis=axis)
211+
212+
if axis:
213+
concat = np.concatenate([array1, array2], axis=axis)
214+
else:
215+
concat = np.concatenate([array1, array2])
202216

203217
# e.g. concating int32 and str arrays results in the result being cast to a Unicode dtype of a certain length (e.g. <U22).
204218
# There isn't really anything better to do as numpy does not support heterogenuous arrays.
@@ -219,7 +233,20 @@ def array_append(
219233
value: Any,
220234
label: Optional[Any] = None,
221235
dim_labels=None,
236+
axis=None,
222237
) -> ArrayLike:
238+
if axis:
239+
if isinstance(value, list) and len(value) == 1:
240+
value = value[0]
241+
if (isinstance(value, np.ndarray) or isinstance(value, da.core.Array)) and len(
242+
value.flatten()
243+
) == 1:
244+
value = value.flatten()[0]
245+
246+
value = np.take(np.ones_like(data), indices=0, axis=axis) * value
247+
concat = array_concat(data, value, axis=axis)
248+
return concat
249+
223250
if dim_labels:
224251
data = array_create_labeled(data=data, labels=dim_labels)
225252
if label is not None:

openeo_processes_dask/process_implementations/cubes/apply.py

+31-8
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,45 @@ def apply_dimension(
7777
exclude_dims={dimension},
7878
)
7979

80-
reordered_result = result.transpose(*data.dims, ...).rename(
81-
{dimension: target_dimension}
82-
)
80+
reordered_result = result.transpose(*data.dims, ...)
8381

84-
if len(reordered_result[target_dimension]) == 1:
85-
reordered_result[target_dimension] = ["0"]
82+
if dimension in reordered_result.dims:
83+
result_len = len(reordered_result[dimension])
84+
else:
85+
result_len = 1
86+
87+
# Case 1: target_dimension is not defined/ is source dimension
88+
if dimension == target_dimension:
89+
# dimension labels preserved
90+
# if the number of source dimension's values is equal to the number of computed values
91+
if len(reordered_data[dimension]) == result_len:
92+
reordered_result[dimension] == reordered_data[dimension].values
93+
else:
94+
reordered_result[dimension] = np.arange(result_len)
95+
elif target_dimension in reordered_result.dims:
96+
# source dimension is not target dimension
97+
# target dimension exists with a single label only
98+
if len(reordered_result[target_dimension]) == 1:
99+
reordered_result = reordered_result.drop_vars(target_dimension).squeeze(
100+
target_dimension
101+
)
102+
reordered_result = reordered_result.rename({dimension: target_dimension})
103+
reordered_result[dimension] = np.arange(result_len)
104+
else:
105+
raise Exception(
106+
f"Cannot rename dimension {dimension} to {target_dimension} as {target_dimension} already exists in dataset and contains more than one label: {reordered_result[target_dimension]}. See process definition. "
107+
)
108+
else:
109+
# source dimension is not the target dimension and the latter does not exist
110+
reordered_result = reordered_result.rename({dimension: target_dimension})
111+
reordered_result[target_dimension] = np.arange(result_len)
86112

87113
if data.rio.crs is not None:
88114
try:
89115
reordered_result.rio.write_crs(data.rio.crs, inplace=True)
90116
except ValueError:
91117
pass
92118

93-
if is_new_dim_added:
94-
reordered_result.openeo.add_dim_type(name=target_dimension, type="other")
95-
96119
return reordered_result
97120

98121

tests/test_apply.py

+1-56
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def test_apply(temporal_interval, bounding_box, random_raster_data, process_regi
4747

4848
@pytest.mark.parametrize("size", [(6, 5, 4, 4)])
4949
@pytest.mark.parametrize("dtype", [np.float32])
50-
def test_apply_dimension_case_1(
50+
def test_apply_dimension_add(
5151
temporal_interval, bounding_box, random_raster_data, process_registry
5252
):
5353
input_cube = create_fake_rastercube(
@@ -78,61 +78,6 @@ def test_apply_dimension_case_1(
7878
)
7979

8080

81-
@pytest.mark.parametrize("size", [(6, 5, 4, 4)])
82-
@pytest.mark.parametrize("dtype", [np.float32])
83-
def test_apply_dimension_target_dimension(
84-
temporal_interval, bounding_box, random_raster_data, process_registry
85-
):
86-
input_cube = create_fake_rastercube(
87-
data=random_raster_data,
88-
spatial_extent=bounding_box,
89-
temporal_extent=temporal_interval,
90-
bands=["B02", "B03", "B04", "B08"],
91-
backend="dask",
92-
)
93-
94-
_process = partial(
95-
process_registry["mean"].implementation,
96-
data=ParameterReference(from_parameter="data"),
97-
)
98-
99-
# Target dimension is null and therefore defaults to the source dimension
100-
output_cube_reduced = apply_dimension(
101-
data=input_cube, process=_process, dimension="x", target_dimension="target"
102-
)
103-
104-
expected_output = (input_cube.mean(dim="x")).expand_dims("target")
105-
106-
general_output_checks(
107-
input_cube=input_cube,
108-
output_cube=output_cube_reduced,
109-
verify_attrs=True,
110-
verify_crs=False,
111-
expected_results=expected_output,
112-
)
113-
114-
# Target dimension is null and therefore defaults to the source dimension
115-
output_cube_reduced = apply_dimension(
116-
data=input_cube, process=_process, dimension="x", target_dimension="y"
117-
)
118-
expected_output = (
119-
input_cube.mean(dim="x")
120-
.expand_dims("target")
121-
.drop_vars("y")
122-
.rename({"target": "y"})
123-
)
124-
125-
general_output_checks(
126-
input_cube=input_cube,
127-
output_cube=output_cube_reduced,
128-
verify_attrs=True,
129-
verify_crs=False,
130-
expected_results=expected_output,
131-
)
132-
133-
assert "y" in output_cube_reduced.openeo.other_dims
134-
135-
13681
@pytest.mark.parametrize("size", [(6, 5, 4, 4)])
13782
@pytest.mark.parametrize("dtype", [np.float32])
13883
def test_apply_dimension_ordering_processes(

0 commit comments

Comments
 (0)