Compare commits

...
3 Commits
Author SHA1 Message Date
ClaudeandClaude Opus 5.5 5fb95f5f4d test: opt-in scaled_shear_n256 four-case shear diagnostic
- run_case: --diagnostic scaled_shear_n256 (requires --flow shear_wave;
  U256/U512/constant R256/projected R256, Re100, no early trace); N512
  only via one of the two scaled diagnostics; scaled_n256 stays TG-only.
- assess_shear_wave: scaled=True contract reusing 92b8afe scaled
  case/build/workload checks, shear diagnostic identity; signed rate bias,
  refined excess over each control; hash-pinned de5b0cc N128 reference and
  descriptive N128->N256 signed trend; CLI --diagnostic/--reference-files.
- tests: scaled contract, set mixing, trend/reference pin, runner options.
- shear_wave.py and oracle.py unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:14:54 +00:00
ClaudeandClaude Opus 5.5 46100e1d53 Merge native 92b8afe scaled N256 Taylor-Green diagnostic into claude/shear-wave
Bundle celeris-scaled-tg-92b8afe-base-eec4677.bundle (SHA256 9e593384...)
verified with git bundle verify; merged without rewriting history.
Conflicts resolved by retaining both additions: run_case keeps the
shear-wave flow helpers/receipt block and the scaled_n256 diagnostic block,
with scaled_n256 restricted to --flow taylor_green (mutually exclusive with
shear_wave); test_projected_pairs keeps the explicit 'taylor_green'
verify_source argument and 92b8afe's per-scheme selector expectation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:14:39 +00:00
Codex 92b8afeeed test: add scaled N256 Taylor-Green diagnostic 2026-10-18 17:00:55 -07:00
6 changed files with 508 additions and 37 deletions

No files matched your search

