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>
This commit is contained in:
commit
46100e1d53
3 files changed
+251
-25
No files matched your search
@@ -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"]),
|
||||
|
||||
Reference in new issue
Block a user