Skip to content

Commit 54e2f75

Browse files
committed
Finish adding test for handling of different units
1 parent bca6e3a commit 54e2f75

File tree

1 file changed

+102
-61
lines changed

1 file changed

+102
-61
lines changed

climada/util/test/test_coordinates.py

Lines changed: 102 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def def_ref_50():
237237

238238

239239
class TestInferUnitCoords(unittest.TestCase):
240-
def create_mock_gdf(crs, num_points=5):
240+
def create_mock_gdf(self, crs, num_points=5):
241241
geometry = [
242242
shapely.Point(x, y) for x, y in zip(range(num_points), range(num_points))
243243
]
@@ -269,7 +269,7 @@ def test_infer_unit_unsupported_crs(self):
269269
"""Test with a mocked unsupported CRS."""
270270

271271
class MockCRS:
272-
is_geodetic = False
272+
is_geographic = False
273273
is_projected = False
274274

275275
class MockGDF:
@@ -1334,38 +1334,46 @@ def setUp_match_coordinates(self):
13341334
self.coords_to_assign = np.array(
13351335
[(2.1, 3), (0, 0), (0, 2), (0.9, 1.0), (0, -179.9)]
13361336
)
1337-
self.expected_results = [
1338-
# test with different thresholds (in km)
1339-
(100, [2, 1, 2, 0, 3, -1, 4]),
1340-
(20, [-1, 1, 2, 0, 3, -1, -1]),
1341-
(0, [-1, 1, 2, 0, -1, -1, -1]),
1342-
]
1337+
# test with different unit
1338+
self.expected_results = {
1339+
"degree": [
1340+
# test with different thresholds (in km)
1341+
(100, [2, 1, 2, 0, 3, -1, 4]),
1342+
(20, [-1, 1, 2, 0, 3, -1, -1]),
1343+
(0, [-1, 1, 2, 0, -1, -1, -1]),
1344+
],
1345+
"m": [
1346+
# test with different thresholds (in km)
1347+
(100, [2, 1, 2, 0, 3, -1, -1]),
1348+
(20, [-1, 1, 2, 0, 3, -1, -1]),
1349+
(0, [-1, 1, 2, 0, -1, -1, -1]),
1350+
],
1351+
"km": [
1352+
# test with different thresholds (in km)
1353+
(100, [2, 1, 2, 0, 3, -1, -1]),
1354+
(20, [-1, 1, 2, 0, 3, -1, -1]),
1355+
(0, [-1, 1, 2, 0, -1, -1, -1]),
1356+
],
1357+
}
13431358

13441359
def test_match_coordinates(self):
13451360
"""Test match_coordinates function"""
13461361
self.setUp_match_coordinates()
1347-
unit_conv_funcs = {
1348-
"degree": lambda x: x,
1349-
"km": lambda x: np.deg2rad(x) * EARTH_RADIUS_KM,
1350-
"m": lambda x: np.deg2rad(x) * EARTH_RADIUS_KM * 1e3,
1351-
}
1362+
unit = "degree" # first only check for degrees
13521363
for distance in ["euclidean", "haversine", "approx"]:
1353-
for unit in ["degree", "km", "m"]:
1354-
# make sure that it works for both float32 and float64
1355-
for test_dtype in [np.float64, np.float32]:
1356-
coords_typed = unit_conv_funcs[unit](self.coords.astype(test_dtype))
1357-
coords_to_assign_typed = unit_conv_funcs[unit](
1358-
self.coords_to_assign.astype(test_dtype)
1364+
# make sure that it works for both float32 and float64
1365+
for test_dtype in [np.float64, np.float32]:
1366+
coords_typed = self.coords.astype(test_dtype)
1367+
coords_to_assign_typed = self.coords_to_assign.astype(test_dtype)
1368+
for thresh, result in self.expected_results[unit]:
1369+
assigned_idx = u_coord.match_coordinates(
1370+
coords_typed,
1371+
coords_to_assign_typed,
1372+
distance=distance,
1373+
unit=unit,
1374+
threshold=thresh,
13591375
)
1360-
for thresh, result in self.expected_results:
1361-
assigned_idx = u_coord.match_coordinates(
1362-
coords_typed,
1363-
coords_to_assign_typed,
1364-
distance=distance,
1365-
unit=unit,
1366-
threshold=thresh,
1367-
)
1368-
np.testing.assert_array_equal(assigned_idx, result)
1376+
np.testing.assert_array_equal(assigned_idx, result)
13691377

13701378
# test empty coords_to_assign
13711379
coords_to_assign_empty = np.array([])
@@ -1383,16 +1391,67 @@ def test_match_coordinates(self):
13831391
)
13841392
np.testing.assert_array_equal(assigned_idx, result)
13851393

