#!/usr/bin/env python3 """Local-stress observable v1 — observation-only addition on unchanged CPUREF-0.3. Frozen spec: 18_local_stress_observable_spec_v1.md (Drive 1IgggnRfJrdvRtRo-07pmpUtILRjFmY2V) Thread: C0C78UFKGRM / 1791869055.115119 Unchanged from shear_diagnostic_v0.2: same 7x32 runs, same 22 hard checks, same resource bounds, reference file unmodified. Addition: at coarse step 32, from ARRIVAL (post-stream, pre-collision) populations, report scalar R and one signed horizontal-face profile. Diagnostic values only — no thresholds / mechanism claims. """ from __future__ import annotations import hashlib import importlib.util import os import sys import time from dataclasses import dataclass import numpy as np HERE = os.path.dirname(os.path.abspath(__file__)) REF_PATH = os.environ.get( "CPU_REFERENCE_PATH", os.path.join(HERE, "cpu_reference_v0.3.py") ) U0 = 1e-3 N_COARSE = 16 N_FINE_DOM = 32 PATCH_LO, PATCH_HI = 4, 12 TAU_C, TAU_F = 0.8, 1.1 N_STEPS = 32 FIT_LO, FIT_HI = 4, 32 CONS_TOL = 1e-12 TRANS_TOL = 1e-12 * U0 INIT_TOL = CONS_TOL T0_TOL = TRANS_TOL K_PHYS = 2.0 * np.pi / 16.0 CS2 = 1.0 / 3.0 NU = CS2 * (TAU_C - 0.5) # 0.1 coarse units RHO0 = 1.0 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) W = np.array([4 / 9] + [1 / 9] * 4 + [1 / 36] * 4, dtype=np.float64) NQ = 9 def _load_ref(): spec = importlib.util.spec_from_file_location("cpu_ref_v03", REF_PATH) mod = importlib.util.module_from_spec(spec) sys.modules[spec.name] = mod spec.loader.exec_module(mod) return mod def sha256_file(path: str) -> str: h = hashlib.sha256() with open(path, "rb") as f: for chunk in iter(lambda: f.read(1 << 16), b""): h.update(chunk) return h.hexdigest() def sinc(x): x = np.asarray(x, dtype=np.float64) out = np.empty_like(x, dtype=np.float64) small = np.abs(x) < 1e-14 out[small] = 1.0 xs = x[~small] out[~small] = np.sin(xs) / xs return float(out) if out.ndim == 0 else out def feq(rho, ux, uy): rho = np.asarray(rho, dtype=np.float64) ux = np.asarray(ux, dtype=np.float64) uy = np.asarray(uy, dtype=np.float64) cu = CX[:, None, None] * ux + CY[:, None, None] * uy usq = ux * ux + uy * uy return W[:, None, None] * rho * (1.0 + 3.0 * cu + 4.5 * cu * cu - 1.5 * usq) def srt_collide(f, tau, mask=None): g = f.copy() if mask is None: mask = np.ones(f.shape[1:], dtype=bool) fm = f[:, mask] rho = fm.sum(axis=0) ux = (CX[:, None] * fm).sum(axis=0) / rho uy = (CY[:, None] * fm).sum(axis=0) / rho rho_g = np.zeros(f.shape[1:]) ux_g = np.zeros(f.shape[1:]) uy_g = np.zeros(f.shape[1:]) rho_g[mask] = rho ux_g[mask] = ux uy_g[mask] = uy eq_full = feq(rho_g, ux_g, uy_g) g[:, mask] = fm - (fm - eq_full[:, mask]) / tau return g def stream_periodic(g): out = np.empty_like(g) for i in range(NQ): out[i] = np.roll(g[i], (int(CY[i]), int(CX[i])), axis=(0, 1)) return out def moments(f): rho = f.sum(axis=0) jx = (CX[:, None, None] * f).sum(axis=0) jy = (CY[:, None, None] * f).sum(axis=0) return rho, jx, jy def cell_avg_ux(y_centers, dx, phi): factor = float(sinc(K_PHYS * dx / 2.0)) return U0 * factor * np.sin(K_PHYS * y_centers + phi) def mode_template(phi): yc = np.arange(N_COARSE, dtype=np.float64) + 0.5 m1d = float(sinc(K_PHYS / 2.0)) * np.sin(K_PHYS * yc + phi) return np.broadcast_to(m1d[:, None], (N_COARSE, N_COARSE)).copy() def project_amp(ux, phi): m = mode_template(phi) return float(np.sum(ux * m) / np.sum(m * m)) def restrict_fine_to_coarse(rho_f, jx_f, jy_f): assert rho_f.shape == (N_FINE_DOM, N_FINE_DOM) rho = rho_f.reshape(N_COARSE, 2, N_COARSE, 2).mean(axis=(1, 3)) jx = jx_f.reshape(N_COARSE, 2, N_COARSE, 2).mean(axis=(1, 3)) jy = jy_f.reshape(N_COARSE, 2, N_COARSE, 2).mean(axis=(1, 3)) return rho, jx, jy, jx / rho, jy / rho def volume_avg_2x2(field_f): """2x2 volume-average of a fine 32^2 field onto 16^2.""" assert field_f.shape == (N_FINE_DOM, N_FINE_DOM) return field_f.reshape(N_COARSE, 2, N_COARSE, 2).mean(axis=(1, 3)) def sigma_xy_cell(f, tau): """Per-cell corrected stress from ARRIVAL populations. Π^neq_xy = Σ c_x c_y f − ρ u_x u_y σ_xy = −(1 − 1/(2τ)) Π^neq_xy No extra dx/dt factor ((dx/dt)^2 = 1). """ rho, jx, jy = moments(f) ux = jx / rho uy = jy / rho pi_neq = (CX[:, None, None] * CY[:, None, None] * f).sum(axis=0) - rho * ux * uy sigma = -(1.0 - 1.0 / (2.0 * tau)) * pi_neq return sigma, rho, ux, uy def project_a_u_P_sigma(u_field, sigma, phi, transpose=False): """Fourier projections over all 16^2 cells (spec §3). a_u = (2/256) Σ u · sin(k· + φ); P_σ = (2/256) Σ σ · cos(k· + φ) Non-transpose: u_x vs y; transpose: u_y vs x. """ centers = np.arange(N_COARSE, dtype=np.float64) + 0.5 if transpose: # u_y(x): template varies with x (columns) sin_t = np.sin(K_PHYS * centers[None, :] + phi) cos_t = np.cos(K_PHYS * centers[None, :] + phi) else: # u_x(y): template varies with y (rows) sin_t = np.sin(K_PHYS * centers[:, None] + phi) cos_t = np.cos(K_PHYS * centers[:, None] + phi) a_u = (2.0 / 256.0) * float(np.sum(u_field * sin_t)) P_s = (2.0 / 256.0) * float(np.sum(sigma * cos_t)) return a_u, P_s def profile_s(sigma, a_u, transpose=False): """Signed horizontal-face profile: mean over x∈[4,12), / (ρ0 ν k a_u). Transpose: no profile (returns None). """ if transpose: return None denom = RHO0 * NU * K_PHYS * a_u row_mean = sigma[:, PATCH_LO:PATCH_HI].mean(axis=1) # j=0..15 return row_mean / denom @dataclass class Series: name: str phi: float A: np.ndarray e_if: np.ndarray e_cb: np.ndarray e_if_patch: np.ndarray e_if_out: np.ndarray nonmodal: np.ndarray max_uy: np.ndarray max_drho: np.ndarray mass: np.ndarray momx: np.ndarray momy: np.ndarray pi_xy_mean: np.ndarray finite_ok: bool cons_ok: bool mass_drift: float = 0.0 momx_drift: float = 0.0 momy_drift: float = 0.0 notes: str = "" def init_uniform(n, dx, phi, transpose=False): centers = (np.arange(n, dtype=np.float64) + 0.5) * dx Y, X = np.meshgrid(centers, centers, indexing="ij") rho = np.ones((n, n), dtype=np.float64) if transpose: ux = np.zeros_like(rho) uy = cell_avg_ux(X, dx, phi) else: ux = cell_avg_ux(Y, dx, phi) uy = np.zeros_like(rho) return feq(rho, ux, uy) def advance_uniform(f, tau, steps): for _ in range(steps): f = stream_periodic(srt_collide(f, tau)) return f def observe_uniform(f, dx, phi, transpose=False): rho, jx, jy = moments(f) if dx < 1.0 - 1e-12: rho_c, jx_c, jy_c, ux, uy = restrict_fine_to_coarse(rho, jx, jy) else: rho_c, jx_c, jy_c = rho, jx, jy ux, uy = jx / rho, jy / rho if transpose: xc = np.arange(N_COARSE, dtype=np.float64) + 0.5 mx = float(sinc(K_PHYS / 2.0)) * np.sin(K_PHYS * xc + phi) mT = np.broadcast_to(mx[None, :], (N_COARSE, N_COARSE)).copy() amp = float(np.sum(uy * mT) / np.sum(mT * mT)) modal = amp * mT nonmodal = float(np.linalg.norm(uy - modal) / U0) max_cross = float(np.max(np.abs(ux)) / U0) else: amp = project_amp(ux, phi) m = mode_template(phi) modal = amp * m nonmodal = float(np.linalg.norm(ux - modal) / U0) max_cross = float(np.max(np.abs(uy)) / U0) return { "amp": amp, "ux": ux, "uy": uy, "rho": rho_c, "jx": jx_c, "jy": jy_c, "nonmodal": nonmodal, "max_cross": max_cross, "max_drho": float(np.max(np.abs(rho_c - 1.0))), "mass": float(rho_c.sum()), "momx": float(jx_c.sum()), "momy": float(jy_c.sum()), } def run_uniform(kind, phi, transpose=False): if kind == "B": n, dx, tau, sub = N_FINE_DOM, 0.5, TAU_F, 2 else: n, dx, tau, sub = N_COARSE, 1.0, TAU_C, 1 f = init_uniform(n, dx, phi, transpose=transpose) amps, nonmodal, max_cross, max_drho = [], [], [], [] mass, momx, momy = [], [], [] fields = [] finite_ok = True for tick in range(N_STEPS + 1): if not np.isfinite(f).all(): finite_ok = False obs = observe_uniform(f, dx, phi, transpose=transpose) amps.append(obs["amp"]) nonmodal.append(obs["nonmodal"]) max_cross.append(obs["max_cross"]) max_drho.append(obs["max_drho"]) mass.append(obs["mass"]) momx.append(obs["momx"]) momy.append(obs["momy"]) fields.append( (obs["ux"].copy(), obs["uy"].copy(), obs["rho"].copy(), obs["jx"].copy(), obs["jy"].copy()) ) if tick < N_STEPS: f = advance_uniform(f, tau, sub) # After N_STEPS advances, f is ARRIVAL at coarse step 32 (post-stream). arrival_name = ( f"uniform_{kind}_f_after_{N_STEPS * sub}_stream_steps" f"_(=coarse_step_{N_STEPS}_arrival; collide-then-stream loop)" ) mass = np.asarray(mass) momx = np.asarray(momx) momy = np.asarray(momy) mass_drift = float(np.max(np.abs(mass - mass[0]))) momx_drift = float(np.max(np.abs(momx - momx[0]))) momy_drift = float(np.max(np.abs(momy - momy[0]))) tol_abs = CONS_TOL * abs(mass[0]) cons_ok = ( mass_drift <= tol_abs and momx_drift <= tol_abs and momy_drift <= tol_abs ) ser = Series( name=f"{kind}_phi{phi:.4f}{'_T' if transpose else ''}", phi=phi, A=np.asarray(amps), e_if=np.full(N_STEPS + 1, np.nan), e_cb=np.full(N_STEPS + 1, np.nan), e_if_patch=np.full(N_STEPS + 1, np.nan), e_if_out=np.full(N_STEPS + 1, np.nan), nonmodal=np.asarray(nonmodal), max_uy=np.asarray(max_cross), max_drho=np.asarray(max_drho), mass=mass, momx=momx, momy=momy, pi_xy_mean=np.full(N_STEPS + 1, np.nan), finite_ok=finite_ok, cons_ok=bool(cons_ok), mass_drift=mass_drift, momx_drift=momx_drift, momy_drift=momy_drift, ) return ser, fields, f, tau, arrival_name def init_composite(ref, spec, maps, phi, transpose=False): n, nf = spec.n_coarse, spec.n_fine coarse = np.full((NQ, n, n), np.nan) fine = np.full((NQ, nf, nf), np.nan) yc = np.arange(n, dtype=np.float64) + 0.5 xc = np.arange(n, dtype=np.float64) + 0.5 Yc, Xc = np.meshgrid(yc, xc, indexing="ij") if transpose: ux_c = np.zeros((n, n)) uy_c = cell_avg_ux(Xc, 1.0, phi) else: ux_c = cell_avg_ux(Yc, 1.0, phi) uy_c = np.zeros((n, n)) coarse[:, :, :] = feq(np.ones((n, n)), ux_c, uy_c) coarse[:, maps.coarse_covered] = np.nan fy = maps.fine_centre fx = maps.fine_centre Yf, Xf = np.meshgrid(fy, fx, indexing="ij") if transpose: ux_f = np.zeros((nf, nf)) uy_f = cell_avg_ux(Xf, 0.5, phi) else: ux_f = cell_avg_ux(Yf, 0.5, phi) uy_f = np.zeros((nf, nf)) eq_f = feq(np.ones((nf, nf)), ux_f, uy_f) fine[:, maps.fine_active] = eq_f[:, maps.fine_active] return ref.State(coarse_f=coarse, fine_f=fine, phase="arrival_f", tick=0) def observe_composite(ref, maps, state, phi, transpose=False): fc, ff = state.coarse_f, state.fine_f n = N_COARSE rho_c = np.full((n, n), np.nan) jx_c = np.full((n, n), np.nan) jy_c = np.full((n, n), np.nan) for y in range(n): for x in range(n): if maps.coarse_active[y, x]: sl = fc[:, y, x] rho_c[y, x] = sl.sum() jx_c[y, x] = (CX * sl).sum() jy_c[y, x] = (CY * sl).sum() for ky in range(PATCH_LO, PATCH_HI): for kx in range(PATCH_LO, PATCH_HI): y0 = spec_children_start(ky) x0 = spec_children_start(kx) kids = [] for dy in (0, 1): for dx in (0, 1): sl = ff[:, y0 + dy, x0 + dx] kids.append((sl.sum(), (CX * sl).sum(), (CY * sl).sum())) rho_c[ky, kx] = np.mean([k[0] for k in kids]) jx_c[ky, kx] = np.mean([k[1] for k in kids]) jy_c[ky, kx] = np.mean([k[2] for k in kids]) ux = jx_c / rho_c uy = jy_c / rho_c if transpose: xc = np.arange(n, dtype=np.float64) + 0.5 mx = float(sinc(K_PHYS / 2.0)) * np.sin(K_PHYS * xc + phi) mT = np.broadcast_to(mx[None, :], (n, n)).copy() amp = float(np.sum(uy * mT) / np.sum(mT * mT)) modal = amp * mT nonmodal = float(np.linalg.norm(uy - modal) / U0) max_cross = float(np.max(np.abs(ux)) / U0) else: amp = project_amp(ux, phi) m = mode_template(phi) modal = amp * m nonmodal = float(np.linalg.norm(ux - modal) / U0) max_cross = float(np.max(np.abs(uy)) / U0) leaf = ref._leaf_totals(fc, ff, maps) return { "amp": amp, "ux": ux, "uy": uy, "rho": rho_c, "jx": jx_c, "jy": jy_c, "nonmodal": nonmodal, "max_cross": max_cross, "max_drho": float(np.max(np.abs(rho_c - 1.0))), "mass": float(leaf[0]), "momx": float(leaf[1]), "momy": float(leaf[2]), "finite_active": bool( np.isfinite(fc[:, maps.coarse_active]).all() and np.isfinite(ff[:, maps.fine_active]).all() ), } def spec_children_start(k): return 4 + 2 * (k - PATCH_LO) def sigma_composite_16(maps, state): """Build 16^2 corrected σ from arrival_f composite state. Patch cells: 2x2 volume-average of fine σ (τ_f). Outside: coarse σ (τ_c). Never uses coarse underlay under the patch. """ fc, ff = state.coarse_f, state.fine_f n = N_COARSE sig = np.full((n, n), np.nan) # outside / active coarse for y in range(n): for x in range(n): if maps.coarse_active[y, x]: f1 = fc[:, y : y + 1, x : x + 1] s1, _, _, _ = sigma_xy_cell(f1, TAU_C) sig[y, x] = float(s1[0, 0]) # patch from fine for ky in range(PATCH_LO, PATCH_HI): for kx in range(PATCH_LO, PATCH_HI): y0 = spec_children_start(ky) x0 = spec_children_start(kx) kids = [] for dy in (0, 1): for dx in (0, 1): f1 = ff[:, y0 + dy : y0 + dy + 1, x0 + dx : x0 + dx + 1] s1, _, _, _ = sigma_xy_cell(f1, TAU_F) kids.append(float(s1[0, 0])) sig[ky, kx] = float(np.mean(kids)) return sig def run_composite(ref, phi, transpose=False): spec = ref.make_spec(collision="srt") assert abs(spec.tau_coarse - TAU_C) < 1e-15 and abs(spec.tau_fine - TAU_F) < 1e-15 maps = ref.build_maps(spec) st = init_composite(ref, spec, maps, phi, transpose=transpose) yc = np.arange(N_COARSE) + 0.5 xc = np.arange(N_COARSE) + 0.5 init_mismatch = 0.0 for ky in range(PATCH_LO, PATCH_HI): for kx in range(PATCH_LO, PATCH_HI): y0 = spec_children_start(ky) x0 = spec_children_start(kx) rhos, jxs, jys = [], [], [] for dy in (0, 1): for dx in (0, 1): sl = st.fine_f[:, y0 + dy, x0 + dx] rhos.append(sl.sum()) jxs.append((CX * sl).sum()) jys.append((CY * sl).sum()) rho_r, jx_r, jy_r = np.mean(rhos), np.mean(jxs), np.mean(jys) if transpose: ux, uy = 0.0, float(cell_avg_ux(xc[kx], 1.0, phi)) else: ux, uy = float(cell_avg_ux(yc[ky], 1.0, phi)), 0.0 init_mismatch = max( init_mismatch, abs(rho_r - 1.0), abs(jx_r - ux), abs(jy_r - uy) ) amps, nonmodal, max_cross, max_drho = [], [], [], [] mass, momx, momy = [], [], [] fields = [] finite_ok = True for tick in range(N_STEPS + 1): obs = observe_composite(ref, maps, st, phi, transpose=transpose) if not obs["finite_active"]: finite_ok = False amps.append(obs["amp"]) nonmodal.append(obs["nonmodal"]) max_cross.append(obs["max_cross"]) max_drho.append(obs["max_drho"]) mass.append(obs["mass"]) momx.append(obs["momx"]) momy.append(obs["momy"]) fields.append( (obs["ux"].copy(), obs["uy"].copy(), obs["rho"].copy(), obs["jx"].copy(), obs["jy"].copy()) ) if tick < N_STEPS: st, _ = ref.advance_coarse_once(spec, maps, st) # After 32 advances: tick=64, phase=arrival_f — post-stream, pre-collision. arrival_name = ( f"State.coarse_f + State.fine_f at phase={st.phase!r} tick={st.tick} " f"(after {N_STEPS} advance_coarse_once; arrival_f = post-stream pre-collision)" ) mass = np.asarray(mass) momx = np.asarray(momx) momy = np.asarray(momy) mass_drift = float(np.max(np.abs(mass - mass[0]))) momx_drift = float(np.max(np.abs(momx - momx[0]))) momy_drift = float(np.max(np.abs(momy - momy[0]))) tol_abs = CONS_TOL * max(abs(mass[0]), 1.0) cons_ok = ( mass_drift <= tol_abs and momx_drift <= tol_abs and momy_drift <= tol_abs ) ser = Series( name=f"A_phi{phi:.4f}{'_T' if transpose else ''}", phi=phi, A=np.asarray(amps), e_if=np.full(N_STEPS + 1, np.nan), e_cb=np.full(N_STEPS + 1, np.nan), e_if_patch=np.full(N_STEPS + 1, np.nan), e_if_out=np.full(N_STEPS + 1, np.nan), nonmodal=np.asarray(nonmodal), max_uy=np.asarray(max_cross), max_drho=np.asarray(max_drho), mass=mass, momx=momx, momy=momy, pi_xy_mean=np.full(N_STEPS + 1, np.nan), finite_ok=finite_ok, cons_ok=bool(cons_ok), mass_drift=mass_drift, momx_drift=momx_drift, momy_drift=momy_drift, notes=f"init_rho_j_mismatch_vs_coarse_formula={init_mismatch:.3e}", ) return ser, fields, st, maps, init_mismatch, arrival_name def fit_lambda(amps): t = np.arange(FIT_LO, FIT_HI + 1, dtype=np.float64) y = np.log(np.abs(amps[FIT_LO : FIT_HI + 1])) n = len(t) tbar, ybar = t.mean(), y.mean() sxx = np.sum((t - tbar) ** 2) slope = np.sum((t - tbar) * (y - ybar)) / sxx intercept = ybar - slope * tbar pred = intercept + slope * t resid = y - pred dof = max(n - 2, 1) s_err = float(np.sqrt(np.sum(resid**2) / dof / sxx)) ss_tot = np.sum((y - ybar) ** 2) r2 = float(1.0 - np.sum(resid**2) / ss_tot) if ss_tot > 0 else 1.0 return float(-slope), s_err, r2 def field_l2(a, b): return float(np.linalg.norm(a - b)) def stress_from_uniform_arrival(f, tau, phi, transpose=False): """σ on 16^2 from uniform arrival f; also ux/uy restricted for a_u.""" sig, rho, ux, uy = sigma_xy_cell(f, tau) if f.shape[1] == N_FINE_DOM: sig16 = volume_avg_2x2(sig) rho_f, jx_f, jy_f = moments(f) _, _, _, ux16, uy16 = restrict_fine_to_coarse(rho_f, jx_f, jy_f) else: sig16 = sig ux16, uy16 = ux, uy u_proj = uy16 if transpose else ux16 a_u, P_s = project_a_u_P_sigma(u_proj, sig16, phi, transpose=transpose) R = P_s / (RHO0 * NU * K_PHYS * a_u) s_prof = profile_s(sig16, a_u, transpose=transpose) return { "sigma16": sig16, "ux16": ux16, "uy16": uy16, "a_u": a_u, "P_sigma": P_s, "R": R, "s": s_prof, "finite": bool(np.isfinite(sig16).all() and np.isfinite(a_u) and np.isfinite(P_s) and np.isfinite(R) and (s_prof is None or np.isfinite(s_prof).all())), } def stress_from_composite_arrival(maps, state, phi, transpose=False): sig16 = sigma_composite_16(maps, state) # u from observe path (same restriction rule) obs = None # rebuild ux/uy on 16^2 from arrival populations (owned cells only) n = N_COARSE rho_c = np.full((n, n), np.nan) jx_c = np.full((n, n), np.nan) jy_c = np.full((n, n), np.nan) fc, ff = state.coarse_f, state.fine_f for y in range(n): for x in range(n): if maps.coarse_active[y, x]: sl = fc[:, y, x] rho_c[y, x] = sl.sum() jx_c[y, x] = (CX * sl).sum() jy_c[y, x] = (CY * sl).sum() for ky in range(PATCH_LO, PATCH_HI): for kx in range(PATCH_LO, PATCH_HI): y0 = spec_children_start(ky) x0 = spec_children_start(kx) kids = [] for dy in (0, 1): for dx in (0, 1): sl = ff[:, y0 + dy, x0 + dx] kids.append((sl.sum(), (CX * sl).sum(), (CY * sl).sum())) rho_c[ky, kx] = np.mean([k[0] for k in kids]) jx_c[ky, kx] = np.mean([k[1] for k in kids]) jy_c[ky, kx] = np.mean([k[2] for k in kids]) ux16 = jx_c / rho_c uy16 = jy_c / rho_c u_proj = uy16 if transpose else ux16 a_u, P_s = project_a_u_P_sigma(u_proj, sig16, phi, transpose=transpose) R = P_s / (RHO0 * NU * K_PHYS * a_u) s_prof = profile_s(sig16, a_u, transpose=transpose) return { "sigma16": sig16, "ux16": ux16, "uy16": uy16, "a_u": a_u, "P_sigma": P_s, "R": R, "s": s_prof, "finite": bool(np.isfinite(sig16).all() and np.isfinite(a_u) and np.isfinite(P_s) and np.isfinite(R) and (s_prof is None or np.isfinite(s_prof).all())), } def main(): t0 = time.time() print("=== local_stress_observable_v1 against CPUREF-0.3 ===") print(f"REF_PATH={REF_PATH}") ref_sha = sha256_file(REF_PATH) print(f"REF_SHA256={ref_sha}") expected_ref = "bba2a06a9f6517b32079ffff15e4060d8c3b7ed35f16ca134e1877226c9e4e1e" print(f"REF_SHA_MATCH={ref_sha == expected_ref}") ref = _load_ref() print(f"API_VERSION={getattr(ref, 'API_VERSION', '?')}") assert getattr(ref, "API_VERSION", None) == "CPUREF-0.3" print(f"U0={U0} tau_c={TAU_C} tau_f={TAU_F} steps={N_STEPS} nu={NU} k={K_PHYS}") print(f"nu*k^2={NU * K_PHYS**2:.8f}") print("ARRIVAL_STATE_POLICY: read CPUREF-0.3 State.coarse_f/fine_f at phase='arrival_f'") print(" after N advance_coarse_once calls (tick=2N). That array IS post-stream pre-collision.") print(" Uniform B/C use local collide-then-stream; f after 2N (B) or N (C) streams is arrival.") print(" If arrival were unreachable without changing the reference, this script would STOP.") print("STRESS: Pi_neq=sum(cx*cy*f)-rho*ux*uy; sigma=-(1-1/(2*tau))*Pi_neq; 2x2 vol-avg of sigma.") print(" No extra dx/dt factor. a_u=(2/256)sum u sin; P_sigma=(2/256)sum sigma cos; own a_u.") print(" Profile s(j)=mean_x[4,12)(sigma)/ (rho0*nu*k*a_u). Transposed: R only, no profile.") print() phis = [0.0, 0.5 * np.pi] results = {} fields = {} init_mm = {} arrivals = {} stress = {} for phi in phis: tag = f"phi{phi:.4f}" print(f"-- running C (uniform-coarse) {tag}") ser_c, fld_c, f_c, tau_c, an_c = run_uniform("C", phi) results[f"C_{tag}"] = ser_c fields[f"C_{tag}"] = fld_c arrivals[f"C_{tag}"] = an_c stress[f"C_{tag}"] = stress_from_uniform_arrival(f_c, tau_c, phi) print(f" ARRIVAL_ARRAY: {an_c}") print(f"-- running B (uniform-fine) {tag}") ser_b, fld_b, f_b, tau_b, an_b = run_uniform("B", phi) results[f"B_{tag}"] = ser_b fields[f"B_{tag}"] = fld_b arrivals[f"B_{tag}"] = an_b stress[f"B_{tag}"] = stress_from_uniform_arrival(f_b, tau_b, phi) print(f" ARRIVAL_ARRAY: {an_b}") print(f"-- running A (composite CPUREF) {tag}") ser_a, fld_a, st_a, maps_a, mism, an_a = run_composite(ref, phi) init_mm[tag] = mism results[f"A_{tag}"] = ser_a fields[f"A_{tag}"] = fld_a arrivals[f"A_{tag}"] = an_a stress[f"A_{tag}"] = stress_from_composite_arrival(maps_a, st_a, phi) print(f" ARRIVAL_ARRAY: {an_a}") print(f" state.phase={st_a.phase} state.tick={st_a.tick}") patch = np.zeros((N_COARSE, N_COARSE), dtype=bool) patch[PATCH_LO:PATCH_HI, PATCH_LO:PATCH_HI] = True out = ~patch for t in range(N_STEPS + 1): du = fld_a[t][0] - fld_b[t][0] ser_a.e_if[t] = float(np.linalg.norm(du)) ser_a.e_if_patch[t] = float(np.linalg.norm(du[patch])) ser_a.e_if_out[t] = float(np.linalg.norm(du[out])) ser_a.e_cb[t] = field_l2(fld_c[t][0], fld_b[t][0]) phi_t = 0.5 * np.pi print(f"-- running A transpose phi={phi_t}") ser_at, fld_at, st_at, maps_at, mism_t, an_at = run_composite(ref, phi_t, transpose=True) init_mm["A_T"] = mism_t results["A_T_phi1.5708"] = ser_at fields["A_T_phi1.5708"] = fld_at arrivals["A_T_phi1.5708"] = an_at stress["A_T_phi1.5708"] = stress_from_composite_arrival( maps_at, st_at, phi_t, transpose=True ) print(f" ARRIVAL_ARRAY: {an_at}") ser_a_ref = results["A_phi1.5708"] fld_a_ref = fields["A_phi1.5708"] trans_err = 0.0 for t in range(N_STEPS + 1): ux, uy, rho, jx, jy = fld_a_ref[t] ux_t, uy_t, rho_t, jx_t, jy_t = fld_at[t] err = max( float(np.max(np.abs(ux_t - uy.T))), float(np.max(np.abs(uy_t - ux.T))), float(np.max(np.abs(rho_t - rho.T))), ) trans_err = max(trans_err, err) transpose_ok = trans_err <= TRANS_TOL print("\n=== HARD CHECKS (unchanged v0.2 set) ===") hard = {} hard_keys = [] for phi in phis: tag = f"phi{phi:.4f}" hard_keys.extend([f"A_{tag}", f"B_{tag}", f"C_{tag}"]) hard_keys.append("A_T_phi1.5708") for key in hard_keys: s = results[key] hard[f"finite_{key}"] = s.finite_ok hard[f"cons_{key}"] = s.cons_ok tol_abs = CONS_TOL * max(abs(s.mass[0]), 1.0) print( f" finite[{key}]={s.finite_ok} cons={s.cons_ok} " f"mass_drift={s.mass_drift:.3e} momx_drift={s.momx_drift:.3e} " f"momy_drift={s.momy_drift:.3e} tol_abs={tol_abs:.3e} {s.notes}" ) hard["transpose_ok"] = transpose_ok print(f" transpose_ok={transpose_ok} max_err={trans_err:.3e} (tol={TRANS_TOL:.3e})") for phi in phis: tag = f"phi{phi:.4f}" ux_a = fields[f"A_{tag}"][0][0] ux_b = fields[f"B_{tag}"][0][0] ux_c = fields[f"C_{tag}"][0][0] patch = np.zeros((16, 16), dtype=bool) patch[PATCH_LO:PATCH_HI, PATCH_LO:PATCH_HI] = True d_ab_p = float(np.max(np.abs(ux_a[patch] - ux_b[patch]))) d_ac_o = float(np.max(np.abs(ux_a[~patch] - ux_c[~patch]))) hard[f"t0_AB_patch_ok_{tag}"] = bool(d_ab_p <= T0_TOL) hard[f"t0_AC_out_ok_{tag}"] = bool(d_ac_o <= T0_TOL) hard[f"init_mismatch_ok_{tag}"] = bool(init_mm[tag] <= INIT_TOL) print( f" t0 {tag}: AB_patch={d_ab_p:.3e} ok={hard[f't0_AB_patch_ok_{tag}']} " f"AC_out={d_ac_o:.3e} ok={hard[f't0_AC_out_ok_{tag}']} " f"init_mm={init_mm[tag]:.3e} ok={hard[f'init_mismatch_ok_{tag}']}" ) hard["init_mismatch_ok_A_T_phi1.5708"] = bool(init_mm["A_T"] <= INIT_TOL) print(f" init_mismatch[A_T]={init_mm['A_T']:.3e} ok={hard['init_mismatch_ok_A_T_phi1.5708']}") # New finite checks for stress arrays print("\n=== STRESS FINITE CHECKS (addition) ===") for key, stv in stress.items(): ok = stv["finite"] hard[f"stress_finite_{key}"] = ok print( f" stress_finite[{key}]={ok} R={stv['R']:.8f} a_u={stv['a_u']:.6e} " f"P_sigma={stv['P_sigma']:.6e}" ) _bool_keys = sorted(k for k, v in hard.items() if isinstance(v, bool)) # Report both: original-22-style (without stress_finite) and all including stress v02_bool = [k for k in _bool_keys if not k.startswith("stress_finite_")] print(f" N_BOOLEAN_HARD_CHECKS_V02={len(v02_bool)}: " + ",".join(v02_bool)) print(f" N_BOOLEAN_HARD_CHECKS_WITH_STRESS={len(_bool_keys)}") print("\n=== LOCAL STRESS OBSERVABLE at coarse step 32 ===") print("FORMULA: R = P_sigma / (rho0 * nu * k * a_u); a_u from SAME run/tick/arrival") print("WORDING: reported diagnostics only; phi probes phase structure only; no mechanism claim") table_rows = [] for phi in phis: tag = f"phi{phi:.4f}" sa, sb, sc = stress[f"A_{tag}"], stress[f"B_{tag}"], stress[f"C_{tag}"] ra, rb, rc = sa["R"], sb["R"], sc["R"] print(f"\n-- {tag} --") print(f" R_A={ra:.10f} R_B={rb:.10f} R_C={rc:.10f}") print(f" R_A/R_B={ra/rb:.10f} R_A/R_C={ra/rc:.10f}") print(f" a_u A/B/C: {sa['a_u']:.8e} {sb['a_u']:.8e} {sc['a_u']:.8e}") print(f" P_sigma A/B/C: {sa['P_sigma']:.8e} {sb['P_sigma']:.8e} {sc['P_sigma']:.8e}") # profiles sA, sB, sC = sa["s"], sb["s"], sc["s"] dAB = sA - sB dAC = sA - sC face = {3, 4, 11, 12} print(" s_A(j): " + " ".join(f"{v:.6e}" for v in sA)) print(" s_B(j): " + " ".join(f"{v:.6e}" for v in sB)) print(" s_C(j): " + " ".join(f"{v:.6e}" for v in sC)) print(" s_A-s_B: " + " ".join(f"{v:.6e}" for v in dAB)) print(" s_A-s_C: " + " ".join(f"{v:.6e}" for v in dAC)) print( " FACE_ROWS j=3,4,11,12 flagged: " + " ".join( f"j{j}:A={sA[j]:.5e},B={sB[j]:.5e},C={sC[j]:.5e}," f"A-B={dAB[j]:.5e},A-C={dAC[j]:.5e}" for j in (3, 4, 11, 12) ) ) table_rows.append( { "phi": phi, "tag": tag, "R_A": ra, "R_B": rb, "R_C": rc, "R_A/R_B": ra / rb, "R_A/R_C": ra / rc, "s_A": sA, "s_B": sB, "s_C": sC, "dAB": dAB, "dAC": dAC, } ) stT = stress["A_T_phi1.5708"] print(f"\n-- A_T phi=1.5708 (R only, no profile) --") print(f" R_A_T={stT['R']:.10f} a_u={stT['a_u']:.8e} P_sigma={stT['P_sigma']:.8e}") print(f" profile={'None (transpose)'}") print("\n=== DECAY FITS (informational; same as v0.2) ===") lam_analytic = NU * K_PHYS**2 print(f" analytic lambda = {lam_analytic:.8f}") for phi in phis: tag = f"phi{phi:.4f}" for kind in ("A", "B", "C"): s = results[f"{kind}_{tag}"] lam, se, r2 = fit_lambda(s.A) print( f" {kind} {tag}: lambda={lam:.8f} stderr={se:.3e} R2={r2:.6f} " f"A0={s.A[0]:.6e} A32={s.A[-1]:.6e}" ) all_hard_pass = all(v for k, v in hard.items() if isinstance(v, bool)) v02_pass = all(hard[k] for k in v02_bool) print("\n=== NUMERIC SUMMARY ===") print(f"ALL_HARD_CHECKS_PASS_V02={v02_pass}") print(f"ALL_HARD_CHECKS_PASS_WITH_STRESS={all_hard_pass}") print(f"runtime_sec={time.time()-t0:.2f}") print("SUMMARY_LINES_BEGIN") for row in table_rows: print( f"R {row['tag']} A={row['R_A']:.12f} B={row['R_B']:.12f} C={row['R_C']:.12f} " f"A/B={row['R_A/R_B']:.12f} A/C={row['R_A/R_C']:.12f}" ) print( f"PROFILE_A {row['tag']} " + " ".join(f"{v:.8e}" for v in row["s_A"]) ) print( f"PROFILE_B {row['tag']} " + " ".join(f"{v:.8e}" for v in row["s_B"]) ) print( f"PROFILE_C {row['tag']} " + " ".join(f"{v:.8e}" for v in row["s_C"]) ) print( f"PROFILE_A-B {row['tag']} " + " ".join(f"{v:.8e}" for v in row["dAB"]) ) print( f"PROFILE_A-C {row['tag']} " + " ".join(f"{v:.8e}" for v in row["dAC"]) ) print(f"R A_T_phi1.5708 R={stT['R']:.12f}") print(f"TRANSPOSE err={trans_err:.6e} ok={transpose_ok}") print(f"REF_SHA256={ref_sha}") print("SUMMARY_LINES_END") return 0 if all_hard_pass else 1 if __name__ == "__main__": sys.exit(main())