worldgen

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

master

raw · 3367 bytes

import shutil
import tempfile
import tracemalloc
import unittest
from pathlib import Path

import numpy as np

from mapgen import pipeline as P
from mapgen import render as RN
from mapgen.testing import small_world


def _files(root: Path) -> dict:
    return {p.relative_to(root).as_posix(): p.read_bytes()
            for p in sorted(root.rglob("*")) if p.is_file() and "cache" not in p.parts}


class LowMemoryTest(unittest.TestCase):
    def test_low_memory_build_writes_identical_files(self):
        # oracle: the normal-mode build of the same world; every output byte must match
        outs = []
        for low in (False, True):
            tmp = Path(tempfile.mkdtemp())
            try:
                small_world(tmp)
                P.build(tmp, 2, log=lambda m: None, low_memory=low)
                outs.append({**_files(tmp / "out"), **_files(tmp / "previews")})
            finally:
                shutil.rmtree(tmp)
        self.assertEqual(sorted(outs[0]), sorted(outs[1]))
        for k in outs[0]:
            self.assertEqual(outs[0][k], outs[1][k], k)

    def test_chunked_relief_matches_and_uses_less_memory(self):
        rng = np.random.default_rng(0)
        H, W = 512, 1024
        z = rng.normal(0, 2000, (H, W))
        hs = rng.random((H, W))
        zone = rng.integers(0, 38, (H, W)).astype(np.int16)
        ground = rng.integers(0, 9, (H, W)).astype(np.int8)
        ice = rng.integers(0, 5, (H, W)).astype(np.int8)
        lake = rng.random((H, W)) < 0.05
        peaks = []
        outs = []
        for low in (False, True):
            tracemalloc.start()
            outs.append(RN.relief_rgb(z, hs, zone, ground, ice, lake, low_memory=low))
            peaks.append(tracemalloc.get_traced_memory()[1])
            tracemalloc.stop()
        np.testing.assert_array_equal(outs[0], outs[1])
        self.assertLess(peaks[1], 0.4 * peaks[0])                     # measured ≈ 0.28


class ProjectionMemoryTest(unittest.TestCase):
    def test_sampling_converts_one_channel_at_a_time(self):
        from mapgen import projections as PJ
        rng = np.random.default_rng(1)
        img = rng.integers(0, 256, (512, 1024, 3), dtype=np.uint8)
        lat = rng.uniform(-90, 90, (64, 64))
        lon = rng.uniform(-180, 180, (64, 64))
        whole = img.astype(np.float64)                        # oracle: the whole-image float conversion
        want = np.stack([PJ.sample_equirect(whole[..., k], lat, lon) for k in range(3)], axis=-1)
        del whole
        tracemalloc.start()
        got = PJ._sample_rgb(img, lat, lon)
        peak = tracemalloc.get_traced_memory()[1]
        tracemalloc.stop()
        np.testing.assert_array_equal(got, want)
        self.assertLess(peak, 0.5 * img.size * 8)               # no full-size float64 copy


class HillshadeTest(unittest.TestCase):
    def test_chunked_hillshade_matches_and_uses_less_memory(self):
        z = np.random.default_rng(2).normal(0, 1500, (700, 1400))        # 700 rows: chunk edges fall mid-raster
        peaks, outs = [], []
        for low in (False, True):
            tracemalloc.start()
            outs.append(RN.hillshade(z, 6371.0, low_memory=low))
            peaks.append(tracemalloc.get_traced_memory()[1])
            tracemalloc.stop()
        np.testing.assert_array_equal(outs[0], outs[1])
        self.assertLess(peaks[1], 0.5 * peaks[0])