Skip to content

Commit

Permalink
Merge pull request #259 from Deltares/numpy2
Browse files Browse the repository at this point in the history
Numpy 2.0 support
  • Loading branch information
Huite authored Jul 12, 2024
2 parents 799adc3 + f3e23de commit 4b0e61a
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 108 deletions.
229 changes: 121 additions & 108 deletions tests/test_regrid/test_structured.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ def test_init_2d(grid_data_a_2d):
StructuredGrid2d(1)


def assert_expected_overlap(
actual_source,
actual_target,
actual_weights,
expected_source,
expected_target,
expected_weights,
):
# Numpy 2.0 release has change sorting behavior of non-stable sorting:
# https://numpy.org/doc/stable/release/2.0.0-notes.html#minor-changes-in-behavior-of-sorting-functions
# So the comparison method must be robust to work for numpy <2.0 and >=2.0.
actual_mapping = np.column_stack((actual_target, actual_source))
expected_mapping = np.column_stack((expected_target, expected_source))
actual, actual_sorter = np.unique(actual_mapping, axis=0, return_index=True)
expected, expected_sorter = np.unique(expected_mapping, axis=0, return_index=True)
assert np.array_equal(actual, expected)
assert np.allclose(actual_weights[actual_sorter], expected_weights[expected_sorter])


def test_overlap_1d(
grid_data_a_1d, grid_data_b_1d, grid_data_b_flipped_1d, grid_data_e_1d
):
Expand All @@ -37,11 +56,12 @@ def test_overlap_1d(
# node 1 1, 2 25 m
# node 2 2, 3 25 m
# --------
source, target, weights = grid_data_a_1d.overlap(grid_data_b_1d, relative=False)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 0, 1, 1, 2, 2]))
assert np.array_equal(target[sorter], np.array([0, 1, 1, 2, 2, 3]))
assert np.array_equal(weights[sorter], np.array([25, 25, 25, 25, 25, 25]))
assert_expected_overlap(
*grid_data_a_1d.overlap(grid_data_b_1d, relative=False),
np.array([0, 0, 1, 1, 2, 2]),
np.array([0, 1, 1, 2, 2, 3]),
np.array([25, 25, 25, 25, 25, 25]),
)

# flipped axis (y-axis)
# --------
Expand All @@ -50,38 +70,37 @@ def test_overlap_1d(
# 1 1, 2 25 m
# 2 2, 3 25 m
# --------
source, target, weights = grid_data_a_1d.overlap(
grid_data_b_flipped_1d, relative=False
assert_expected_overlap(
*grid_data_a_1d.overlap(grid_data_b_flipped_1d, relative=False),
np.array([0, 0, 1, 1, 2, 2]),
np.array([2, 3, 1, 2, 0, 1]),
np.array([25, 25, 25, 25, 25, 25]),
)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 0, 1, 1, 2, 2]))
assert np.array_equal(target[sorter], np.array([2, 3, 1, 2, 0, 1]))
assert np.array_equal(weights[sorter], np.array([25, 25, 25, 25, 25, 25]))

# non-equidistant
# --------
# source targets weight
# node 0 0, 1 17.5 m, 32.5 m
# node 1 1, 2 17.5 m, 25.0 m
# --------
source, target, weights = grid_data_a_1d.overlap(grid_data_e_1d, relative=False)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 0, 1, 1]))
assert np.array_equal(target[sorter], np.array([0, 1, 1, 2]))
assert np.array_equal(weights[sorter], np.array([17.5, 32.5, 17.5, 25.0]))
assert_expected_overlap(
*grid_data_a_1d.overlap(grid_data_e_1d, relative=False),
np.array([0, 0, 1, 1]),
np.array([0, 1, 1, 2]),
np.array([17.5, 32.5, 17.5, 25.0]),
)

