Repository: DHI/mikeio
Pull request #394 (2022-07-28 05:14:49)

Fix dfsu read single element in area argument
If the area covered only a single element a "strange" error message was given. This PR also provides a better error message if no elements are inside the area. Closing #376. 


Patch:
diff --git a/mikeio/dfsu.py b/mikeio/dfsu.py
index d9c5de55..0e5839eb 100644
--- a/mikeio/dfsu.py
+++ b/mikeio/dfsu.py
@@ -858,7 +858,7 @@ class _Dfsu(_UnstructuredFile, EquidistantTimeSeries):
         if elements is not None and len(elements) == 1:
             # squeeze point data
             dims = tuple([d for d in dims if d != "element"])
-            data_list = [np.squeeze(d) for d in data_list]
+            data_list = [np.squeeze(d, axis=-1) for d in data_list]
 
         return Dataset(
             data_list, time, items, geometry=geometry, dims=dims, validate=False
@@ -886,6 +886,11 @@ class _Dfsu(_UnstructuredFile, EquidistantTimeSeries):
         if (x is not None) or (y is not None):
             elements = self.geometry.find_index(x=x, y=y)
 
+        if (x is not None) or (y is not None) or (area is not None):
+            # selection was attempted
+            if (elements is None) or len(elements) == 0:
+                raise ValueError("No elements in selection!")
+
         return elements
 
     def write_header(
diff --git a/mikeio/dfsu_layered.py b/mikeio/dfsu_layered.py
index 00ee5c01..fd784c27 100644
--- a/mikeio/dfsu_layered.py
+++ b/mikeio/dfsu_layered.py
@@ -260,7 +260,7 @@ class DfsuLayered(_Dfsu):
         if elements is not None and len(elements) == 1:
             # squeeze point data
             dims = tuple([d for d in dims if d != "element"])
-            data_list = [np.squeeze(d) for d in data_list]
+            data_list = [np.squeeze(d, axis=-1) for d in data_list]
 
         if hasattr(geometry, "is_layered") and geometry.is_layered:
             return Dataset(
@@ -294,6 +294,16 @@ class DfsuLayered(_Dfsu):
                 elements_xy if layers is None else np.intersect1d(elements, elements_xy)
             )
 
+        if (
+            (x is not None)
+            or (y is not None)
+            or (layers is not None)
+            or (area is not None)
+        ):
+            # selection was attempted
+            if (elements is None) or len(elements) == 0:
+                raise ValueError("No elements in selection!")
+
         return elements
 
 


Test patch:
diff --git a/tests/test_dfsu.py b/tests/test_dfsu.py
index 46bce115..179ee4f8 100644
--- a/tests/test_dfsu.py
+++ b/tests/test_dfsu.py
@@ -11,6 +11,7 @@ from mikeio.eum import ItemInfo
 from pytest import approx
 
 from mikeio.spatial.FM_geometry import GeometryFM
+from mikeio.spatial.geometry import GeometryPoint2D
 from mikeio.spatial.grid_geometry import Grid2D
 
 
@@ -212,6 +213,39 @@ def test_read_single_time_step_outside_bounds_fails():
         dfs.read(items=[0, 3], time=[100])
 
 
+def test_read_area():
+
+    filename = "tests/testdata/FakeLake.dfsu"
+    dfs = mikeio.open(filename)
+
+    ds = dfs.read(area=[0, 0, 0.1, 0.1])
+    assert isinstance(ds.geometry, GeometryFM)
+    assert ds.geometry.n_elements == 18
+
+
+def test_read_area_single_element():
+
+    filename = "tests/testdata/FakeLake.dfsu"
+    dfs = mikeio.open(filename)
+
+    ds = dfs.read(area=[0, 0, 0.02, 0.02])
+    assert isinstance(ds.geometry, GeometryPoint2D)
+    assert ds.dims == ("time",)
+
+    ds = dfs.read(area=[0, 0, 0.02, 0.02], time=0)
+    assert isinstance(ds.geometry, GeometryPoint2D)
+    assert len(ds.dims) == 0
+
+
+def test_read_empty_area_fails():
+
+    filename = "tests/testdata/FakeLake.dfsu"
+    dfs = mikeio.open(filename)
+
+    with pytest.raises(ValueError, match="No elements in selection"):
+        dfs.read(area=[0, 0, 0.001, 0.001])
+
+
 def test_number_of_time_steps():
     filename = "tests/testdata/HD2D.dfsu"
     dfs = mikeio.open(filename)
diff --git a/tests/test_dfsu_layered.py b/tests/test_dfsu_layered.py
index 28b51571..4fc198e4 100644
--- a/tests/test_dfsu_layered.py
+++ b/tests/test_dfsu_layered.py
@@ -122,6 +122,33 @@ def test_read_dfsu3d_area():
     assert np.all(dsa1.to_numpy() == dsa2.to_numpy())
 
 
+def test_read_dfsu3d_area_single_element():
+    filename = "tests/testdata/oresund_sigma_z.dfsu"
+    dfs = mikeio.open(filename)
+
+    bbox = [356000, 6144000, 357000, 6144500]
+    ds = dfs.read(area=bbox)
+    assert ds.geometry.geometry2d.n_elements == 1
+    assert ds.geometry.n_elements == 4
+
+    ds = dfs.read(area=bbox, layers="top")
+    assert isinstance(ds.geometry, GeometryPoint3D)
+    assert ds.dims == ("time",)
+
+    ds = dfs.read(area=bbox, layers="top", time=0)
+    assert isinstance(ds.geometry, GeometryPoint3D)
+    assert len(ds.dims) == 0
+
+
+def test_read_dfsu3d_area_empty_fails():
+    filename = "tests/testdata/oresund_sigma_z.dfsu"
+    dfs = mikeio.open(filename)
+
+    bbox = [350000, 6192000, 350001, 6192001]
+    with pytest.raises(ValueError, match="No elements in selection"):
+        dfs.read(area=bbox)
+
+
 def test_read_dfsu3d_column():
     filename = "tests/testdata/oresund_sigma_z.dfsu"
     dfs = mikeio.open(filename)