Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog/7253.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:user:`stephenworsley` fixed a bug which caused indexing to fail when
``start_index`` was 1. (:issue:`7246`)
2 changes: 2 additions & 0 deletions lib/iris/mesh/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -3132,6 +3132,7 @@ def indexed(
# used by MeshCoord, which also maintains laziness.
indices = connectivity.lazy_indices()
indices_indexed = connectivity.indices_by_location(indices)[indexing]
indices_indexed -= connectivity.start_index

# Map node indices in "values" to their new zero-based positions
# via the inverse-lookup table. This creates a contiguous
Expand Down Expand Up @@ -3524,6 +3525,7 @@ def _calculate_node_bool_index(self):
conn_indices = connectivity.indices_by_location(
connectivity.core_indices()
)[self.indices]
conn_indices -= connectivity.start_index
al = da if _lazy.is_lazy_data(conn_indices) else np
# Flatten and drop masked padding (ragged connectivities) by scattering
# membership into a fixed-shape boolean mask.
Expand Down
43 changes: 43 additions & 0 deletions lib/iris/tests/integration/mesh/test_indexing_meshes.py
Comment thread
trexfeathers marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# This file is part of Iris and is released under the BSD license.
# See LICENSE in the root of the repository for full licensing details.

import numpy as np
import pytest

from iris.coords import AuxCoord, Coord
Expand Down Expand Up @@ -47,6 +48,17 @@ def cube_mesh_face():
return (sample_mesh_cube(location=location, mesh=mesh), location)


@pytest.fixture
def cube_mesh_1_indexed(cube_mesh_from_file):
cube = cube_mesh_from_file[0]
mesh = cube.mesh
for con in mesh.all_connectivities:
if con is not None:
con.indices[:] += 1
con._metadata_manager.start_index = 1
return (cube, "face")


def change_and_assert_no_change_in_right(left: Coord, right: Coord, value: int):
left.points[0] = value
assert right.points[0] != value
Expand Down Expand Up @@ -187,3 +199,34 @@ def change_original_mesh_reflected_in_index_set(
change_original_mesh_reflected_in_index_set(
cube, indexed_cube, "longitude", location, value
)


@pytest.mark.parametrize(
"fixture",
["cube_mesh_from_file", "cube_mesh_edge", "cube_mesh_face", "cube_mesh_1_indexed"],
)
def test_indexing_mode_equivalency(fixture, request):
Comment thread
trexfeathers marked this conversation as resolved.
cube: Cube
location: str
(cube, location) = request.getfixturevalue(fixture)

with mesh_coord_indexing.SETTING.context(mesh_coord_indexing.Options.AUX_COORD):
indexed_cube_aux = cube[0, 1:-1]
with mesh_coord_indexing.SETTING.context(mesh_coord_indexing.Options.NEW_MESH):
indexed_cube_mesh = cube[0, 1:-1]
with mesh_coord_indexing.SETTING.context(
mesh_coord_indexing.Options.MESH_INDEX_SET
):
indexed_cube_mis = cube[0, 1:-1]

aux_lon = indexed_cube_aux.coord("longitude")
aux_lat = indexed_cube_aux.coord("latitude")
mesh_lon = indexed_cube_mesh.coord("longitude")
mesh_lat = indexed_cube_mesh.coord("latitude")
mis_lon = indexed_cube_mis.coord("longitude")
mis_lat = indexed_cube_mis.coord("latitude")

assert np.array_equal(aux_lon.bounds, mesh_lon.bounds)
assert np.array_equal(aux_lat.bounds, mesh_lat.bounds)
assert np.array_equal(aux_lon.bounds, mis_lon.bounds)
assert np.array_equal(aux_lat.bounds, mis_lat.bounds)
31 changes: 26 additions & 5 deletions lib/iris/tests/unit/mesh/components/test_MeshIndexSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,12 +513,27 @@ def varied_mesh(self, lazy_values):
)
return mesh

def test_varied_faces(self, varied_mesh):
@pytest.fixture
def varied_mesh_1_indexed(self, varied_mesh):
mesh = varied_mesh
for con in mesh.all_connectivities:
if con is not None:
con.indices[:] += 1
con._metadata_manager.start_index = 1
return mesh

@pytest.mark.parametrize(
"fixture",
["varied_mesh", "varied_mesh_1_indexed"],
)
def test_varied_faces(self, fixture, request):
mesh: MeshXY = request.getfixturevalue(fixture)
index_set = _MeshIndexSet(indices=[0, 1, 3], mesh=mesh, location="face")
_shared_utils.assert_array_equal(index_set.indices, np.array([0, 1, 3]))
connectivity = index_set.connectivity(cf_role="face_node_connectivity")
normalised_indices = connectivity.indices - connectivity.start_index
_shared_utils.assert_array_equal(
index_set.connectivity(cf_role="face_node_connectivity").indices,
normalised_indices,
np.ma.masked_array(
data=[[7, 8, 10, 9, -1], [3, 7, 6, -1, -1], [0, 1, 2, 5, 4]],
mask=[[0, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 0, 0, 0, 0]],
Expand All @@ -532,12 +547,18 @@ def test_varied_faces(self, varied_mesh):
np.array([-2, -3, -4, -1, -3, -4, -1, -2, -3, -2, -3]),
)

def test_varied_edges(self, varied_mesh):
mesh = varied_mesh
@pytest.mark.parametrize(
"fixture",
["varied_mesh", "varied_mesh_1_indexed"],
)
def test_varied_edges(self, fixture, request):
mesh: MeshXY = request.getfixturevalue(fixture)
index_set = _MeshIndexSet(indices=[0, 1, 4], mesh=mesh, location="edge")
_shared_utils.assert_array_equal(index_set.indices, np.array([0, 1, 4]))
connectivity = index_set.connectivity(cf_role="edge_node_connectivity")
normalised_indices = connectivity.indices - connectivity.start_index
_shared_utils.assert_array_equal(
index_set.connectivity(cf_role="edge_node_connectivity").indices,
normalised_indices,
# Note the shared node.
np.array([[0, 1], [1, 2], [3, 4]]),
)
Expand Down
Loading