+42
View File
@@ -295,3 +295,45 @@ is not placement robustness. Two resolutions show a trend, not an order.
- Merge note: native 92b8afe adds a `scaled_n256` receipt block. When the
two are merged, keep both blocks and make `--flow shear_wave` and
`scaled_n256` mutually exclusive. Not merged here.
### Scaled shear diagnostic (opt-in `scaled_shear_n256`)
Runner: `run_case.py --flow shear_wave --diagnostic scaled_shear_n256 --re 100`
with one of these four cases:
- `--n 256 --depth 1` (U256)
- `--n 512 --depth 1` (U512)
- `--n 256 --depth 2 --explosion constant` (constant R256)
- `--n 256 --depth 2 --explosion projected_linear` (projected R256)
Everything physical is unchanged from N128:
- `rectangles(256,2)` covers the same physical box;
- same t* schedule (16N root steps);
- `nu = U*N/100`;
- same `eps(N)`, limits and floors.
`scaled_n256` (Taylor–Green, from native 92b8afe) and `scaled_shear_n256`
each require their own flow, so they are mutually exclusive. N512 is
accepted only through one of the two diagnostics. The shear diagnostic
takes no early-pressure trace.
Assessment:
python assess_shear_wave.py U256.json U512.json R256_constant.json R256_projected.json \
--diagnostic scaled_shear_n256 --reference-files <four de5b0cc N128 receipts> \
--output report.json --expected-revision <sha>
- The scaled N256/512 case, build and workload checks come from the
92b8afe assessor. Its TG-only diagnostic identity and early-sampling
checks are not used. Instead every record must carry
`diagnostic=scaled_shear_n256`, and N128 records must carry none.
- The reference N128 receipts are hash-pinned to the audited de5b0cc
evidence (commit cba6bca). They are never relabelled as fresh controls.
- The report always includes, for each case:
- the raw signed rate bias `rate/exact - 1` and the interval errors;
- each refined run's signed excess over *each* uniform control (rate
bias, residual, raw pressure rms);
- the N128→N256 signed changes and ratios. The ratio is null when the
N128 value is zero.
- These are descriptive. Passing or failing another floor-controlled
screen is not the conclusion, and a two-resolution ratio is not a
convergence order.
@@ -1,6 +1,7 @@
"""New-source four-case repeat of 11901a7; frozen oracle and gates are unchanged."""
import argparse
import hashlib
import json
import math
from pathlib import Path
@@ -8,16 +9,25 @@ from pathlib import Path
from assess import BASELINE_FACTOR, FLOORS
from oracle import LIMITS, TIMES, U, rectangles
from run_case import (INITIALIZATION, sample_steps, NUMERICAL_REVISION, SOURCE_SHA256,
BUILD_CAPTURE_SHA256, REFERENCE_HARNESS)
BUILD_CAPTURE_SHA256, REFERENCE_HARNESS, SCALED_DIAGNOSTIC)
# Host-generated snapshots of a135252 at the frozen two local configurations.
# Host-generated snapshots of a135252 at the frozen local configurations.
# These describe expected inputs; actual sidecars are captured before cleanup.
BUILD_SOURCES = {
128: "803177416b7599ab89cc5afd35cf4a28a673b2f4bb8e8a6a1abc0b6d77610873",
256: "17ec5e60f87b840d3d13b8778bc8a3aecf485469c5a061af46c5cc19b73396cf",
512: "4e85e38098858ec95c137d1b1e96846a58d9cf3cc242b349a3ad7c8b8e3ce0aa",
}
CASES = ((100, 128, 1, "constant"), (100, 256, 1, "constant"),
(100, 128, 2, "constant"), (100, 128, 2, "projected_linear"))
REFERENCE_REVISION = "2cf9853952e52f59bea63cf5c1d3a1cd76e53eed"
# Audited 2cf9853 scalar receipts, archived at evidence commit 90849a55cad4a0da9b72747da7bfe6eb75962a44.
REFERENCE_RECEIPTS = {
"uniform128": "724efafc267eaa59dcc59e8d4c16177b67f6c6a08fd2732a481833237bb19cee",
"uniform256": "3c312a99ebf747a135674dd481b77455a3d2c9a406ca388f30524b37dad9bbe9",
"constant128": "2ee28efd1e81b2e28b7902b6c4f95bb2c1ea4e5f0ec484638fa5ae83dca34bba",
"projected128": "ee67b1d4d90a048c0d3d1a16447c6eab3d89c94d151f791306e373f96dd8b963",
}
NUMERICS = dict(lattice_model="D2Q9", collision="SRT", store_precision="FP32",
ddf_shifting=True, streaming="double_buffer", les_enabled=False,
boundary="periodic", block_shape=[8, 8],
@@ -73,7 +83,11 @@ def valid_builds(record, n, depth):
return True
def assess(records, expected_revision=None):
def assess(records, expected_revision=None, *, diagnostic=None):
if diagnostic not in (None, SCALED_DIAGNOSTIC):
raise ValueError("Unknown diagnostic")
base_n = 256 if diagnostic else 128
cases = tuple((re, n * base_n // 128, depth, scheme) for re, n, depth, scheme in CASES)
indexed, duplicates = {}, []
for record in records:
key = tuple(record.get(k) for k in ("re_L", "n", "depth", "explosion"))
@@ -81,9 +95,11 @@ def assess(records, expected_revision=None):
duplicates.append(str(key))
else:
indexed[key] = record
missing = [str(k) for k in CASES if k not in indexed]
checks = dict(complete_matrix=not missing, no_extra_cases=set(indexed) <= set(CASES),
missing = [str(k) for k in cases if k not in indexed]
checks = dict(complete_matrix=not missing, no_extra_cases=set(indexed) <= set(cases),
no_duplicate_cases=not duplicates, finite_receipts=finite_tree(records))
if diagnostic or any("diagnostic" in r for r in records):
checks["diagnostic_identity"] = all(r.get("diagnostic") == diagnostic for r in records)
sources = [r.get("source", {}) for r in records]
checks["same_source_and_harness"] = bool(sources) and len({
json.dumps(s, sort_keys=True) for s in sources}) == 1
@@ -106,9 +122,11 @@ def assess(records, expected_revision=None):
) and len(set(devices)) == 1
enabled = [r.get("early_pressure", {}).get("enabled") for r in records]
checks["same_early_sampling"] = bool(enabled) and all(type(v) is bool for v in enabled) and len(set(enabled)) == 1
if diagnostic:
checks["diagnostic_early_sampling"] = all(v is True for v in enabled)
shared_valid = all(checks.values())
complete, case_valid, early = {}, {}, []
for key in CASES:
for key in cases:
if key not in indexed:
continue
r = indexed[key]
@@ -135,7 +153,7 @@ def assess(records, expected_revision=None):
(("module", "__init__.py"), ("compiler", "cuda/compiler_v2.py"), ("kernel_root", "lbm/kernels")))
expected_patch = [] if depth == 1 else rectangles(n, depth)
checks[label + " patch"] = json.dumps(r.get("refinements")) == json.dumps(expected_patch)
cells = [n*n] if depth == 1 else [8704, 30720]
cells = [n*n] if depth == 1 else [17*n*n//32, 15*n*n//8]
hops = [16*n * 2**l for l in range(depth)]
work = r.get("workload", {})
checks[label + " workload"] = (
@@ -168,19 +186,22 @@ def assess(records, expected_revision=None):
comparisons, scheme_results = [], {}
for scheme in ("constant", "projected_linear"):
key = (100, 128, 2, scheme)
key = (100, base_n, 2, scheme)
for metric, floor in FLOORS.items():
amr, coarse, fine = (worst(k, metric) for k in (key, CASES[0], CASES[1]))
amr, coarse, fine = (worst(k, metric) for k in (key, cases[0], cases[1]))
budget = None if coarse is None else max(BASELINE_FACTOR * coarse, floor)
budget = budget if finite(budget) else None
ratio = None if amr is None or fine is None else amr / max(fine, 1e-30)
passed = amr is not None and budget is not None and amr <= budget
checks[f"baseline {scheme}/{metric}"] = passed
comparisons.append(dict(explosion=scheme, metric=metric, amr=amr,
uniform128=coarse, baseline_budget=budget, passed=passed,
uniform256=fine, amr_to_uniform256=ratio if finite(ratio) else None))
baseline_budget=budget, passed=passed,
**{f"uniform{base_n}": coarse, f"uniform{2*base_n}": fine,
f"amr_to_uniform{2*base_n}": ratio if finite(ratio) else None}))
if diagnostic:
comparisons[-1]["floor_dominates"] = None if coarse is None else floor >= BASELINE_FACTOR * coarse
baseline_passed = all(checks[f"baseline {scheme}/{metric}"] for metric in FLOORS)
valid = shared_valid and all(case_valid.get(k, False) for k in (CASES[0], CASES[1], key))
valid = shared_valid and all(case_valid.get(k, False) for k in (cases[0], cases[1], key))
scheme_results[scheme] = dict(passed=valid and baseline_passed,
valid_case_and_controls=valid, baseline_passed=baseline_passed)
return dict(passed=all(checks.values()), missing=missing, duplicates=duplicates, checks=checks,
@@ -190,19 +211,89 @@ def assess(records, expected_revision=None):
floors=FLOORS, baseline_factor=BASELINE_FACTOR,
main_statistic="maximum of four post-initial samples at t*=.12,.24,.36,.48",
early_statistic="sampled pressure maximum only, t*=k*.001875, k=0..64; not an all-step or continuous maximum",
finest_control="uniform256 and AMR/ uniform256 ratios are descriptive, not acceptance gates",
finest_control=f"uniform{2*base_n} and AMR/ uniform{2*base_n} ratios are descriptive, not acceptance gates",
scope="2D periodic Re100 smooth-decay diagnostic; no new algorithm, convergence-order or general AMR qualification")
def load_reference(paths):
"""Use the four audited historical files verbatim, never relabel them fresh controls."""
blobs = [path.read_bytes() for path in paths]
hashes = [hashlib.sha256(blob).hexdigest() for blob in blobs]
if len(hashes) != 4 or set(hashes) != set(REFERENCE_RECEIPTS.values()):
raise ValueError("Historical N128 receipt hashes differ from the audited 2cf9853 evidence")
return [json.loads(blob) for blob in blobs]
def resolution_trend(records, reference, expected_revision):
"""Signed changes are descriptive; they never replace the frozen acceptance budgets."""
old = assess(reference, REFERENCE_REVISION)
new = assess(records, expected_revision, diagnostic=SCALED_DIAGNOSTIC)
# Numerical screen failures still have useful raw errors; only malformed inputs block trends.
valid = all(v for result in (old, new) for k, v in result["checks"].items()
if not k.startswith("baseline ") and not k.endswith(" absolute"))
valid = valid and all(maximum(r["rows"], m) is not None for r in reference + records for m in LIMITS)
oracle = reference[0]["source"]["harness_sha256"].get("oracle.py") if valid else None
valid = valid and bool(oracle) and records[0]["source"]["harness_sha256"].get("oracle.py") == oracle
if not valid:
return dict(valid=False, per_time=[], worst_post_initial=[], uniform256_bridge=[])
key = lambda r: (r["re_L"], r["n"], r["depth"], r["explosion"])
before, after = {key(r): r for r in reference}, {key(r): r for r in records}
def change(role, metric, low, high, **extra):
ratio = high / low if low else None
percent = 100*(ratio-1) if ratio is not None else None
return dict(role=role, metric=metric, n128_campaign_error=low, n256_campaign_error=high,
signed_change=high-low, new_to_old=ratio if finite(ratio) else None,
ratio_unavailable_reason=None if finite(ratio) else "zero historical error" if not low else "overflow",
change_percent=percent if finite(percent) else None, **extra)
per_time, worst, bridge = [], [], []
for old_key, role in zip(CASES, ("uniform_root", "uniform_fine", "constant", "projected_linear")):
re, n, depth, scheme = old_key
low, high = before[old_key], after[(re, 2*n, depth, scheme)]
for metric in LIMITS:
per_time.extend(change(role, metric, a[metric], b[metric], tstar=a["tstar"])
for a, b in zip(low["rows"], high["rows"]))
worst.append(change(role, metric, maximum(low["rows"][1:], metric),
maximum(high["rows"][1:], metric)))
for a, b in zip(before[CASES[1]]["rows"], after[CASES[1]]["rows"]):
bridge.extend(dict(metric=m, tstar=a["tstar"], historical=a[m], fresh=b[m], signed_change=b[m]-a[m])
for m in LIMITS)
low, high = before[CASES[1]], after[CASES[1]]
bridge_identity = dict(main_rows_identical=low["rows"] == high["rows"],
early_pressure_rows_identical=low["early_pressure"]["rows"] == high["early_pressure"]["rows"])
same_runtime = reference[0]["runtime_identity"] == records[0]["runtime_identity"]
return dict(valid=True, reference_revision=REFERENCE_REVISION, reference_receipt_sha256=REFERENCE_RECEIPTS,
reference_scheme_results=old["scheme_results"], per_time=per_time, worst_post_initial=worst,
uniform256_bridge=bridge, uniform256_bridge_identity=bridge_identity,
same_recorded_runtime=same_runtime,
trend_interpretation_ready=all(bridge_identity.values()) and same_runtime,
scope="Historical same-production/oracle reference versus fresh controls; same-placement two-resolution trend only, not convergence order or phase robustness")
if __name__ == "__main__":
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("files", type=Path, nargs="+")
p.add_argument("--output", type=Path, required=True)
p.add_argument("--expected-revision", required=True)
p.add_argument("--diagnostic", choices=[SCALED_DIAGNOSTIC])
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")
result = assess([json.loads(path.read_text()) for path in args.files], args.expected_revision)
if bool(args.diagnostic) != bool(args.reference_files):
p.error("--diagnostic scaled_n256 requires --reference-files; references are diagnostic-only")
records = [json.loads(path.read_text()) for path in args.files]
result = assess(records, args.expected_revision, diagnostic=args.diagnostic)
if args.diagnostic:
try:
reference = load_reference(args.reference_files)
except ValueError as exc:
p.error(str(exc))
result["diagnostic"] = args.diagnostic
result["resolution_trend"] = resolution_trend(records, reference, args.expected_revision)
result["checks"]["valid_historical_reference_and_trend"] = result["resolution_trend"]["valid"]
result["passed"] = all(result["checks"].values())
args.output.write_text(json.dumps(result, indent=2, allow_nan=False) + "\n")
print(json.dumps(result, indent=2, allow_nan=False))
raise SystemExit(0 if result["passed"] else 1)
@@ -1,4 +1,9 @@
"""Fixed N128 four-case shear-wave contract: U128, U256, constant R128, projected R128.
"""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
@@ -6,12 +11,23 @@ Taylor-Green-specific checks are replaced by shear-wave metadata and physics.
"""
import argparse
import hashlib
import json
from pathlib import Path
import assess_projected_pairs as tg
import shear_wave as sw
from run_case import SHEAR_WAVE_SHA256
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",
@@ -33,15 +49,26 @@ def metadata_ok(record, n):
and (record.get("source") or {}).get("shear_wave_sha256") == SHEAR_WAVE_SHA256)
def assess(records, expected_revision=None):
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")
base_checks = tg.assess(records, expected_revision)["checks"]
# 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 tg.CASES:
for key in cases:
_, n, depth, scheme = key
label = f"{n}/{depth}/{scheme}"
for name in PER_CASE:
@@ -49,32 +76,112 @@ def assess(records, expected_revision=None):
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 tg.CASES], expected_revision=expected_revision,
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[tg.CASES[0]], indexed[tg.CASES[1]],
[indexed[tg.CASES[2]], indexed[tg.CASES[3]]])
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")
result = assess([json.loads(path.read_text()) for path in args.files], args.expected_revision)
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="")
+24 -2
View File
@@ -19,6 +19,8 @@ BUILD_CAPTURE_SHA256 = "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944
REFERENCE_HARNESS = "11901a7f77557a901e017a171eeae1758d584fa5"
INITIALIZATION = "physical FP64 equilibrium G at actual cell centers; rho=1+3p"
SHEAR_WAVE_SHA256 = "81d5c8ee60864372887cddf9239580c82fb6750d956038f1e3ee9de61aa4e877"
SCALED_DIAGNOSTIC = "scaled_n256"
SCALED_SHEAR = "scaled_shear_n256" # mutually exclusive with scaled_n256 (one flow each)
def flow_functions(flow="taylor_green"):
@@ -176,10 +178,13 @@ def main():
p.add_argument("--run-gpu", action="store_true")
p.add_argument("--dry-run", action="store_true")
p.add_argument("--re", type=int, choices=[100, 1000], required=True)
p.add_argument("--n", type=int, choices=[32, 64, 128, 256], required=True)
p.add_argument("--n", type=int, choices=[32, 64, 128, 256, 512], required=True)
p.add_argument("--depth", type=int, choices=[1, 2, 3], required=True)
p.add_argument("--output", type=Path, required=True)
p.add_argument("--explosion", choices=["constant", "projected_linear"], default="constant")
p.add_argument("--diagnostic", choices=[SCALED_DIAGNOSTIC, SCALED_SHEAR],
help="explicit four-case N256/fine512 same-placement diagnostic "
"(scaled_n256: Taylor-Green; scaled_shear_n256: shear wave)")
p.add_argument("--early-pressure", action="store_true",
help="also save 65 scalar pressure samples at t*=k*.001875, k=0..64")
p.add_argument("--flow", choices=["taylor_green", "shear_wave"], default="taylor_green")
@@ -191,6 +196,20 @@ def main():
p.error("Output already exists; choose a new path to retain prior evidence")
if args.explosion != "constant" and args.depth != 2:
p.error("projected_linear requires depth 2")
if args.diagnostic:
cases = {(256, 1, "constant"), (512, 1, "constant"),
(256, 2, "constant"), (256, 2, "projected_linear")}
flow = "shear_wave" if args.diagnostic == SCALED_SHEAR else "taylor_green"
if args.flow != flow:
p.error(f"--diagnostic {args.diagnostic} requires --flow {flow}")
if args.diagnostic == SCALED_DIAGNOSTIC and (
args.re != 100 or (args.n, args.depth, args.explosion) not in cases
or not args.early_pressure):
p.error("scaled_n256 requires one of its four Re100 cases and --early-pressure")
if args.diagnostic == SCALED_SHEAR and (args.n, args.depth, args.explosion) not in cases:
p.error("scaled_shear_n256 requires one of its four Re100 cases")
elif args.n == 512:
p.error("N512 requires --diagnostic scaled_n256 or scaled_shear_n256")
selected = os.environ.get("CUDA_VISIBLE_DEVICES", "")
if not args.dry_run and (not args.run_gpu or not selected or "," in selected or selected == "-1"):
p.error("--run-gpu and exactly one explicit CUDA_VISIBLE_DEVICES are required")
@@ -199,7 +218,8 @@ def main():
source = verify_source(repo, args.expected_revision, args.flow)
runtime = runtime_source(repo)
if args.dry_run:
print(json.dumps(dict(source=source, runtime_source=runtime, dry_run=True)))
print(json.dumps(dict(source=source, runtime_source=runtime, dry_run=True,
**({"diagnostic": args.diagnostic} if args.diagnostic else {}))))
return 0
from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.blocks import BlockLayout2D
@@ -252,6 +272,8 @@ def main():
report.update(flow=args.flow, mode=list(shear_wave.MODE),
polarization=shear_wave.E.tolist(), angle_deg=shear_wave.ANGLE_DEG,
phase=shear_wave.PHI, eps=shear_wave.eps(args.n))
if args.diagnostic:
report["diagnostic"] = args.diagnostic
args.output.parent.mkdir(parents=True, exist_ok=True)
def save():
temporary = args.output.with_suffix(args.output.suffix + ".tmp")
@@ -17,6 +17,7 @@ from unittest.mock import patch
import numpy as np
import run_case
import assess_projected_pairs as assessor
from assess_projected_pairs import (BUILD_SOURCES, CASES, NUMERICS, NUMERICAL_REVISION,
SOURCE_SHA256, assess)
from oracle import LIMITS, TIMES, U, rectangles
@@ -31,7 +32,7 @@ RUNTIME = dict(device=dict(name="host mock", pci_bus_id="mock", capability=[7, 0
def source():
return dict(revision=MOCK_REVISION, dirty=False, source_tree_sha256=SOURCE_SHA256,
harness_sha256={"run_case.py": "a" * 64},
harness_sha256={"run_case.py": "a" * 64, "oracle.py": "c" * 64},
build_capture_sha256=run_case.BUILD_CAPTURE_SHA256)
@@ -42,12 +43,14 @@ def build_metadata(size):
arch="sm_70", flags=["--use_fast_math"], ptx_sha256="b" * 64)
def records(early=False):
def records(early=False, diagnostic=None):
from CelerisLab.lbm.hierarchy import build_hierarchy
from CelerisLab.lbm.refinement import ACTIVE
out = []
for re, n, depth, scheme in CASES:
if diagnostic:
n *= 2
cfg = run_case.config(n, re)
refinements = [] if depth == 1 else rectangles(n, depth)
h = build_hierarchy(cfg, refinements)
@@ -66,6 +69,8 @@ def records(early=False):
early_pressure=dict(enabled=early, rows=[
dict(step=s, tstar=s*U/n, pressure_l2=.01 if s not in main_steps else 0.0) for s in early_steps],
sampled_max_pressure_l2=.01 if early else None)))
if diagnostic:
out[-1]["diagnostic"] = diagnostic
return out
@@ -251,7 +256,7 @@ class ProjectedPairsTests(unittest.TestCase):
def test_pinned_build_sources_match_host_generated_inputs(self):
from CelerisLab.cuda import compiler_v2
for size in (128, 256):
for size in (128, 256, 512):
cfg = replace(run_case.config(size, 100), nx=10, ny=10)
cfg.validate()
root = compiler_v2.generate_config(cfg)
@@ -263,6 +268,111 @@ class ProjectedPairsTests(unittest.TestCase):
finally:
compiler_v2.cleanup_build_dir(root)
def test_scaled_geometry_work_and_frozen_gates(self):
data = records(True, run_case.SCALED_DIAGNOSTIC)
self.assertEqual(sum(r["workload"]["active_collision_updates"] for r in data), 4714397696)
self.assertEqual([r["viscosity"] for r in data], [.0768, .1536, .0768, .0768])
self.assertEqual(data[-1]["tau_by_level"], [.7303999999999999, .9608])
for r in data:
self.assertEqual([row["tstar"] for row in r["rows"]], TIMES)
self.assertEqual(len(r["early_pressure"]["rows"]), 65)
if r["depth"] == 2:
self.assertEqual(r["refinements"], [[(32, 32, 224, 192)]])
self.assertEqual(r["workload"]["active_cells_by_level"], [34816, 122880])
self.assertEqual(r["workload"]["level_hops"], [4096, 8192])
result = assess(data, MOCK_REVISION, diagnostic=run_case.SCALED_DIAGNOSTIC)
self.assertTrue(result["passed"])
self.assertEqual(result["floors"], dict(velocity_l2=.002, pressure_l2=.02, energy_relative=.004))
self.assertTrue(all(row["floor_dominates"] for row in result["comparisons"]))
data[-1]["rows"][-1]["velocity_l2"] = .00200001
self.assertFalse(assess(data, diagnostic=run_case.SCALED_DIAGNOSTIC)["passed"])
self.assertFalse(assess(data)["passed"])
data[-1]["rows"][-1]["velocity_l2"] = 0.0
for mutate in (lambda r: r.pop("diagnostic"), lambda r: r.update(diagnostic="wrong"),
lambda r: r["source"].update(revision="wrong"),
lambda r: r["early_pressure"].update(enabled=False),
lambda r: r.update(refinements=[[(32, 32, 224, 200)]])):
bad = deepcopy(data)
mutate(bad[-1])
self.assertFalse(assess(bad, MOCK_REVISION, diagnostic=run_case.SCALED_DIAGNOSTIC)["passed"])
def test_raw_resolution_changes_and_reference_identity(self):
old, new = records(True), records(True, run_case.SCALED_DIAGNOSTIC)
for r in old:
r["source"]["revision"] = assessor.REFERENCE_REVISION
old[-2]["rows"][-1]["velocity_l2"] = .004 # historical constant failure remains usable
old[-1]["rows"][-1]["velocity_l2"] = .001
new[-1]["rows"][-1]["velocity_l2"] = .0015 # floor pass, but worse raw error
result = assessor.resolution_trend(new, old, MOCK_REVISION)
self.assertTrue(result["valid"])
self.assertTrue(result["trend_interpretation_ready"])
self.assertFalse(result["reference_scheme_results"]["constant"]["passed"])
self.assertEqual((len(result["per_time"]), len(result["worst_post_initial"]),
len(result["uniform256_bridge"])), (80, 16, 20))
row = next(r for r in result["per_time"] if r["role"] == "projected_linear"
and r["metric"] == "velocity_l2" and r["tstar"] == .48)
self.assertEqual((row["signed_change"], row["new_to_old"], row["change_percent"]), (.0005, 1.5, 50.))
self.assertTrue(assess(new, diagnostic=run_case.SCALED_DIAGNOSTIC)["passed"])
self.assertIsNone(result["per_time"][0]["new_to_old"]) # zero denominator is explicit
self.assertEqual(result["per_time"][0]["ratio_unavailable_reason"], "zero historical error")
new[-1]["rows"][-1]["velocity_l2"] = .06 # retain raw errors even when absolute screen fails
self.assertTrue(assessor.resolution_trend(new, old, MOCK_REVISION)["valid"])
self.assertFalse(assess(new, diagnostic=run_case.SCALED_DIAGNOSTIC)["passed"])
new[-1]["rows"][-1]["velocity_l2"] = .0015
for sample in ("rows", "early_pressure"):
bad = deepcopy(new)
if sample == "rows":
bad[0]["rows"][-1]["velocity_l2"] = .0001
else:
bad[0]["early_pressure"]["rows"][1]["pressure_l2"] = .009
result = assessor.resolution_trend(bad, old, MOCK_REVISION)
self.assertTrue(result["valid"])
self.assertFalse(result["trend_interpretation_ready"])
for mutate in (lambda r: r["source"].update(revision=MOCK_REVISION),
lambda r: r["source"].update(source_tree_sha256="wrong"),
lambda r: r["source"]["harness_sha256"].update(**{"oracle.py": "wrong"}),
lambda r: r.update(diagnostic=run_case.SCALED_DIAGNOSTIC),
lambda r: r.update(refinements=[]), lambda r: r["rows"].pop()):
bad = deepcopy(old)
mutate(bad[-1])
self.assertFalse(assessor.resolution_trend(new, bad, MOCK_REVISION)["valid"])
with tempfile.TemporaryDirectory() as tmp:
paths = [Path(tmp) / f"{i}.json" for i in range(4)]
for path, receipt in zip(paths, old):
path.write_text(json.dumps(receipt))
with self.assertRaisesRegex(ValueError, "receipt hashes"):
assessor.load_reference(paths)
witnesses = {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in paths}
with patch.object(assessor, "REFERENCE_RECEIPTS", witnesses):
self.assertEqual(assessor.load_reference(paths), json.loads(json.dumps(old)))
with self.assertRaises(ValueError):
assessor.load_reference(paths[:-1] + paths[:1])
paths[-1].write_text(paths[-1].read_text() + " ")
with self.assertRaises(ValueError):
assessor.load_reference(paths)
def test_scaled_runner_requires_explicit_bounded_diagnostic(self):
with tempfile.TemporaryDirectory() as tmp:
base = ["run_case.py", "--repo", str(REPO), "--expected-revision", MOCK_REVISION,
"--output", str(Path(tmp) / "case.json"), "--dry-run"]
diagnostic = ["--diagnostic", run_case.SCALED_DIAGNOSTIC, "--early-pressure"]
for n, depth, re, extra, valid in (
(512, 1, 100, [], False), (512, 1, 100, diagnostic, True),
(256, 2, 100, diagnostic, True), (128, 2, 100, diagnostic, False),
(256, 3, 100, diagnostic, False), (256, 2, 1000, diagnostic, False),
(256, 2, 100, diagnostic[:2], False), (512, 2, 100, diagnostic, False)):
argv = base + ["--n", str(n), "--depth", str(depth), "--re", str(re)] + extra
with self.subTest(argv=argv), patch.object(sys, "argv", argv), \
patch.object(run_case, "verify_source", return_value=source()) as verify, \
redirect_stdout(io.StringIO()), patch("sys.stderr", io.StringIO()):
if valid:
self.assertEqual(run_case.main(), 0)
else:
with self.assertRaises(SystemExit) as caught:
run_case.main()
self.assertEqual(caught.exception.code, 2)
verify.assert_not_called()
def test_source_preflight_requires_clean_exact_revision_and_tree(self):
import oracle
from tests.validation.multigrid import check_projected_pairs as gate
@@ -349,9 +459,15 @@ class ProjectedPairsTests(unittest.TestCase):
def test_mocked_runner_default_early_and_failure(self):
# Replace the GPU context and steppers before import. No CUDA module or flow is used.
for early, depth, fail in ((False, 1, None), (False, 2, None), (True, 2, None),
cases = [(early, depth, fail, 128, None, "projected_linear" if early else "constant")
for early, depth, fail in
((False, 1, None), (False, 2, None), (True, 2, None),
(True, 2, "resource"), (True, 2, "nonfinite"),
(True, 2, "probe_nonfinite")):
(True, 2, "probe_nonfinite"))]
cases += [(True, depth, None, n, run_case.SCALED_DIAGNOSTIC, scheme)
for n, depth, scheme in ((256, 1, "constant"), (512, 1, "constant"),
(256, 2, "constant"), (256, 2, "projected_linear"))]
for early, depth, fail, n, diagnostic, scheme in cases:
calls, selectors = [], []
class FakeRun:
@@ -395,11 +511,14 @@ class ProjectedPairsTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmp:
output = Path(tmp) / "case.json"
argv = ["run_case.py", "--repo", str(REPO), "--re", "100", "--n", "128",
argv = ["run_case.py", "--repo", str(REPO), "--re", "100", "--n", str(n),
"--depth", str(depth), "--output", str(output),
"--expected-revision", MOCK_REVISION, "--run-gpu"]
argv += ["--explosion", scheme]
if early:
argv += ["--early-pressure", "--explosion", "projected_linear"]
argv += ["--early-pressure"]
if diagnostic:
argv += ["--diagnostic", diagnostic]
with patch.dict(sys.modules, modules), patch.object(sys, "argv", argv), \
patch.dict("os.environ", CUDA_VISIBLE_DEVICES="mock"), \
patch.object(run_case, "verify_source", return_value=source()) as verify, \
@@ -413,15 +532,16 @@ class ProjectedPairsTests(unittest.TestCase):
self.assertEqual(run_case.main(), 0)
receipt = json.loads(output.read_text())
verify.assert_called_once_with(REPO, MOCK_REVISION, "taylor_green")
self.assertEqual(selectors, ["projected_linear" if early else "constant"] if depth == 2 else [])
self.assertEqual(selectors, [scheme] if depth == 2 else [])
self.assertEqual(receipt["source"], source())
self.assertEqual(receipt["runtime_identity"], RUNTIME)
self.assertEqual(receipt["completed"], not fail)
self.assertEqual(receipt.get("diagnostic"), diagnostic)
self.assertEqual(calls[:2], [0, 1]) # READY probe is part of this trajectory
if not fail:
self.assertEqual([r["tstar"] for r in receipt["rows"]], TIMES)
self.assertEqual(len(receipt["early_pressure"]["rows"]), 65 if early else 0)
self.assertEqual(calls[-1], 2048)
self.assertEqual(calls[-1], 16*n)
else:
self.assertEqual(len(receipt["rows"]), 1)
self.assertEqual(len(receipt["early_pressure"]["rows"]),
@@ -4,8 +4,13 @@ Run from this directory with PYTHONPATH=<checkout>/src (same as test_oracle.py).
"""
import hashlib
import io
import json
import math
import sys
import tempfile
from contextlib import redirect_stdout
from unittest.mock import patch
import unittest
from pathlib import Path
@@ -361,7 +366,7 @@ class RunnerSampleTests(unittest.TestCase):
self.assertEqual(row["leaf_cells"], N * N)
def receipt(n, depth, explosion="constant"):
def receipt(n, depth, explosion="constant", diagnostic=None):
"""Synthetic receipt satisfying every contract field of the fixed four-case set."""
import assess_projected_pairs as tg
steps = run_case.sample_steps(n)[0]
@@ -369,7 +374,7 @@ def receipt(n, depth, explosion="constant"):
for row, step in zip(rows, steps):
row.update(step=step, tstar=step * U / n,
spurious_pressure_scaled_by_level=[row["spurious_pressure_scaled"]] * depth)
cells = [n * n] if depth == 1 else [8704, 30720]
cells = [n * n] if depth == 1 else [17 * n * n // 32, 15 * n * n // 8]
hops = [16 * n * 2**level for level in range(depth)]
builds = []
for level in range(depth):
@@ -406,7 +411,8 @@ def receipt(n, depth, explosion="constant"):
active_collision_updates=sum(c * h for c, h in zip(cells, hops))),
actual_build_sidecars=builds, rows=rows, completed=True,
flow="shear_wave", mode=list(sw.MODE), polarization=sw.E.tolist(),
angle_deg=sw.ANGLE_DEG, phase=sw.PHI, eps=sw.eps(n))
angle_deg=sw.ANGLE_DEG, phase=sw.PHI, eps=sw.eps(n),
**({"diagnostic": diagnostic} if diagnostic else {}))
class ContractTests(unittest.TestCase):
@@ -448,6 +454,89 @@ class ContractTests(unittest.TestCase):
self.assertEqual(a(self.records, "wrong-revision")["status"], "INVALID_SET")
def scaled_set(rate_error=0.0):
d = run_case.SCALED_SHEAR
out = [receipt(256, 1, diagnostic=d), receipt(512, 1, diagnostic=d),
receipt(256, 2, diagnostic=d), receipt(256, 2, "projected_linear", diagnostic=d)]
if rate_error:
out[3]["rows"] = rows_for(256, rate_error=rate_error)
for row, step in zip(out[3]["rows"], run_case.sample_steps(256)[0]):
row.update(step=step, tstar=step * U / 256,
spurious_pressure_scaled_by_level=[row["spurious_pressure_scaled"]] * 2)
return out
class ScaledContractTests(unittest.TestCase):
def setUp(self):
import assess_shear_wave
self.mod = assess_shear_wave
def test_scaled_contract_and_signed_excess(self):
result = self.mod.assess(scaled_set(1.5e-3), "r", scaled=True)
self.assertTrue(result["contract_valid"], [k for k, v in result["checks"].items() if not v])
self.assertEqual([c[1] for c in result["cases"]], [256, 512, 256, 256])
projected = result["signed"]["projected_linear"]
self.assertAlmostEqual(projected["signed_rate_bias"], 1.5e-3, delta=1e-9)
self.assertAlmostEqual(projected["excess_over_uniform_root"]["signed_rate_bias"], 1.5e-3,
delta=1e-9)
self.assertIn("excess_over_uniform_fine", projected)
def test_scaled_and_default_sets_do_not_mix(self):
n128 = [receipt(128, 1), receipt(256, 1), receipt(128, 2), receipt(128, 2, "projected_linear")]
self.assertEqual(self.mod.assess(n128, "r", scaled=True)["status"], "INVALID_SET")
self.assertEqual(self.mod.assess(scaled_set(), "r")["status"], "INVALID_SET")
unlabeled = scaled_set()
unlabeled[0].pop("diagnostic")
self.assertEqual(self.mod.assess(unlabeled, "r", scaled=True)["status"], "INVALID_SET")
tg_label = scaled_set()
tg_label[2]["diagnostic"] = run_case.SCALED_DIAGNOSTIC
self.assertEqual(self.mod.assess(tg_label, "r", scaled=True)["status"], "INVALID_SET")
def test_resolution_trend_and_reference_pin(self):
reference = [receipt(128, 1), receipt(256, 1), receipt(128, 2),
receipt(128, 2, "projected_linear")]
new = self.mod.assess(scaled_set(1.5e-3), "r", scaled=True)
trend = self.mod.resolution_trend(new, reference, "r")
self.assertTrue(trend["valid"])
change = trend["changes"]["projected_linear"]["signed_rate_bias"]
self.assertAlmostEqual(change["signed_change"], 1.5e-3, delta=1e-9)
self.assertIn("excess_over_uniform_fine.residual_l2", trend["changes"]["constant"])
with tempfile.TemporaryDirectory() as tmp:
paths = []
for i, r in enumerate(reference):
paths.append(Path(tmp) / f"{i}.json")
paths[-1].write_text(json.dumps(r))
with self.assertRaises(ValueError):
self.mod.load_reference(paths)
def test_scaled_runner_options(self):
repo = Path(__file__).resolve().parents[3]
with tempfile.TemporaryDirectory() as tmp:
base = ["run_case.py", "--repo", str(repo), "--expected-revision", "f" * 40,
"--output", str(Path(tmp) / "case.json"), "--dry-run", "--re", "100"]
shear = ["--flow", "shear_wave"]
scaled = ["--diagnostic", run_case.SCALED_SHEAR]
for extra, valid in (
(["--n", "512", "--depth", "1"] + shear + scaled, True),
(["--n", "256", "--depth", "2", "--explosion", "projected_linear"] + shear + scaled, True),
(["--n", "512", "--depth", "1"] + shear, False),
(["--n", "128", "--depth", "2"] + shear + scaled, False),
(["--n", "512", "--depth", "1"] + scaled, False), # needs shear flow
(["--n", "512", "--depth", "1", "--early-pressure", "--diagnostic",
run_case.SCALED_DIAGNOSTIC] + shear, False), # mutually exclusive
(["--n", "256", "--depth", "2", "--early-pressure"] + shear + scaled, False)):
argv = base + extra
with self.subTest(argv=argv), patch.object(sys, "argv", argv), \
patch.object(run_case, "verify_source", return_value={}), \
patch.object(run_case, "runtime_source", return_value={}), \
redirect_stdout(io.StringIO()), patch("sys.stderr", io.StringIO()):
if valid:
self.assertEqual(run_case.main(), 0)
else:
with self.assertRaises(SystemExit):
run_case.main()
class DefaultPathTests(unittest.TestCase):
def test_frozen_oracle_is_byte_identical(self):
digest = hashlib.sha256((HERE / "oracle.py").read_bytes()).hexdigest()