#!/usr/bin/env python3 """ Pins the mountain-rock rule in `compute_biome`, which compared kelvin against 0.35 (T-1295). `compute_biome` receives absolute kelvin, but the rule was written against a 0-1 scale, so from the generator's first commit mountain rock could never fire. Nothing noticed, because no test asked the rule to fire, or to hold back. These do both, on a synthetic body whose answer is known. The sulfuric-scrub rule had the same unit bug and is fixed alongside it, but it is not pinned here: it converts rock only at elev_norm 0.25-0.65, while rock exists only above 0.65, so it cannot fire at all. Making it reachable is a design call, not a units fix. Run directly or via `make test-tooling`: .venv/bin/python tooling/test_planet_biome_rules.py """ import sys import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) import numpy as np # noqa: E402 from tooling.domains.atlas.planet.planet_simulation import ( # noqa: E402 GRID_H, GRID_W, LAYER_NONE, compose_layers, compute_biome, compute_biome_layers, ) MOUNTAIN_ROCK = 18 SEA_LEVEL = 0.2 def _body(substrate: str = "silicate") -> dict: return { "seed": 7, "planet_class": "temperate", "body_type": "planet", "physical": {"atmosphere": "standard"}, # No hydrosphere: keeps high ground out of the snow rule, so rock is # the only rule that can claim it. "environment": {"hydrosphere": "none", "substrate": substrate}, } def _world(temp_k: np.ndarray, elev: np.ndarray) -> np.ndarray: water = np.zeros((GRID_H, GRID_W), dtype=bool) moisture = np.full((GRID_H, GRID_W), 0.5, dtype=np.float32) return compute_biome(_body(), elev, SEA_LEVEL, water, temp_k, moisture) class MountainRockTests(unittest.TestCase): def setUp(self): # West half high ground, east half low. Temperature runs 275-305 K # west to east, the temperate band, so the high west is the cold third. self.elev = np.full((GRID_H, GRID_W), 0.3, dtype=np.float32) self.elev[:, : GRID_W // 2] = 0.95 # elev_norm ~0.94, above the 0.65 gate ramp = np.linspace(275.0, 305.0, GRID_W, dtype=np.float32) self.temp = np.tile(ramp, (GRID_H, 1)) def test_cold_high_ground_is_rock(self): biome = _world(self.temp, self.elev) cold_high = biome[:, : int(GRID_W * 0.30)] share = float((cold_high == MOUNTAIN_ROCK).mean()) # The anomaly scatter repaints ~3% of land, so "all of it" is too # strong; the dead rule scored exactly 0 here. self.assertGreater(share, 0.9, f"cold high ground rock share {share:.3f}") def test_warm_or_low_ground_is_not_rock(self): biome = _world(self.temp, self.elev) warm_high = biome[:, int(GRID_W * 0.40) : GRID_W // 2] low = biome[:, GRID_W // 2 :] self.assertEqual(int((warm_high == MOUNTAIN_ROCK).sum()), 0) self.assertEqual(int((low == MOUNTAIN_ROCK).sum()), 0) class LayerSplitTests(unittest.TestCase): """D-258 ruling 6: biome and terrain are two maps (T-1295).""" def _layers(self, atmosphere: str, water_rows: int = 0): elev = np.full((GRID_H, GRID_W), 0.3, dtype=np.float32) elev[:, : GRID_W // 2] = 0.95 # high west, as in MountainRockTests water = np.zeros((GRID_H, GRID_W), dtype=bool) if water_rows: water[-water_rows:, :] = True # a southern sea elev[-water_rows:, :] = 0.05 temp = np.tile(np.linspace(275.0, 305.0, GRID_W, dtype=np.float32), (GRID_H, 1)) moisture = np.full((GRID_H, GRID_W), 0.5, dtype=np.float32) body = _body() body["physical"]["atmosphere"] = atmosphere body["environment"]["hydrosphere"] = "liquid_water" if water_rows else "none" biome, terrain = compute_biome_layers(body, elev, SEA_LEVEL, water, temp, moisture) return biome, terrain, water def test_rock_keeps_its_biome_beneath(self): # The point of the split: the climate class under a mountain survives. biome, terrain, _ = self._layers("standard") rock = terrain == MOUNTAIN_ROCK self.assertTrue(rock.any()) self.assertFalse((biome[rock] == LAYER_NONE).any(), "rock with no biome beneath") def test_thin_atmosphere_is_bare_ground_with_scattered_life(self): # Thin worlds skip the Whittaker table, so their ground is terrain. The # only life is what the anomaly scatter places (it skips airless worlds # only): oasis savanna, shrubs, pioneers. So the biome map is sparse and # holds nothing but those classes. biome, terrain, _ = self._layers("thin") placed = biome != LAYER_NONE self.assertLess(float(placed.mean()), 0.10, "thin world carries a climate biome") self.assertTrue(np.isin(biome[placed], (4, 7, 12, 24)).all(), set(np.unique(biome[placed]))) self.assertFalse((terrain[~placed] == LAYER_NONE).any()) def test_water_is_terrain_only(self): biome, terrain, water = self._layers("standard", water_rows=64) self.assertTrue((biome[water] == LAYER_NONE).all()) self.assertTrue(np.isin(terrain[water], (0, 1, 2, 26)).all()) def test_no_pixel_is_empty_on_both_maps(self): for atmo, rows in (("standard", 0), ("standard", 64), ("thin", 0)): biome, terrain, _ = self._layers(atmo, water_rows=rows) both = (biome == LAYER_NONE) & (terrain == LAYER_NONE) self.assertFalse(both.any(), f"{atmo}/{rows}: {int(both.sum())} px on neither map") def test_stacking_the_maps_is_the_rendered_grid(self): biome, terrain, water = self._layers("standard", water_rows=64) composed = compose_layers(biome, terrain) elev = np.full((GRID_H, GRID_W), 0.3, dtype=np.float32) elev[:, : GRID_W // 2] = 0.95 elev[-64:, :] = 0.05 temp = np.tile(np.linspace(275.0, 305.0, GRID_W, dtype=np.float32), (GRID_H, 1)) body = _body() body["environment"]["hydrosphere"] = "liquid_water" grid = compute_biome(body, elev, SEA_LEVEL, water, temp, np.full((GRID_H, GRID_W), 0.5, dtype=np.float32)) self.assertTrue(np.array_equal(composed, grid)) if __name__ == "__main__": unittest.main()