import unittest from pathlib import Path import numpy as np from mapgen import climate as CL from tests.helpers import make_ctx GOLDEN = Path(__file__).parent / "data" / "climate_golden_r2.npz" NEW = ("current", "current_speed", "sst", "upwelling", "productivity") def golden_ctx(cfg=None): ctx = make_ctx(2, cfg=cfg) g = ctx.grid land = (np.abs(g.lat) < 40) & (np.abs(g.lon) < 50) ctx.data["elevation_eroded_m"] = np.where(land, np.where(np.abs(g.lon) < 10, 2500.0, 300.0), -4000.0).astype(np.float32) return ctx, land class OceanDisabledTest(unittest.TestCase): def test_disabled_reproduces_pre_ocean_climate(self): ctx, land = golden_ctx({"ocean": {"enabled": False}}) out = CL.run(ctx) ref = np.load(GOLDEN) for k in ref.files: np.testing.assert_array_equal(out[k], ref[k], err_msg=k) self.assertTrue(np.all(out["current"] == 0) and np.all(out["productivity"] == 0)) np.testing.assert_array_equal(out["sst"], out["T_mean"].astype(np.float32)) class OceanCoupledTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.ctx, cls.land = golden_ctx() cls.out = CL.run(cls.ctx) def test_new_fields(self): g, out = self.ctx.grid, self.out for k in NEW: self.assertIn(k, out) self.assertEqual(out[k].dtype, np.float32, k) self.assertTrue(np.all(np.isfinite(out[k])), k) self.assertEqual(out["current"].shape, (g.n, 3)) self.assertTrue(np.all(out["current"][self.land] == 0)) np.testing.assert_allclose(out["current_speed"], np.linalg.norm(out["current"], axis=1), rtol=1e-5) sea = ~self.land self.assertTrue(np.all((out["sst"][sea] >= -1.8) & (out["sst"][sea] < 40))) # sea water freezes at −1.8 °C def test_currents_change_the_climate(self): ref = np.load(GOLDEN) self.assertGreater(np.abs(self.out["T_mean"] - ref["T_mean"]).max(), 0.5) # the old gyre rule is gone def test_winds_come_from_current_free_temperatures(self): ctx, _ = golden_ctx({"ocean": {"relax_days": 30.0}}) # other SST, same winds np.testing.assert_array_equal(CL.run(ctx)["wind_jun"], self.out["wind_jun"]) def test_unknown_ocean_key_is_an_error(self): from mapgen.config import ConfigError ctx, _ = golden_ctx({"ocean": {"frictoin_days": 3.0}}) with self.assertRaises(ConfigError): CL.run(ctx) def test_all_land_world(self): ctx = make_ctx(2) ctx.data["elevation_eroded_m"] = np.full(ctx.grid.n, 500.0, np.float32) out = CL.run(ctx) self.assertTrue(np.all(out["current"] == 0)) def test_locked_world_has_still_ocean(self): ctx, land = golden_ctx({"climate": {"lock": True}}) out = CL.run(ctx) self.assertTrue(np.all(out["current"] == 0) and np.all(out["upwelling"] == 0)) np.testing.assert_array_equal(out["sst"], out["T_mean"].astype(np.float32)) def test_upwelling_and_productivity_filled(self): sea = ~self.land self.assertGreater(np.abs(self.out["upwelling"][sea]).max(), 1.0) self.assertGreater(self.out["productivity"][sea].max(), 0.05) self.assertTrue(np.all(self.out["productivity"][self.land] == 0))