"""Fixed four-case shear-wave contracts. Default: N128 (U128, U256, constant R128, projected R128). Opt-in --diagnostic scaled_shear_n256: N256 (U256, U512, constant R256, projected R256), same physical rectangle, t* schedule, nu = U N / 100, eps(N), limits and floors, plus a descriptive comparison with the hash-pinned N128 receipts. Shared provenance, build, workload and sample-time checks are reused from assess_projected_pairs (same cases, source pins and geometry); only the Taylor-Green-specific checks are replaced by shear-wave metadata and physics. """ import argparse import hashlib import json import math from pathlib import Path import assess_projected_pairs as tg import shear_wave as sw from run_case import SCALED_DIAGNOSTIC, SCALED_SHEAR, SHEAR_WAVE_SHA256 # Audited de5b0cc N128 receipts (evidence commit cba6bca, shear-wave-de5b0cc zip). REFERENCE_REVISION = "de5b0cc080794d0ce44d37f845aa8e8dbf8c2016" REFERENCE_RECEIPTS = { "uniform128": "d4a60fb806d04bfa8098a862cceba51e00b49979a6a250fef17a5fc8e3ea3255", "uniform256": "e0b58e734724be5f82ee5d6df84395e3181b4e96e4246dd5a574ea23a8d12386", "constant128": "c70d7cd14b1257a01cc49f8edfcc7685d430e5301e2f2d60ed426936f8b96c51", "projected128": "980161458b9463af09a8e3178063fea0f4bbeb465329e1d3becdb0f224537b54", } ROLES = ("uniform_root", "uniform_fine", "constant", "projected_linear") SHARED = ("complete_matrix", "no_extra_cases", "no_duplicate_cases", "finite_receipts", "same_source_and_harness", "clean_a135252_numerical_source", "same_recorded_runtime", "same_explicit_device", "same_early_sampling") PER_CASE = ("complete_times", "scales", "actual_builds", "reference", "runtime_source", "patch", "workload") METADATA_ULPS = 4 def close_ulps(recorded, expected, ulps=METADATA_ULPS): """Portable check for recomputed float metadata only (e.g. eps = |k|^2). The recorded value comes from another runtime/libm, so exact equality can fail by one ULP (observed: 0.012047856934923534 Horsea vs ...532 here). A few ULPs is far below any meaningful change; hashes, case identity and scientific thresholds stay exact. """ return (isinstance(recorded, float) and math.isfinite(recorded) and abs(recorded - expected) <= ulps * math.ulp(max(abs(recorded), abs(expected)))) def metadata_ok(record, n): return (record.get("flow") == "shear_wave" and record.get("mode") == list(sw.MODE) and record.get("polarization") == sw.E.tolist() and record.get("angle_deg") == sw.ANGLE_DEG and record.get("phase") == sw.PHI and close_ulps(record.get("eps"), sw.eps(n)) and record.get("numerics") == tg.NUMERICS and record.get("initialization") == sw.INITIALIZATION and record.get("limits") == sw.LIMITS and record.get("early_pressure") == dict(enabled=False, rows=[], sampled_max_pressure_l2=None) and (record.get("source") or {}).get("shear_wave_sha256") == SHEAR_WAVE_SHA256) def cases_for(scaled): factor = 2 if scaled else 1 return tuple((re, n * factor, depth, scheme) for re, n, depth, scheme in tg.CASES) def assess(records, expected_revision=None, *, scaled=False): if not isinstance(records, list) or not all(isinstance(r, dict) for r in records): raise ValueError("records must be a list of receipt objects") # The scaled TG assessor supplies N256/512 cases, builds and workload; its # TG-only diagnostic identity and early-sampling checks are not used here. base_checks = tg.assess(records, expected_revision, diagnostic=SCALED_DIAGNOSTIC if scaled else None)["checks"] checks = {name: base_checks.get(name, False) for name in SHARED} checks["shear_diagnostic_identity"] = all( r.get("diagnostic") == (SCALED_SHEAR if scaled else None) for r in records) cases = cases_for(scaled) indexed = {} for r in records: indexed.setdefault(tuple(r.get(k) for k in ("re_L", "n", "depth", "explosion")), r) for key in cases: _, n, depth, scheme = key label = f"{n}/{depth}/{scheme}" for name in PER_CASE: checks[f"{label} {name}"] = base_checks.get(f"{label} {name}", False) checks[f"{label} shear_metadata"] = key in indexed and metadata_ok(indexed[key], n) contract_valid = all(checks.values()) result = dict(checks=checks, contract_valid=contract_valid, cases=[list(k) for k in cases], expected_revision=expected_revision, diagnostic=SCALED_SHEAR if scaled else None, scope="2D periodic Re100 oblique (2,1) shear wave; one phase and one " "rectangle; no placement robustness or convergence order") if not contract_valid: result.update(status="INVALID_SET", passed=False) return result try: physics = sw.assess(indexed[cases[0]], indexed[cases[1]], [indexed[cases[2]], indexed[cases[3]]]) except (KeyError, ValueError) as error: result.update(status="INVALID_SET", passed=False, reason=str(error)) return result result.update(physics=physics, status=physics["status"], passed=physics["status"] == "PASS") try: result["signed"] = signed_summary([indexed[k] for k in cases]) except (KeyError, TypeError, ValueError) as error: result["signed_unavailable"] = str(error) return result def _signed(record): """Raw signed quantities of one valid record (None when the fit is unavailable).""" s = sw.summarize(record) bias = None if not s["rate_fit_valid"] else s["rate"] / s["exact_rate"] - 1 return dict(n=record["n"], depth=record["depth"], explosion=record["explosion"], rate_fit_valid=s["rate_fit_valid"], signed_rate_bias=bias, rate_tstar=s["rate_tstar"], exact_rate_tstar=s["exact_rate_tstar"], interval_rate_errors=s["interval_rate_errors"], residual_l2=s["residual_l2"], spurious_pressure_scaled=s["spurious_pressure_scaled"], spurious_pressure_rms=s["spurious_pressure_rms"], final_amplitude_error=record["rows"][-1]["amplitude_error"]) def signed_summary(records): """Signed bias per case and refined excess over each uniform control.""" rows = dict(zip(ROLES, (_signed(r) for r in records))) def minus(a, b): return None if a is None or b is None else a - b for role in ("constant", "projected_linear"): for control in ("uniform_root", "uniform_fine"): rows[role][f"excess_over_{control}"] = { key: minus(rows[role][key], rows[control][key]) for key in ("signed_rate_bias", "residual_l2", "spurious_pressure_rms")} return rows def load_reference(paths): """The four audited N128 receipts verbatim; never relabelled as fresh controls.""" blobs = [Path(path).read_bytes() for path in paths] hashes = {hashlib.sha256(blob).hexdigest() for blob in blobs} if len(blobs) != 4 or hashes != set(REFERENCE_RECEIPTS.values()): raise ValueError("N128 receipt hashes differ from the audited de5b0cc evidence") return [json.loads(blob) for blob in blobs] def resolution_trend(new_result, reference, reference_revision=REFERENCE_REVISION): """Descriptive N128 -> N256 signed changes; never an acceptance gate or an order.""" old_result = assess(reference, reference_revision) if "signed" not in old_result or "signed" not in new_result: return dict(valid=False, reason="N128 reference or N256 set lacks a valid signed summary") out = {} for role in ROLES: old, new = old_result["signed"][role], new_result["signed"][role] out[role] = {} for key in ("signed_rate_bias", "residual_l2", "spurious_pressure_rms", *(f"excess_over_{c}" for c in ("uniform_root", "uniform_fine"))): if key not in old: continue pairs = old[key].items() if isinstance(old[key], dict) else [(None, old[key])] for sub, low in pairs: high = new[key][sub] if sub else new[key] ok = low is not None and high is not None out[role][key if sub is None else f"{key}.{sub}"] = dict( n128=low, n256=high, signed_change=high - low if ok else None, n256_to_n128=high / low if ok and low else None) return dict(valid=True, reference_revision=reference_revision, reference_receipt_sha256=REFERENCE_RECEIPTS, reference_status=old_result["status"], changes=out, scope="same-placement two-resolution trend; not a convergence order, " "placement robustness or redesign decision") if __name__ == "__main__": p = argparse.ArgumentParser(description=__doc__) p.add_argument("files", type=Path, nargs=4) p.add_argument("--output", type=Path, required=True) p.add_argument("--expected-revision", required=True) p.add_argument("--diagnostic", choices=[SCALED_SHEAR]) p.add_argument("--reference-files", type=Path, nargs=4) args = p.parse_args() if args.output.exists(): p.error("Output already exists; choose a new path to retain prior evidence") if bool(args.diagnostic) != bool(args.reference_files): p.error("--diagnostic scaled_shear_n256 requires --reference-files (N128 receipts)") result = assess([json.loads(path.read_text()) for path in args.files], args.expected_revision, scaled=bool(args.diagnostic)) if args.diagnostic: try: reference = load_reference(args.reference_files) except ValueError as exc: p.error(str(exc)) result["resolution_trend"] = resolution_trend(result, reference) text = json.dumps(result, indent=2, allow_nan=False) + "\n" args.output.write_text(text) print(text, end="") raise SystemExit(0 if result["passed"] else 1)