# relative
# --------
# source targets weight
# node 0 0, 1 17.5 m, 32.5 m
# node 1 1, 2 17.5 m, 25.0 m
# --------
source, target, weights = grid_data_a_1d.overlap(grid_data_e_1d, relative=True)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 0, 1, 1]))
assert np.array_equal(target[sorter], np.array([0, 1, 1, 2]))
assert np.array_equal(
weights[sorter], np.array([17.5 / 50.0, 32.5 / 50.0, 17.5 / 50.0, 25.0 / 50.0])
assert_expected_overlap(
*grid_data_a_1d.overlap(grid_data_e_1d, relative=True),
np.array([0, 0, 1, 1]),
np.array([0, 1, 1, 2]),
np.array([17.5 / 50.0, 32.5 / 50.0, 17.5 / 50.0, 25.0 / 50.0]),
)


Expand All @@ -98,11 +117,9 @@ def test_overlap_2d(grid_data_a_2d, grid_data_b_2d):
# 7 9, 10, 13, 14 625 m
# 8 10, 11, 14, 15 625 m
# --------
source, target, weights = grid_data_a_2d.overlap(grid_data_b_2d, relative=False)
sorter = np.argsort(source)
assert np.array_equal(
source[sorter],
np.array(
assert_expected_overlap(
*grid_data_a_2d.overlap(grid_data_b_2d, relative=False),
expected_source=np.array(
[
0,
0,
Expand Down Expand Up @@ -142,10 +159,7 @@ def test_overlap_2d(grid_data_a_2d, grid_data_b_2d):
8,
]
),
)
assert np.array_equal(
target[sorter],
np.array(
expected_target=np.array(
[
0,
4,
Expand Down Expand Up @@ -185,8 +199,8 @@ def test_overlap_2d(grid_data_a_2d, grid_data_b_2d):
15,
]
),
expected_weights=np.full(36, 625.0),
)
assert np.array_equal(weights[sorter], np.array([625] * source.size))


def test_locate_centroids_1d(
Expand All @@ -197,35 +211,38 @@ def test_locate_centroids_1d(
# 0 1 1
# 1 2 1
# --------
source, target, weights = grid_data_a_1d.locate_centroids(grid_data_b_1d)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 1]))
assert np.array_equal(target[sorter], np.array([1, 2]))
assert np.allclose(weights[sorter], np.ones(2))
assert_expected_overlap(
*grid_data_a_1d.locate_centroids(grid_data_b_1d),
np.array([0, 1]),
np.array([1, 2]),
np.ones(2),
)

# flipped axis (y-axis)
# --------
# source target weight
# 0 1 1
# 1 2 1
# --------
source, target, weights = grid_data_a_1d.locate_centroids(grid_data_b_flipped_1d)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 1]))
assert np.array_equal(target[sorter], np.array([2, 1]))
assert np.allclose(weights[sorter], np.ones(2))
assert_expected_overlap(
*grid_data_a_1d.locate_centroids(grid_data_b_flipped_1d),
np.array([0, 1]),
np.array([2, 1]),
np.ones(2),
)

# non-equidistant
# --------
# source target weight
# 0 0, 1 1, 1
# 1 2 1
# --------
source, target, weights = grid_data_a_1d.locate_centroids(grid_data_e_1d)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 0, 1]))
assert np.array_equal(target[sorter], np.array([0, 1, 2]))
assert np.allclose(weights[sorter], np.ones(3))
assert_expected_overlap(
*grid_data_a_1d.locate_centroids(grid_data_e_1d),
np.array([0, 0, 1]),
np.array([0, 1, 2]),
np.ones(3),
)


def test_locate_centroids_2d(grid_data_a_2d, grid_data_b_2d):
Expand All @@ -236,11 +253,12 @@ def test_locate_centroids_2d(grid_data_a_2d, grid_data_b_2d):
# 3 9 1
# 4 10 1
# --------
source, target, weights = grid_data_a_2d.locate_centroids(grid_data_b_2d)
sorter = np.argsort(source)
assert np.array_equal(source[sorter], np.array([0, 1, 3, 4]))
assert np.array_equal(target[sorter], np.array([5, 6, 9, 10]))
assert np.allclose(weights[sorter], np.ones(4))
assert_expected_overlap(
*grid_data_a_2d.locate_centroids(grid_data_b_2d),
np.array([0, 1, 3, 4]),
np.array([5, 6, 9, 10]),
np.ones(4),
)


