# map/tests/test_plateaus.py import json import unittest import numpy as np from mapgen import plateaus as PL from mapgen.sphere import east_north, great_circle_point, latlon_to_xyz from tests.helpers import small_grid R = 12742.0 P1 = {"name": "east-flank", "center": [-39.9, -18.0], "area_km2": 3.0e6, "elongation": 1.9, "azimuth_deg": 30.0, "top_m": [1500.0, 3000.0]} P2 = {"name": "plateau-02", "center": [-0.4, 176.6], "area_km2": 1.0e6, "top_m": [1000.0, 1500.0], "islands": True} def at(lat, lon): return latlon_to_xyz(lat, lon)[None] class PlateauGeometryTest(unittest.TestCase): def test_centre_inside_and_area_close_to_config(self): g = small_grid(4) for p in (P1, P2): self.assertLess(PL.rho(at(*p["center"]), p, 1296, R)[0], 1e-6) area = g.area_km2[PL.rho(g.xyz, p, 1296, R) < 1.0].sum() self.assertAlmostEqual(area / p["area_km2"], 1.0, delta=0.2, msg=p["name"]) def test_long_axis_follows_the_azimuth(self): a, b = PL.semi_axes(P1) self.assertAlmostEqual(a / b, 1.9) self.assertAlmostEqual(np.pi * a * b, P1["area_km2"], delta=1.0) c = latlon_to_xyz(*P1["center"]) e, n = east_north(c[None]) az = np.radians(30.0) along = np.sin(az) * e[0] + np.cos(az) * n[0] across = np.cos(az) * e[0] - np.sin(az) * n[0] self.assertLess(PL.rho(great_circle_point(c, along, 0.8 * a, R)[None], P1, 1296, R)[0], 1.0) self.assertGreater(PL.rho(great_circle_point(c, across, 0.8 * a, R)[None], P1, 1296, R)[0], 1.0) def test_features_are_deterministic_inside_and_json_ready(self): f = PL.features(P2, 1296, R) self.assertEqual(f, PL.features(P2, 1296, R)) json.dumps(f) self.assertTrue(6 <= len(f["cones"]) <= 20) self.assertTrue(1 <= len(f["calderas"]) <= 3) self.assertTrue(3 <= sum(c["island"] for c in f["cones"]) <= 6) for c in f["cones"] + f["calderas"]: self.assertLess(PL.rho(at(c["lat"], c["lon"]), P2, 1296, R)[0], 0.86) self.assertFalse(any(c["island"] for c in PL.features(P1, 1296, R)["cones"])) self.assertEqual(PL.features({**P1, "vent": 0.0}, 1296, R)["cones"], []) def test_surface_depth_follows_top_m(self): g = small_grid(4) inner = g.xyz[PL.rho(g.xyz, P1, 1296, R) < 0.5] z = PL.surface(inner, P1, {"cones": [], "calderas": []}, 1296, R, np.full(len(inner), -5900.0)) self.assertTrue(np.all(z <= -P1["top_m"][0] + PL.RELIEF_M + 1e-6)) self.assertTrue(np.all(z >= -P1["top_m"][1] - PL.RELIEF_M - 1e-6)) def test_apply_hidden_clamp_islands_and_nothing_else(self): g = small_grid(4) plats = [P1, P2] ids = PL.cell_ids(g.xyz, plats, 1296, R) self.assertGreater((ids == 0).sum(), 100) z = PL.apply(g, np.full(g.n, -6000.0), plats, ids, 1296) self.assertLessEqual(z[ids == 0].max(), PL.HIDDEN_MAX_M) self.assertGreater(z.max(), 0.0, "island plateau: small volcanic islands") changed_outside = (ids < 0) & (z != -6000.0) self.assertLessEqual(changed_outside.sum(), 6, "only islands' nearest cells may lie outside the outline") def test_outline_across_the_antimeridian_and_near_the_pole(self): p = {"name": "plateau-11", "center": [77.0, 179.0], "area_km2": 0.9e6, "top_m": [1000.0, 1500.0]} self.assertLess(PL.rho(at(77.0, 179.8), p, 1296, R)[0], 0.3) self.assertLess(PL.rho(at(77.0, -179.8), p, 1296, R)[0], 0.3) q = {"name": "polar", "center": [88.0, 0.0], "area_km2": 1.0e6, "top_m": [1000.0, 1500.0]} self.assertLess(PL.rho(at(89.9, 90.0), q, 1296, R)[0], 1.0) self.assertLess(PL.rho(at(89.9, -90.0), q, 1296, R)[0], 1.0) self.assertTrue(np.all(np.isfinite(PL.rho(small_grid(3).xyz, q, 1296, R))))