"""Isolated NumPy CPU reference: one static 2:1 rectangular patch, volumetric transfer. API version CPUREF-0.3 (ClaudeWorker, 2026-10-13). NOT EXECUTED BY THE AUTHOR: written without a shell; Grok/Horsea run it. A test-reference CANDIDATE, not a certified truth and not a project implementation. v0.2 (Drive 1gfYrjdpzLxQ8LCZAH_pMMQRLSSuvFMIf, SHA256 b6adbad7...) is kept unchanged. Scope of evidence Checked for conservation and bookkeeping only. Interface accuracy/stress transfer is unvalidated (for every tau, tau_coarse = 1 included). Changes from v0.2 (jointly agreed small patch; numerical algorithm unchanged): * explosion_count removed (it was a constant); explosion_writes is the evidence. * Corner-pass links are derived from the coalescence map (rows whose coarse source cell is not covered): all 8, each with a unique key "_q", e.g. "lower_left_q8", "lower_left_q7". corner_packets is keyed the same way. * Diagnostic renames: fine_valid_after -> hop2_valid; budget closure_error -> bookkeeping_check. * Per-packet path records (coalesce_paths, origin_g copy) moved to the tests; cheap in-code guards kept (invalid packet, path through an outer ghost). * Coalescence moved into a _coalesce helper. * state.tick must be a non-negative even integer (synchronised phase); other values are rejected instead of int()-truncated. Contract: AMR_Shared_CPU_API_2026-10-13.md SHA256 ee8010e763d38937b95c34dadaf97415cdb8b6c23e3c79a9f1f32bd5d4e112f6 plus root amendment: make_spec(*, collision='identity'|'srt'), stored in Spec. Snapshot: 20-file snapshot SHA256 e45df47d0fabde7199d345ada0729bca9ee64a833f433cdd776a4774b6af0673 Dependencies: NumPy and the standard library only. No CelerisLab/CUDA imports. Conventions D2Q9 paired ordering cx=(0,1,-1,0,0,1,-1,1,-1), cy=(0,0,0,1,-1,1,-1,-1,1). Arrays are Q-major [q, y, x], float64, unshifted physical populations. Coarse cell (x, y) has centre (x+.5, y+.5) on the doubly periodic [0,16)^2. The patch covers coarse cells [4,12)^2 (covered). Fine index a = 0..23 (halo 4) has centre 4 + (a-4+.5)/2 and coarse parent 4 + (a-4)//2; active fine is [:, 4:20, 4:20]. Fine cell volume is 1/4 of a coarse cell. Invalid entries (covered coarse, fine ghosts at synchronisation) hold NaN. Phase rule advance_coarse_once maps arrival f(t) to arrival f(t+1). Production stores post-collision g. Compare C(f_ref) with g_prod at a matched tick; never compare f with g directly and never apply C to a stored g again. Synchronised phase "arrival_f". One advance_coarse_once (Schornbaum & Ruede 2016, Sec. 4 order): 1 collide coarse active cells g_c = C_c(f_c(t)) tau_c 2 collide fine active cells g_f = C_f(f_f(t)) tau_f 3 explode: every fine ghost cell (inner and outer) receives g_c of its coarse parent in all directions; once per coarse step, no rescaling 4 fine stream, hop 1; targets are active cells and inner ghosts (inner ghosts stream but never collide) 5 collide fine active cells only; outer ghosts are poisoned (NaN, invalid) 6 fine stream, hop 2; active cells now hold f_f(t+1) 7 coarse periodic stream; incoming populations of covered cells are invalid 8 coalesce: for each non-covered coarse cell K and direction i whose link midpoint (centre(K) - c_i/2) lies in the CLOSED patch, replace the coarse incoming population by the mean of K's four inner-ghost children's slot i (includes the 8 corner-pass links, e.g. (4,3)->(3,4), i=8). Assumptions (stated, not validated by rest-state tests) * Ghosts hold g_c(t) for the whole coarse step and inner ghosts never collide, so ghost-sourced inflow into the first fine layer is an uncollided coarse packet in both hops. * The closed corner rule matters only through the mid-step fine collision: with identity collision the open-corner variant is also conservative, so identity-only tests cannot distinguish the two rules; use SRT with non-equilibrium states. * Budget: bookkeeping_check is self-consistency of this file's flux accounting (it subtracts interface_residual), NOT conservation evidence; test leaf_before/leaf_after and interface_residual independently. """ from __future__ import annotations from dataclasses import dataclass from typing import NamedTuple import numpy as np API_VERSION = "CPUREF-0.3" CONTRACT_SHA256 = "ee8010e763d38937b95c34dadaf97415cdb8b6c23e3c79a9f1f32bd5d4e112f6" SNAPSHOT_SHA256 = "e45df47d0fabde7199d345ada0729bca9ee64a833f433cdd776a4774b6af0673" NQ = 9 CX = np.array([0, 1, -1, 0, 0, 1, -1, 1, -1], dtype=np.int64) CY = np.array([0, 0, 0, 1, -1, 1, -1, -1, 1], dtype=np.int64) OPP = np.array([0, 2, 1, 4, 3, 6, 5, 8, 7], dtype=np.int64) W = np.array([4 / 9] + [1 / 9] * 4 + [1 / 36] * 4, dtype=np.float64) FINE_VOLUME = 0.25 # Moment weights per direction: (mass, x-momentum, y-momentum). MOMENTS = np.stack([np.ones(NQ), CX.astype(np.float64), CY.astype(np.float64)], axis=1) ACTIVE, INNER_GHOST, OUTER_GHOST = 0, 1, 2 @dataclass(frozen=True) class Spec: patch_id: str = "P0" n_coarse: int = 16 patch_lo: int = 4 patch_hi: int = 12 halo: int = 4 dt_coarse: float = 1.0 dt_fine: float = 0.5 tau_coarse: float = 0.8 tau_fine: float = 1.1 collision: str = "identity" @property def n_fine(self) -> int: return 2 * (self.patch_hi - self.patch_lo) + 2 * self.halo @dataclass(frozen=True) class State: coarse_f: np.ndarray fine_f: np.ndarray phase: str = "arrival_f" tick: int = 0 class CornerLink(NamedTuple): key: str # "_q", unique over the 8 corner-pass links i: int source_xy: tuple # uncovered coarse source cell (x, y) target_xy: tuple # coarse target cell K (x, y) @dataclass(frozen=True) class Maps: coarse_active: np.ndarray # (n, n) bool [y, x] coarse_covered: np.ndarray # (n, n) bool fine_active: np.ndarray # (nf, nf) bool fine_inner_ghost: np.ndarray # (nf, nf) bool fine_outer_ghost: np.ndarray # (nf, nf) bool fine_class: np.ndarray # (nf, nf) int: ACTIVE / INNER_GHOST / OUTER_GHOST fine_parent: np.ndarray # (nf,) coarse parent index (same for x and y) fine_centre: np.ndarray # (nf,) physical centre (same for x and y) coalesce: np.ndarray # (M, 3) rows (i, ky, kx) corner_links: tuple # 8 x CornerLink, sorted by key def make_spec(*, collision: str = "identity") -> Spec: if collision not in ("identity", "srt"): raise ValueError("collision must be 'identity' or 'srt'") spec = Spec(collision=collision) if not np.isclose(spec.tau_fine - 0.5, 2.0 * (spec.tau_coarse - 0.5)): raise ValueError("tau values violate acoustic 2:1 scaling") if not np.isclose(spec.dt_fine, 0.5 * spec.dt_coarse): raise ValueError("dt values violate 2:1 time refinement") return spec def _readonly(array) -> np.ndarray: array = np.array(array) array.setflags(write=False) return array def _children_start(spec: Spec, k: int) -> int: """First fine index of the two children of coarse index k.""" return spec.halo + 2 * (k - spec.patch_lo) def build_maps(spec: Spec) -> Maps: n, lo, hi, nf = spec.n_coarse, spec.patch_lo, spec.patch_hi, spec.n_fine idx = np.arange(n) inside = (idx >= lo) & (idx < hi) covered = inside[:, None] & inside[None, :] a = np.arange(nf) parent = lo + (a - spec.halo) // 2 centre = lo + (a - spec.halo + 0.5) / 2 active_1d = (a >= spec.halo) & (a < nf - spec.halo) ring_1d = (parent >= lo - 1) & (parent <= hi) # children of patch or first ring fine_active = active_1d[:, None] & active_1d[None, :] near = ring_1d[:, None] & ring_1d[None, :] inner = near & ~fine_active outer = ~near fine_class = np.where(fine_active, ACTIVE, np.where(inner, INNER_GHOST, OUTER_GHOST)) rows = [] for ky in range(n): for kx in range(n): if covered[ky, kx]: continue for i in range(1, NQ): mx = kx + 0.5 - CX[i] / 2.0 my = ky + 0.5 - CY[i] / 2.0 if lo <= mx <= hi and lo <= my <= hi: rows.append((i, ky, kx)) coalesce = np.array(rows, dtype=np.int64).reshape(-1, 3) for i, ky, kx in coalesce: y0, x0 = _children_start(spec, ky), _children_start(spec, kx) if not inner[y0:y0 + 2, x0:x0 + 2].all(): raise AssertionError("coalescence target children must be inner ghosts") # Corner-pass links: coalesced rows whose coarse source cell is not covered. links = [] for i, ky, kx in coalesce.tolist(): sx, sy = kx - int(CX[i]), ky - int(CY[i]) if covered[sy, sx]: continue mx, my = kx + 0.5 - CX[i] / 2.0, ky + 0.5 - CY[i] / 2.0 if mx not in (lo, hi) or my not in (lo, hi): raise AssertionError("corner-pass link must cross a patch corner point") name = ("lower" if my == lo else "upper") + ("_left" if mx == lo else "_right") links.append(CornerLink(f"{name}_q{i}", i, (sx, sy), (kx, ky))) links.sort(key=lambda link: link.key) if len(links) != 8 or len({link.key for link in links}) != 8: raise AssertionError("expected 8 uniquely keyed corner-pass links") return Maps( coarse_active=_readonly(~covered), coarse_covered=_readonly(covered), fine_active=_readonly(fine_active), fine_inner_ghost=_readonly(inner), fine_outer_ghost=_readonly(outer), fine_class=_readonly(fine_class), fine_parent=_readonly(parent), fine_centre=_readonly(centre), coalesce=_readonly(coalesce), corner_links=tuple(links)) def _equilibrium(rho, ux, uy) -> np.ndarray: """D2Q9 second-order equilibrium; inputs are 1-D arrays of equal length.""" cu = CX[:, None] * ux[None, :] + CY[:, None] * uy[None, :] usq = ux * ux + uy * uy return W[:, None] * rho[None, :] * (1.0 + 3.0 * cu + 4.5 * cu * cu - 1.5 * usq[None, :]) def make_state(spec: Spec, rho: float = 1.0, velocity=(0.0, 0.0)) -> State: maps = build_maps(spec) ux, uy = velocity feq = _equilibrium(np.array([rho], float), np.array([ux], float), np.array([uy], float))[:, 0] n, nf = spec.n_coarse, spec.n_fine coarse = np.full((NQ, n, n), np.nan) fine = np.full((NQ, nf, nf), np.nan) coarse[:, maps.coarse_active] = feq[:, None] fine[:, maps.fine_active] = feq[:, None] return State(coarse_f=coarse, fine_f=fine, phase="arrival_f", tick=0) def _collide(spec: Spec, f: np.ndarray, valid: np.ndarray, tau: float, mask: np.ndarray, counts: np.ndarray) -> np.ndarray: """Collision on masked cells (counted here); other cells copied unchanged.""" if not valid[:, mask].all(): raise RuntimeError("collision touches a cell with an invalid direction") g = f.copy() if spec.collision == "srt": fm = f[:, mask] rho = fm.sum(axis=0) ux = (CX[:, None] * fm).sum(axis=0) / rho uy = (CY[:, None] * fm).sum(axis=0) / rho g[:, mask] = fm - (fm - _equilibrium(rho, ux, uy)) / tau counts[mask] += 1 return g def _explode(gc, coarse_valid, gf, fine_valid, maps: Maps, writes: np.ndarray) -> None: """Copy each ghost's coarse parent into it (all directions); counts writes.""" ghosts = maps.fine_inner_ghost | maps.fine_outer_ghost gy, gx = np.nonzero(ghosts) py, px = maps.fine_parent[gy], maps.fine_parent[gx] if not coarse_valid[:, py, px].all(): raise RuntimeError("explosion source is not a valid coarse cell") gf[:, gy, gx] = gc[:, py, px] fine_valid[:, gy, gx] = True np.add.at(writes, (gy, gx), 1) def _stream_periodic(g: np.ndarray) -> np.ndarray: out = np.empty_like(g) for i in range(NQ): out[i] = np.roll(g[i], (CY[i], CX[i]), axis=(0, 1)) # out[y,x] = g[y-cy, x-cx] return out def _shift(a: np.ndarray, dy: int, dx: int, fill) -> np.ndarray: """out[y, x] = a[y-dy, x-dx]; `fill` where the source lies outside the array.""" out = np.full(a.shape, fill, dtype=a.dtype) ny, nx = a.shape out[max(dy, 0):ny + min(dy, 0), max(dx, 0):nx + min(dx, 0)] = \ a[max(-dy, 0):ny + min(-dy, 0), max(-dx, 0):nx + min(-dx, 0)] return out def _fine_hop(g: np.ndarray, valid: np.ndarray, maps: Maps): """One fine pull-stream to active cells and inner ghosts, with exchange records.""" targets = maps.fine_active | maps.fine_inner_ghost src_class = maps.fine_class.astype(np.float64) out = np.full_like(g, np.nan) out_valid = np.zeros_like(valid) inflow = np.zeros(3) # into active cells from ghost sources (fine-volume units) outflow = np.zeros(3) # from active sources into inner-ghost targets sources = {"active": 0, "inner_ghost": 0, "outer_ghost": 0, "outside": 0} with np.errstate(invalid="ignore"): for i in range(NQ): dy, dx = int(CY[i]), int(CX[i]) moved = _shift(g[i], dy, dx, np.nan) cls = _shift(src_class, dy, dx, np.nan) out[i] = moved out_valid[i] = _shift(valid[i], dy, dx, False) & targets from_ghost = maps.fine_active & (cls >= INNER_GHOST) to_ghost = maps.fine_inner_ghost & (cls == ACTIVE) inflow += MOMENTS[i] * moved[from_ghost].sum() outflow += MOMENTS[i] * moved[to_ghost].sum() act_cls = cls[maps.fine_active] sources["active"] += int(np.sum(act_cls == ACTIVE)) sources["inner_ghost"] += int(np.sum(act_cls == INNER_GHOST)) sources["outer_ghost"] += int(np.sum(act_cls == OUTER_GHOST)) sources["outside"] += int(np.sum(np.isnan(act_cls))) out[:, ~targets] = np.nan out[~out_valid] = np.nan return out, out_valid, FINE_VOLUME * inflow, FINE_VOLUME * outflow, sources def _coalesce(spec: Spec, maps: Maps, f2, hop2_valid, fc_new, new_valid, owner): """Overwrite each listed coarse incoming slot with the mean of its four inner-ghost children (fc_new, new_valid, owner updated in place). Returns (replaced, coalesced, writes, reads).""" n, nf = spec.n_coarse, spec.n_fine replaced = np.zeros(3) coalesced = np.zeros(3) writes = np.zeros((NQ, n, n), dtype=np.int64) reads = np.zeros((NQ, nf, nf), dtype=np.int64) for i, ky, kx in maps.coalesce.tolist(): y0, x0 = _children_start(spec, ky), _children_start(spec, kx) kids = (slice(y0, y0 + 2), slice(x0, x0 + 2)) if not hop2_valid[i][kids].all(): raise RuntimeError(f"invalid coalescence packet (i={i}, K=({kx},{ky}))") ym, xm = y0 - int(CY[i]), x0 - int(CX[i]) # hop-2 sources (intermediates) if (maps.fine_class[ym:ym + 2, xm:xm + 2] == OUTER_GHOST).any(): raise RuntimeError("coalescence packet passed through an outer ghost") value = f2[i][kids].mean() if new_valid[i, ky, kx]: replaced += MOMENTS[i] * fc_new[i, ky, kx] fc_new[i, ky, kx] = value new_valid[i, ky, kx] = True owner[i, ky, kx] = 2 coalesced += MOMENTS[i] * value writes[i, ky, kx] += 1 reads[i][kids] += 1 return replaced, coalesced, writes, reads def _leaf_totals(coarse_f, fine_f, maps: Maps) -> np.ndarray: mc = coarse_f[:, maps.coarse_active] mf = fine_f[:, maps.fine_active] return MOMENTS.T @ mc.sum(axis=1) + FINE_VOLUME * (MOMENTS.T @ mf.sum(axis=1)) def _moments_of_difference(after, before, mask) -> np.ndarray: return MOMENTS.T @ (after[:, mask] - before[:, mask]).sum(axis=1) def advance_coarse_once(spec: Spec, maps: Maps, state: State): n, nf = spec.n_coarse, spec.n_fine if state.phase != "arrival_f": raise ValueError("state.phase must be 'arrival_f'") tick = state.tick if isinstance(tick, bool) or not isinstance(tick, (int, np.integer)) or tick < 0 or tick % 2: raise ValueError("state.tick must be a non-negative even integer (synchronised phase)") tick = int(tick) if state.coarse_f.shape != (NQ, n, n) or state.fine_f.shape != (NQ, nf, nf): raise ValueError("state arrays have the wrong shape") fc = np.array(state.coarse_f, dtype=np.float64) ff = np.array(state.fine_f, dtype=np.float64) if not (np.isfinite(fc[:, maps.coarse_active]).all() and np.isfinite(ff[:, maps.fine_active]).all()): raise ValueError("active populations must be finite") fc[:, ~maps.coarse_active] = np.nan # invalid input entries are never trusted ff[:, ~maps.fine_active] = np.nan coarse_valid = np.broadcast_to(maps.coarse_active, (NQ, n, n)).copy() fine_valid = np.broadcast_to(maps.fine_active, (NQ, nf, nf)).copy() leaf_before = _leaf_totals(fc, ff, maps) count_c = np.zeros((n, n), dtype=np.int64) count_f = np.zeros((nf, nf), dtype=np.int64) explosion_writes = np.zeros((nf, nf), dtype=np.int64) # 1-2: collisions at t gc = _collide(spec, fc, coarse_valid, spec.tau_coarse, maps.coarse_active, count_c) gf = _collide(spec, ff, fine_valid, spec.tau_fine, maps.fine_active, count_f) coarse_collision = _moments_of_difference(gc, fc, maps.coarse_active) fine_collision = FINE_VOLUME * _moments_of_difference(gf, ff, maps.fine_active) # 3: explosion, once per coarse step _explode(gc, coarse_valid, gf, fine_valid, maps, explosion_writes) # 4: hop 1 f1, valid1, in1, out1, src1 = _fine_hop(gf, fine_valid, maps) # 5: mid-step fine collision, active only; outer ghosts poisoned g1 = _collide(spec, f1, valid1, spec.tau_fine, maps.fine_active, count_f) fine_collision += FINE_VOLUME * _moments_of_difference(g1, f1, maps.fine_active) valid1 = valid1.copy() g1[:, maps.fine_outer_ghost] = np.nan valid1[:, maps.fine_outer_ghost] = False # 6: hop 2 f2, hop2_valid, in2, out2, src2 = _fine_hop(g1, valid1, maps) # 7: coarse stream streamed = _stream_periodic(gc) streamed_valid = np.stack([np.roll(coarse_valid[i], (CY[i], CX[i]), axis=(0, 1)) for i in range(NQ)]) to_covered = np.zeros(3) for i in range(NQ): to_covered += MOMENTS[i] * streamed[i][maps.coarse_covered & streamed_valid[i]].sum() fc_new = streamed.copy() new_valid = streamed_valid & maps.coarse_active[None, :, :] fc_new[~new_valid] = np.nan owner = np.zeros((NQ, n, n), dtype=np.int64) owner[new_valid] = 1 # 8: coalescence of incoming directions from the fine region replaced, coalesced, coalesce_writes, coalesce_reads = _coalesce( spec, maps, f2, hop2_valid, fc_new, new_valid, owner) if not new_valid[:, maps.coarse_active].all() or not np.isfinite(fc_new[:, maps.coarse_active]).all(): raise RuntimeError("coarse incoming population without a valid owner") if not hop2_valid[:, maps.fine_active].all() or not np.isfinite(f2[:, maps.fine_active]).all(): raise RuntimeError("fine active population received an invalid value") ff_new = np.full((NQ, nf, nf), np.nan) ff_new[:, maps.fine_active] = f2[:, maps.fine_active] leaf_after = _leaf_totals(fc_new, ff_new, maps) fine_inflow, fine_outflow = in1 + in2, out1 + out2 interface = (coalesced - to_covered - replaced) + (fine_inflow - fine_outflow) budget = { "coarse_collision": coarse_collision, "fine_collision": fine_collision, "coarse_to_covered": to_covered, "coarse_replaced": replaced, "coalesced": coalesced, "fine_inflow": fine_inflow, "fine_outflow": fine_outflow, "interface_residual": interface, # Self-consistency of this file's accounting only; defined using interface_residual. "bookkeeping_check": (leaf_after - leaf_before) - (coarse_collision + fine_collision + interface), } corner_packets = {} for link in maps.corner_links: kx, ky = link.target_xy y0, x0 = _children_start(spec, ky), _children_start(spec, kx) kids = [(y, x) for y in (y0, y0 + 1) for x in (x0, x0 + 1)] corner_packets[link.key] = { "direction": link.i, "source_coarse_xy": link.source_xy, "target_coarse_xy": link.target_xy, "children_fine_yx": kids, "children_centre_xy": [(float(maps.fine_centre[x]), float(maps.fine_centre[y])) for y, x in kids], "packets": [float(f2[link.i, y, x]) for y, x in kids], "weights": [0.25] * 4, "coalesced": float(fc_new[link.i, ky, kx]), } diagnostics = { "api_version": API_VERSION, "collision": spec.collision, "tick_before": tick, "tick_after": tick + 2, "collision_count_coarse": count_c, "collision_count_fine": count_f, "explosion_writes": explosion_writes, "coarse_incoming_owner": owner, # 0 invalid (covered), 1 coarse stream, 2 coalescence "coalesce_writes": coalesce_writes, "coalesce_reads": coalesce_reads, "fine_hop_sources": {"hop1": src1, "hop2": src2}, # Pre-cleanup hop-2 validity, including valid inner ghosts. The returned # fine_f is valid exactly on maps.fine_active and NaN elsewhere. "hop2_valid": hop2_valid, "coarse_valid_after": new_valid, "leaf_before": leaf_before, # (mass, momentum_x, momentum_y) "leaf_after": leaf_after, "budget": budget, "corner_packets": corner_packets, # 8 entries keyed "_q" } new_state = State(coarse_f=fc_new, fine_f=ff_new, phase="arrival_f", tick=tick + 2) return new_state, diagnostics