test: select matched MRT DFG pilot with separate provenance
This commit is contained in:
1 parent
3ea131e92c
commit
2abc48f0d8
4 files changed
+290
-27
No files matched your search
@@ -1,4 +1,4 @@
|
||||
"""Frozen matched SRT DFG comparison. GPU execution requires explicit root admission."""
|
||||
"""Frozen matched SRT/MRT DFG comparison. GPU execution requires explicit root admission."""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
@@ -39,20 +39,21 @@ def helpers(source):
|
||||
return h, periodic
|
||||
|
||||
|
||||
def config(h, diameter):
|
||||
cfg, body, p = h.make_config(diameter, SPEED, "SRT", "neq_extrap", "zou_he_local")
|
||||
def config(h, diameter, collision="SRT"):
|
||||
cfg, body, p = h.make_config(diameter, SPEED, collision, "neq_extrap", "zou_he_local")
|
||||
cfg["method"]["outlet"]["srt_neq_damp"] = 0.5
|
||||
return cfg, body, p
|
||||
|
||||
|
||||
def plan(h):
|
||||
_, _, c = config(h, 40)
|
||||
_, _, f = config(h, 80)
|
||||
def plan(h, collision="SRT"):
|
||||
_, _, c = config(h, 40, collision)
|
||||
_, _, f = config(h, 80, collision)
|
||||
x0, y0, x1, y1 = BOUNDS
|
||||
fine_active = 4 * (x1 - x0) * (y1 - y0)
|
||||
coarse_uncovered = c["nx"] * c["ny"] - fine_active // 4
|
||||
return dict(
|
||||
status="prepared_not_run",
|
||||
collision=collision,
|
||||
root_gpu_gates_required=True,
|
||||
root=c,
|
||||
uniform=f,
|
||||
@@ -82,7 +83,11 @@ def plan(h):
|
||||
/ (2 * f["nx"] * f["ny"]),
|
||||
cost_caveat="Geometry-only estimates include ghosts/solids; exclude block halos, transfers, observation and launch overhead. Not measured speedup.",
|
||||
sampling_offset="For origin (38,22), fine physical x=(j+75.5)*dx80 versus uniform i*dx80: half-fine-cell x offset. Fine physical y=(k+42.5)*dx80 equals uniform (l-.5)*dx80 at l=k+43: y samples align. Body, wall and source planes coincide.",
|
||||
outlet="SRT pressure NEQ, all nine fneq damped by .5, no backflow clamp; noncanonical DFG outlet",
|
||||
outlet=(
|
||||
"SRT pressure NEQ, all nine fneq damped by .5, no backflow clamp; noncanonical DFG outlet"
|
||||
if collision == "SRT" else
|
||||
"MRT pressure NEQ, unknowns q2/6/8 extrapolated; no backflow clamp; noncanonical DFG outlet"
|
||||
),
|
||||
modes={"pilot_tstar": 5.0, "full_tstar": 300.0},
|
||||
observation_dense_tstar=0.02,
|
||||
)
|
||||
@@ -120,7 +125,7 @@ def initial_state(shape, origin, spacing, height=164.0, speed=SPEED, root=False)
|
||||
return w * (1 + 3 * cu + 4.5 * cu * cu - 1.5 * velocity * velocity)
|
||||
|
||||
|
||||
def host_geometry(source, h):
|
||||
def host_geometry(source, h, collision="SRT"):
|
||||
"""Production donor/transfer and complete cut-link checks, without CUDA."""
|
||||
from CelerisLab.config import load_lbm_config
|
||||
from CelerisLab.lbm.refinement import FixedPatch2D, prepare_fine_boundary
|
||||
@@ -133,7 +138,7 @@ def host_geometry(source, h):
|
||||
from CelerisLab.body.geometry.circle import CircleGeometry
|
||||
from CelerisLab.body.objects import SimObject
|
||||
|
||||
cfgdict, _, _ = config(h, 40)
|
||||
cfgdict, _, _ = config(h, 40, collision)
|
||||
with TemporaryDirectory() as tmp:
|
||||
p = Path(tmp) / "cfg.json"
|
||||
p.write_text(json.dumps(cfgdict))
|
||||
@@ -151,8 +156,11 @@ def host_geometry(source, h):
|
||||
return cfg, pair, body, host
|
||||
|
||||
|
||||
def verify_source(source):
|
||||
expected = json.loads((HERE / "data/refined_dfg/source_manifest.json").read_text())
|
||||
def verify_source(source, collision="SRT"):
|
||||
if collision not in ("SRT", "MRT"):
|
||||
raise ValueError("Matched collision must be SRT or MRT")
|
||||
name = "source_manifest.json" if collision == "SRT" else "source_manifest_mrt.json"
|
||||
expected = json.loads((HERE / "data/refined_dfg" / name).read_text())
|
||||
for name, digest in expected["sha256"].items():
|
||||
if hashlib.sha256((source / name).read_bytes()).hexdigest() != digest:
|
||||
raise RuntimeError("Source mismatch: " + name)
|
||||
@@ -167,7 +175,7 @@ def run_case(a, h, periodic, case):
|
||||
from contextlib import ExitStack
|
||||
|
||||
refined = case == "refined"
|
||||
cfgdict, bodydict, p = config(h, 40 if refined else 80)
|
||||
cfgdict, bodydict, p = config(h, 40 if refined else 80, a.collision)
|
||||
cap = 5.0 if a.mode == "pilot" else 300.0
|
||||
max_steps = math.ceil(cap * p["diameter"] / SPEED)
|
||||
rows = []
|
||||
@@ -179,7 +187,7 @@ def run_case(a, h, periodic, case):
|
||||
dest.mkdir()
|
||||
with ExitStack() as stack:
|
||||
if refined:
|
||||
cfg, pair, body, host = host_geometry(a.source, h)
|
||||
cfg, pair, body, host = host_geometry(a.source, h, a.collision)
|
||||
context = stack.enter_context(CudaContext(0))
|
||||
backend = stack.enter_context(
|
||||
FixedPatchStepper(
|
||||
@@ -336,6 +344,8 @@ def run_case(a, h, periodic, case):
|
||||
if len(rows) == 1:
|
||||
ready = dict(
|
||||
case=case,
|
||||
collision=a.collision,
|
||||
**a.provenance,
|
||||
mode=a.mode,
|
||||
step=begin,
|
||||
tstar=row["tstar"],
|
||||
@@ -348,6 +358,8 @@ def run_case(a, h, periodic, case):
|
||||
print("READY " + json.dumps(ready, allow_nan=False), flush=True)
|
||||
result = dict(
|
||||
case=case,
|
||||
collision=a.collision,
|
||||
**a.provenance,
|
||||
mode=a.mode,
|
||||
history=rows,
|
||||
healthy=bool(healthy),
|
||||
@@ -416,12 +428,14 @@ def check_deadline(deadline):
|
||||
)
|
||||
|
||||
|
||||
def verify_pilot(path, manifest):
|
||||
def verify_pilot(path, manifest, collision="SRT"):
|
||||
if path is None:
|
||||
raise ValueError(
|
||||
"Full comparison requires --pilot-results from a completed matched pilot"
|
||||
)
|
||||
previous = read_finite_json(path / "plan.json")
|
||||
if previous.get("collision") != collision:
|
||||
raise ValueError("Pilot collision differs")
|
||||
if previous["source_manifest"] != manifest or previous["bounds_root_edge"] != list(
|
||||
BOUNDS
|
||||
):
|
||||
@@ -432,7 +446,8 @@ def verify_pilot(path, manifest):
|
||||
for case, diameter in (("uniform", 80), ("refined", 40)):
|
||||
summary = read_finite_json(path / case / "summary.json")
|
||||
if (
|
||||
summary.get("case") != case
|
||||
summary.get("collision") != collision
|
||||
or summary.get("case") != case
|
||||
or summary.get("mode") != "pilot"
|
||||
or summary.get("status") != "pilot_complete"
|
||||
or summary.get("healthy") is not True
|
||||
@@ -483,7 +498,8 @@ def verify_pilot(path, manifest):
|
||||
raise ValueError("Unhealthy pilot observations")
|
||||
ready = read_finite_json(path / case / "ready.json")
|
||||
if (
|
||||
ready.get("case") != case
|
||||
ready.get("collision") != collision
|
||||
or ready.get("case") != case
|
||||
or ready.get("mode") != "pilot"
|
||||
or ready.get("step") != interval
|
||||
or ready.get("runner_sha256") != runner_hash()
|
||||
@@ -507,6 +523,7 @@ def verify_pilot(path, manifest):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--collision", choices=["SRT", "MRT"], default="SRT")
|
||||
parser.add_argument("--source", type=Path, default=DEFAULT_SOURCE)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--mode", choices=["plan", "pilot", "full"], default="plan")
|
||||
@@ -519,9 +536,15 @@ def main():
|
||||
)
|
||||
a = parser.parse_args()
|
||||
a.source = a.source.resolve()
|
||||
manifest = verify_source(a.source)
|
||||
manifest = verify_source(a.source, a.collision)
|
||||
h, periodic = helpers(a.source)
|
||||
calibration = verify_pilot(a.pilot_results, manifest) if a.mode == "full" else None
|
||||
from source_provenance import checkout_provenance
|
||||
|
||||
a.provenance = checkout_provenance(a.source)
|
||||
calibration = (
|
||||
verify_pilot(a.pilot_results, manifest, a.collision)
|
||||
if a.mode == "full" else None
|
||||
)
|
||||
if a.mode != "plan" and (
|
||||
a.max_wall_seconds is None
|
||||
or not math.isfinite(a.max_wall_seconds)
|
||||
@@ -536,16 +559,17 @@ def main():
|
||||
if a.output.exists() and any(a.output.iterdir()):
|
||||
raise ValueError("Output must be empty/new")
|
||||
a.output.mkdir(parents=True, exist_ok=True)
|
||||
specification = plan(h)
|
||||
specification = plan(h, a.collision)
|
||||
specification.update(
|
||||
source_manifest=manifest,
|
||||
**a.provenance,
|
||||
gates=periodic.GATES,
|
||||
reference_gates=periodic.REFERENCE_GATES,
|
||||
runner_sha256=runner_hash(),
|
||||
wall_time_budget_seconds=budget,
|
||||
full_pilot_calibration_seconds=calibration,
|
||||
)
|
||||
host_geometry(a.source, h)
|
||||
host_geometry(a.source, h, a.collision)
|
||||
(a.output / "plan.json").write_text(json.dumps(specification, indent=2))
|
||||
if a.mode == "plan":
|
||||
return 0
|
||||
@@ -561,6 +585,8 @@ def main():
|
||||
except TimeoutError as exc:
|
||||
failure = dict(
|
||||
status="wall_time_limit",
|
||||
collision=a.collision,
|
||||
**a.provenance,
|
||||
case=case,
|
||||
matched_case_pass=False,
|
||||
error=str(exc),
|
||||
@@ -574,6 +600,8 @@ def main():
|
||||
if not result["healthy"]:
|
||||
break
|
||||
comparison = dict(
|
||||
collision=a.collision,
|
||||
**a.provenance,
|
||||
status="pilot_only" if a.mode == "pilot" else "incomplete",
|
||||
matched_case_pass=False,
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user