def test_linear_weights_1d(
Expand All @@ -258,11 +276,12 @@ def test_linear_weights_1d(
# 1 -> 2 50%
# 2 -> 2 50%
# --------
source, target, weights = grid_data_a_1d.linear_weights(grid_data_b_1d)
sorter = np.argsort(target)
assert np.array_equal(source[sorter], np.array([0, 1, 1, 2]))
assert np.array_equal(target[sorter], np.array([1, 1, 2, 2]))
assert np.allclose(weights[sorter], np.array([0.5, 0.5, 0.5, 0.5]))
assert_expected_overlap(
*grid_data_a_1d.linear_weights(grid_data_b_1d),
np.array([0, 1, 1, 2]),
np.array([1, 1, 2, 2]),
np.array([0.5, 0.5, 0.5, 0.5]),
)

# flipped axis (y-axis)
# --------
Expand All @@ -272,11 +291,12 @@ def test_linear_weights_1d(
# 1 -> 1 50%
# 2 -> 1 50%
# --------
source, target, weights = grid_data_a_1d.linear_weights(grid_data_b_flipped_1d)
sorter = np.argsort(target)
assert np.array_equal(source[sorter], np.array([1, 2, 0, 1]))
assert np.array_equal(target[sorter], np.array([1, 1, 2, 2]))
assert np.allclose(weights[sorter], np.array([0.5, 0.5, 0.5, 0.5]))
assert_expected_overlap(
*grid_data_a_1d.linear_weights(grid_data_b_flipped_1d),
np.array([2, 1, 1, 0]),
np.array([1, 1, 2, 2]),
np.array([0.5, 0.5, 0.5, 0.5]),
)

# --------
# source target weight
Expand All @@ -285,11 +305,12 @@ def test_linear_weights_1d(
# 2 2 80%
# 1 2 20%
# --------
source, target, weights = grid_data_a_1d.linear_weights(grid_data_c_1d)
sorter = np.argsort(target)
assert np.array_equal(source[sorter], np.array([1, 0, 2, 1]))
assert np.array_equal(target[sorter], np.array([1, 1, 2, 2]))
assert np.allclose(weights[sorter], np.array([0.8, 0.2, 0.8, 0.2]))
assert_expected_overlap(
*grid_data_a_1d.linear_weights(grid_data_c_1d),
np.array([1, 0, 2, 1]),
np.array([1, 1, 2, 2]),
np.array([0.8, 0.2, 0.8, 0.2]),
)

# --------
# source target weight
Expand All @@ -300,11 +321,12 @@ def test_linear_weights_1d(
# 1 3 90%
# 2 3 10%
# --------
source, target, weights = grid_data_a_1d.linear_weights(grid_data_d_1d)
sorter = np.argsort(target)
assert np.array_equal(source[sorter], np.array([0, 1, 1, 0, 1, 2]))
assert np.array_equal(target[sorter], np.array([1, 1, 2, 2, 3, 3]))
assert np.allclose(weights[sorter], np.array([0.9, 0.1, 0.6, 0.4, 0.9, 0.1]))
assert_expected_overlap(
*grid_data_a_1d.linear_weights(grid_data_d_1d),
np.array([0, 1, 1, 0, 1, 2]),
np.array([1, 1, 2, 2, 3, 3]),
np.array([0.9, 0.1, 0.6, 0.4, 0.9, 0.1]),
)

# non-equidistant
# --------
Expand All @@ -314,11 +336,12 @@ def test_linear_weights_1d(
# 1 2 90%
# 2 2 10%
# --------
source, target, weights = grid_data_a_1d.linear_weights(grid_data_e_1d)
sorter = np.argsort(target)
assert np.array_equal(source[sorter], np.array([0, 1, 1, 2]))
assert np.array_equal(target[sorter], np.array([1, 1, 2, 2]))
assert np.allclose(weights[sorter], np.array([0.65, 0.35, 0.9, 0.1]))
assert_expected_overlap(
*grid_data_a_1d.linear_weights(grid_data_e_1d),
np.array([0, 1, 1, 2]),
np.array([1, 1, 2, 2]),
np.array([0.65, 0.35, 0.9, 0.1]),
)

# 1-1 grid
# --------
Expand All @@ -328,11 +351,12 @@ def test_linear_weights_1d(
# 2 2 100%
# 1 2 0%
# --------
source, target, weights = grid_data_b_1d.linear_weights(grid_data_b_1d)
sorter = np.argsort(target)
assert np.array_equal(source[sorter], np.array([1, 0, 2, 1]))
assert np.array_equal(target[sorter], np.array([1, 1, 2, 2]))
assert np.allclose(weights[sorter], np.array([1.0, 0.0, 1.0, 0.0]))
assert_expected_overlap(
*grid_data_b_1d.linear_weights(grid_data_b_1d),
np.array([1, 0, 2, 1]),
np.array([1, 1, 2, 2]),
np.array([1.0, 0.0, 1.0, 0.0]),
)


def test_linear_weights_2d(
Expand All @@ -345,15 +369,12 @@ def test_linear_weights_2d(
# 9 3, 4, 6, 7 25%
# 10 4, 5, 7, 8 25%
# --------
source, target, weights = grid_data_a_2d.linear_weights(grid_data_b_2d)
sorter = np.argsort(target)
assert np.array_equal(
source[sorter], np.array([0, 1, 3, 4, 1, 2, 4, 5, 3, 4, 6, 7, 4, 5, 7, 8])
)
assert np.array_equal(
target[sorter], np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10])
assert_expected_overlap(
*grid_data_a_2d.linear_weights(grid_data_b_2d),
np.array([3, 4, 1, 0, 5, 4, 1, 2, 6, 7, 4, 3, 8, 7, 4, 5]),
np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10]),
np.array([0.25] * 16),
)
assert np.allclose(weights[sorter], np.array([0.25] * 16))

# --------
# source targets weight
Expand All @@ -362,15 +383,12 @@ def test_linear_weights_2d(
# 9 3, 4, 6, 7 10% 40% 10% 40%
# 10 4, 5, 7, 8 10% 40% 10% 40%
# --------
source, target, weights = grid_data_a_layered_2d.linear_weights(grid_data_c_2d)
sorter = np.argsort(target)
assert np.array_equal(
source[sorter], np.array([1, 0, 4, 3, 2, 1, 5, 4, 4, 3, 7, 6, 5, 4, 8, 7])
)
assert np.array_equal(
target[sorter], np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10])
assert_expected_overlap(
*grid_data_a_layered_2d.linear_weights(grid_data_c_2d),
np.array([1, 0, 4, 3, 2, 1, 5, 4, 4, 3, 7, 6, 5, 4, 8, 7]),
np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10]),
np.array([0.4, 0.1, 0.4, 0.1] * 4),
)
assert np.allclose(weights[sorter], np.array([0.4, 0.1, 0.4, 0.1] * 4))

# 1-1
# --------
Expand All @@ -380,14 +398,9 @@ def test_linear_weights_2d(
# 9 8, 9,12,13 0% 100% 0% 0%
# 10 9,10,13,14 0% 100% 0% 0%
# --------
source, target, weights = grid_data_b_2d.linear_weights(grid_data_b_2d)
sorter = np.argsort(target)
assert np.array_equal(
source[sorter], np.array([5, 4, 9, 8, 6, 5, 10, 9, 9, 8, 13, 12, 10, 9, 14, 13])
)
assert np.array_equal(
target[sorter], np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10])
)
assert np.allclose(
weights[sorter], np.array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
assert_expected_overlap(
*grid_data_b_2d.linear_weights(grid_data_b_2d),
np.array([5, 4, 9, 8, 6, 5, 10, 9, 9, 8, 13, 12, 10, 9, 14, 13]),
np.array([5, 5, 5, 5, 6, 6, 6, 6, 9, 9, 9, 9, 10, 10, 10, 10]),
np.array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]),
)
2 changes: 2 additions & 0 deletions xugrid/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def linestrings_to_edges(edges: LineArray) -> Tuple[FloatArray, FloatArray, IntA
segments = np.column_stack([linear_index[:-1], linear_index[1:]])
segments = segments[np.diff(index) == 0]
unique, inverse = np.unique(xy, return_inverse=True, axis=0)
inverse = inverse.ravel()
segments = inverse[segments]
x, y = contiguous_xy(unique)
return x, y, segments
Expand All @@ -93,6 +94,7 @@ def polygons_to_faces(
*shapely.get_coordinates(polygons, return_index=True)
)
unique, inverse = np.unique(xy, axis=0, return_inverse=True)
inverse = inverse.ravel()
n = len(polygons)
m_per_row = np.bincount(indices)
m = m_per_row.max()
Expand Down
Loading

0 comments on commit 4b0e61a

Please sign in to comment.