worldgen

git clone https://git.godosa.eu/worldgen

master

raw · 3376 bytes

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))