import unittest
import numpy as np
from mapgen.grid import Grid
from tests.helpers import small_grid
class GridTest(unittest.TestCase):
def test_counts_and_pentagons(self):
g = small_grid(2)
self.assertEqual(g.n, 5882)
self.assertTrue(np.all(np.diff(g.ids.astype(np.int64)) > 0))
self.assertEqual(int(np.sum(g.counts == 5)), 12)
self.assertEqual(int(np.sum(g.counts == 6)), g.n - 12)
def test_neighbours_symmetric(self):
g = small_grid(2)
pairs = set(zip(g.src.tolist(), g.dst.tolist()))
self.assertTrue(all((b, a) in pairs for a, b in pairs))
def test_area_sums_to_sphere(self):
g = small_grid(2)
self.assertAlmostEqual(g.area_km2.sum() / (4 * np.pi * 12742.0**2), 1.0, places=6)
def test_spacing_and_tangents(self):
g = small_grid(2)
self.assertTrue(500 < g.spacing_km < 800) # res 2 ≈ 632 km
np.testing.assert_allclose(np.linalg.norm(g.edge_tangents, axis=1), 1.0)
np.testing.assert_allclose(np.sum(g.edge_tangents * g.xyz[g.src], axis=1), 0.0, atol=1e-12)
def test_roundtrip_arrays_and_lookup(self):
g = small_grid(2)
h = Grid.from_arrays(g.to_arrays(), g.res, g.radius_km)
np.testing.assert_array_equal(h.nbr_idx, g.nbr_idx)
i = g.cell_index(10.0, 20.0)
self.assertLess(abs(g.lat[i] - 10.0), 5.0)
class CellParentsTest(unittest.TestCase):
def test_same_as_h3_cell_to_parent(self):
import h3.api.basic_int as h3
import numpy as np
from mapgen.grid import cell_parents
rng = np.random.default_rng(5)
for res in (1, 3, 6, 9):
cells = [h3.latlng_to_cell(float(la), float(lo), res + int(k))
for la, lo, k in zip(rng.uniform(-90, 90, 300), rng.uniform(-180, 180, 300), rng.integers(0, 4, 300))]
pent = h3.get_pentagons(max(res - 2, 0))[:2] + [h3.latlng_to_cell(10.0, 20.0, max(res - 2, 0))]
cells += [c for p in pent for c in h3.cell_to_children(p, res)] # incl. pentagons
for pr in range(0, res + 1):
want = np.array([h3.cell_to_parent(c, pr) for c in cells], np.uint64)
self.assertTrue(np.array_equal(cell_parents(cells, pr), want), (res, pr))
with self.assertRaises(ValueError):
cell_parents([h3.latlng_to_cell(0.0, 0.0, 2)], 3)
class EdgeBlocksTest(unittest.TestCase):
def test_blocked_edge_fields_same_as_whole(self):
from unittest import mock
from mapgen import grid as GR
from mapgen import plates as PL
from mapgen.sphere import tangent_dir
g = small_grid(3)
xyz, src, dst = g.xyz, g.src, g.dst
want_t = tangent_dir(xyz[src], xyz[dst]) # the whole-array formulas, written out
want_km = g.radius_km * np.arccos(np.clip(np.sum(xyz[src] * xyz[dst], axis=1), -1.0, 1.0))
vel = np.random.default_rng(2).normal(size=(g.n, 3))
rel = vel[dst] - vel[src]
along = np.sum(rel * want_t, axis=1)
want_tang = np.linalg.norm(rel - along[:, None] * want_t, axis=1)
with mock.patch.object(GR, "EDGE_BLOCK", 997): # many uneven blocks
g2 = small_grid(3)
self.assertTrue(np.array_equal(g2.edge_tangents, want_t))
self.assertTrue(np.array_equal(g2.edge_km, want_km))
conv, tang = PL.edge_convergence(g2, vel)
self.assertTrue(np.array_equal(conv, -along))
self.assertTrue(np.array_equal(tang, want_tang))
self.assertGreater(len(GR.edge_blocks(len(dst), 997)), 3)
with mock.patch.object(GR, "EDGE_BLOCK", 997):
for idx in (src, dst):
self.assertTrue(np.array_equal(GR.rowdot_at(vel, idx, want_t), np.sum(vel[idx] * want_t, axis=1)))
self.assertTrue(np.array_equal(GR.rowdot_at(vel, idx, want_t), np.sum(want_t * vel[idx], axis=1)))