import json import unittest import numpy as np from mapgen import seabed as SB from mapgen.graph import distance_to from tests.helpers import make_ctx def sea_ctx(tect=None): ctx = make_ctx(3, tect=tect or {"plate": []}) g = ctx.grid land = (np.abs(g.lat) < 30) & (np.abs(g.lon) < 40) ridge = np.abs(g.lon - 120) < 1.0 d_div = distance_to(g, ridge) age = np.where(land, 0.0, np.minimum(d_div / 30.0, 200.0)) ctx.data.update({"elevation_eroded_m": np.where(land, 500.0, -4500.0).astype(np.float32), "ocean": ~land, "continental": land, "ocean_age_myr": age.astype(np.float32), "d_div_km": d_div, "d_over_km": np.full(g.n, np.inf), "d_sub_km": np.full(g.n, np.inf), "T_mean": 25.0 - 0.5 * np.abs(g.lat), "vel": np.zeros((g.n, 3))}) return ctx class SeabedTest(unittest.TestCase): def test_land_has_no_sea_floor(self): ctx = sea_ctx() out = SB.run(ctx) land = ~ctx.data["ocean"] for k in ("vent_potential", "seabed_type", "seabed_mineral", "bottom_temp_c", "sediment_m"): self.assertTrue(np.all(np.asarray(out[k])[land] == 0), k) def test_vents_on_the_ridge_not_far_from_it(self): ctx = sea_ctx() out = SB.run(ctx) d = ctx.data["d_div_km"] self.assertGreaterEqual(out["vent_potential"][d == 0].min(), 0.5) self.assertLess(out["vent_potential"][ctx.data["ocean"] & (d > 3000)].max(), 0.05) def test_sediment_thickens_with_age_away_from_land(self): ctx = sea_ctx() out = SB.run(ctx) g = ctx.grid young = ctx.data["ocean"] & (ctx.data["d_div_km"] < 300) & (np.abs(g.lon) > 90) old = ctx.data["ocean"] & (ctx.data["ocean_age_myr"] > 100) & (np.abs(g.lon) > 90) self.assertLess(out["sediment_m"][young].mean(), out["sediment_m"][old].mean()) def test_bottom_temperature(self): ctx = sea_ctx() g = ctx.grid eq, polar = g.cell_index(0.0, 170.0), g.cell_index(-80.0, 170.0) z = np.asarray(ctx.data["elevation_eroded_m"]).copy() shallow = g.cell_index(-20.0, 170.0) z[shallow] = -100.0 ctx.data["elevation_eroded_m"] = z out = SB.run(ctx) self.assertAlmostEqual(out["bottom_temp_c"][eq], 1.0 + 3.0 * np.cos(np.radians(g.lat[eq])) ** 2, places=4) self.assertLess(out["bottom_temp_c"][polar], 1.3) deep = 1.0 + 3.0 * np.cos(np.radians(g.lat[shallow])) ** 2 t = 25.0 - 0.5 * abs(g.lat[shallow]) self.assertAlmostEqual(out["bottom_temp_c"][shallow], deep + 0.875 * (t - deep), places=3) def test_plateau_volcanic_field_makes_volcanic_sea_floor(self): plat = {"name": "p", "center": [0.0, -150.0], "area_km2": 3.0e6, "top_m": [1500.0, 3000.0]} ctx = sea_ctx({"plate": [], "plateau": [plat]}) out = SB.run(ctx) from mapgen.crust import center_dist near = center_dist(ctx.grid, [0.0, -150.0]) < 800.0 self.assertTrue(np.isin(out["seabed_type"][near], [SB.SB_VOLCANIC, SB.SB_VENTS]).any()) self.assertGreater(out["vent_potential"][near].max(), 0.3) def test_deterministic(self): a, b = SB.run(sea_ctx()), SB.run(sea_ctx()) for k in a: np.testing.assert_array_equal(a[k], b[k]) class SeabedRenderTest(unittest.TestCase): def test_rasters_legends_and_plateaus_in_the_build(self): from mapgen.testing import built_world out = built_world() / "out" / "r2" fields = json.loads((out / "fields.json").read_text()) for name in ("pressure", "o2_fraction", "fire", "vent_potential", "bottom_temp", "sediment", "plant_height"): self.assertIn(name, fields["continuous"]) self.assertTrue((out / "raster" / f"{name}.png").exists(), name) for name in ("seabed_type", "seabed_mineral"): self.assertIn(name, fields["categorical"]) meta = json.loads((out / "cells_meta.json").read_text()) self.assertEqual(meta["legends"]["seabed_type"], SB.SEABED_NAMES) self.assertEqual(meta["plateaus"], []) with np.load(out / "cells.npz") as z: for k in ("vent_potential", "seabed_type", "pressure_bar", "fire_reactivity", "plateau_id"): self.assertIn(k, z.files)