1386-
def test_nearest_neighbor_approx_valid_unit(self):
1387-
# Test with valid unit ('deg')
1394+
def test_match_coordinates_different_unit(self):
1395+
"""Test match_coordinates function"""
1396+
self.setUp_match_coordinates()
1397+
unit_conv_funcs = {
1398+
"degree": lambda x: x,
1399+
"km": lambda x: np.deg2rad(x) * EARTH_RADIUS_KM,
1400+
"m": lambda x: np.deg2rad(x) * EARTH_RADIUS_KM * 1e3,
1401+
}
1402+
distance = "euclidean"
1403+
for unit in ["degree", "km", "m"]:
1404+
results = self.expected_results[unit]
1405+
# do not check antimeridian if units are not in degree
1406+
check_antimeridian = False if unit != "degree" else True
1407+
# make sure that it works for both float32 and float64
1408+
for test_dtype in [np.float64, np.float32]:
1409+
coords_typed = unit_conv_funcs[unit](self.coords.astype(test_dtype))
1410+
coords_to_assign_typed = unit_conv_funcs[unit](
1411+
self.coords_to_assign.astype(test_dtype)
1412+
)
1413+
for thresh, result in results:
1414+
assigned_idx = u_coord.match_coordinates(
1415+
coords_typed,
1416+
coords_to_assign_typed,
1417+
distance=distance,
1418+
unit=unit,
1419+
threshold=thresh,
1420+
check_antimeridian=check_antimeridian,
1421+
)
1422+
np.testing.assert_array_equal(assigned_idx, result)
1423+
# test empty coords_to_assign
1424+
coords_to_assign_empty = np.array([])
1425+
result = [-1, -1, -1, -1, -1, -1, -1]
1426+
assigned_idx = u_coord.match_coordinates(
1427+
self.coords,
1428+
coords_to_assign_empty,
1429+
distance=distance,
1430+
unit=unit,
1431+
threshold=thresh,
1432+
)
1433+
np.testing.assert_array_equal(assigned_idx, result)
1434+
# test empty coords
1435+
coords_empty = np.array([])
1436+
result = np.array([])
1437+
assigned_idx = u_coord.match_coordinates(
1438+
coords_empty,
1439+
self.coords_to_assign,
1440+
distance=distance,
1441+
unit=unit,
1442+
threshold=thresh,
1443+
)
1444+
np.testing.assert_array_equal(assigned_idx, result)
1445+
1446+
def test_nearest_neighbor_euclidean_invalid_unit(self):
1447+
# Test with invalid unit ('foo')
13881448
self.setUp_match_coordinates()
13891449
coords_to_assign = np.deg2rad(self.coords_to_assign)
13901450
coords = np.deg2rad(self.coords)
1391-
result = u_coord._nearest_neighbor_approx(
1392-
coords_to_assign, coords, "degree", u_coord.NEAREST_NEIGHBOR_THRESHOLD
1393-
)
1394-
self.assertEqual(len(result), len(self.coords))
1395-
self.assertTrue(np.all(result >= -1)) # Valid indices or -1
1451+
with self.assertRaises(ValueError):
1452+
u_coord._nearest_neighbor_euclidean(
1453+
coords_to_assign, coords, "foo", u_coord.NEAREST_NEIGHBOR_THRESHOLD
1454+
)
13961455

13971456
def test_nearest_neighbor_approx_invalid_unit(self):
13981457
# Test with invalid unit
@@ -1404,18 +1463,15 @@ def test_nearest_neighbor_approx_invalid_unit(self):
14041463
coords_to_assign, coords, "km", u_coord.NEAREST_NEIGHBOR_THRESHOLD
14051464
)
14061465

1407-
def test_nearest_neighbor_euclidean_valid_unit_no_antimeridian(self):
1408-
# Test with valid unit ('deg') and check_antimeridian=False
1466+
def test_nearest_neighbor_haversine_invalid_unit(self):
1467+
# Test with invalid unit
14091468
self.setUp_match_coordinates()
1410-
result = u_coord._nearest_neighbor_euclidean(
1411-
self.coords_to_assign,
1412-
self.coords,
1413-
"degree",
1414-
u_coord.NEAREST_NEIGHBOR_THRESHOLD,
1415-
check_antimeridian=False,
1416-
)
1417-
self.assertEqual(len(result), len(self.coords))
1418-
self.assertTrue(np.all(result >= -1)) # Valid indices or -1
1469+
coords_to_assign = np.deg2rad(self.coords_to_assign)
1470+
coords = np.deg2rad(self.coords)
1471+
with self.assertRaises(ValueError):
1472+
u_coord._nearest_neighbor_haversine(
1473+
coords_to_assign, coords, "km", u_coord.NEAREST_NEIGHBOR_THRESHOLD
1474+
)
14191475

14201476
def test_nearest_neighbor_euclidean_invalid_unit_with_antimeridian(self):
14211477
# Test with invalid unit when check_antimeridian=True
@@ -1429,21 +1485,6 @@ def test_nearest_neighbor_euclidean_invalid_unit_with_antimeridian(self):
14291485
check_antimeridian=True,
14301486
)
14311487

1432-
def test_nearest_neighbor_euclidean_valid_unit_with_antimeridian(self):
1433-
# Test with valid unit ('deg') and check_antimeridian=True
1434-
self.setUp_match_coordinates()
1435-
coords_to_assign = np.deg2rad(self.coords_to_assign)
1436-
coords = np.deg2rad(self.coords)
1437-
result = u_coord._nearest_neighbor_euclidean(
1438-
coords_to_assign,
1439-
coords,
1440-
"degree",
1441-
u_coord.NEAREST_NEIGHBOR_THRESHOLD,
1442-
check_antimeridian=True,
1443-
)
1444-
self.assertEqual(len(result), len(self.coords))
1445-
self.assertTrue(np.all(result >= -1)) # Valid indices or -1
1446-
14471488

14481489
class TestGetGeodata(unittest.TestCase):
14491490
def test_nat_earth_resolution_pass(self):

0 commit comments

Comments
 (0)