From b4692e6ec483d952cdfff50e604de74967361482 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 19 Oct 2026 08:50:34 -0700 Subject: [PATCH] test: select single-case resolution and compact refinement --- docs/validation/refined_dfg_window.md | 20 +++++ tests/unit/test_refined_dfg.py | 65 +++++++++++++- tests/validation/run_refined_dfg.py | 122 ++++++++++++++++++-------- 3 files changed, 166 insertions(+), 41 deletions(-) diff --git a/docs/validation/refined_dfg_window.md b/docs/validation/refined_dfg_window.md index 2e04fa6..6eedb17 100644 --- a/docs/validation/refined_dfg_window.md +++ b/docs/validation/refined_dfg_window.md @@ -95,3 +95,23 @@ retains the two-cell face-gradient stencils. No fields or per-link arrays are sa `cv_observation_seconds` is the CV portion of observation/overhead time. Helper hash and the observation flag must match pilot/full. Time integration, temporal coarsening and any physical assessment remain separate offline work. + +## Bounded resolution and placement controls + +Defaults remain `--case both --uniform-diameter 80 --placement wide`. Single-case +runs use `--case uniform` or `--case refined` and never report a matched-case pass. +Their own reference/periodicity or driven-diagnostic results remain available. +A single zero-Jet full run exits successfully only when its periodicity and the +unchanged complete DFG reference verdict pass; driven completion is not qualification. + +The D160 option requires `--case uniform --uniform-diameter 160` and an explicit +public Jet scenario. U and Jet speeds stay .01 and ±.001; viscosity is .016, +grid 3521×658, center (320,320.5), radius80. CV uses root spacing/time factor .25, +origin (.375,.75), impulse factor .0625, root viscosity .004, and x-face shift .125. + +`--case refined --placement compact` selects root bounds (48,48,128,128), fine +168×168 and origin (46,46), with the same D40/fineD80 body/Jet resolution. Its CV +contours are (52,52,112,112) and (50,50,120,120); complete face-gradient stencils +are clear of both solids and the transfer footprint. Compact is refined-only. +CV metadata gives each grid's spacing/origin/contours explicitly. Case, uniform +diameter and placement must match the newly completed pilot in every receipt. diff --git a/tests/unit/test_refined_dfg.py b/tests/unit/test_refined_dfg.py index 818e432..dd49fed 100644 --- a/tests/unit/test_refined_dfg.py +++ b/tests/unit/test_refined_dfg.py @@ -146,24 +146,26 @@ def test_full_requires_completed_pilot(): r.verify_pilot(None, r.verify_source(r.DEFAULT_SOURCE, "MRT", "window")) -def pilot_fixture(path, observation_mode="window", jet_scenario="none"): +def pilot_fixture(path, observation_mode="window", jet_scenario="none", case_selection="both", uniform_diameter=80, placement="wide"): """Synthetic contract fixture only; never a physical result or run receipt.""" manifest = (r.verify_source(r.DEFAULT_SOURCE, "MRT", "window", jet_scenario) if observation_mode == "window" else json.loads((r.HERE / "data/refined_dfg/source_manifest_mrt.json").read_text())) + selection = dict(case_selection=case_selection, uniform_diameter=uniform_diameter, placement=placement) (path / "plan.json").write_text( json.dumps( dict( source_manifest=manifest, + **selection, collision="MRT", jet_scenario=jet_scenario, observation_mode=observation_mode, - bounds_root_edge=list(r.BOUNDS), + bounds_root_edge=list(r.PLACEMENTS[placement]), runner_sha256=r.runner_hash(), ) ) ) - for case, diameter in (("uniform", 80), ("refined", 40)): + for case, diameter in r.selected_cases(case_selection, uniform_diameter): dest = path / case dest.mkdir() interval = round(0.02 * diameter / r.SPEED) @@ -190,6 +192,7 @@ def pilot_fixture(path, observation_mode="window", jet_scenario="none"): json.dumps( dict( case=case, + **selection, collision="MRT", jet_scenario=jet_scenario, observation_mode=observation_mode, @@ -208,6 +211,7 @@ def pilot_fixture(path, observation_mode="window", jet_scenario="none"): json.dumps( dict( case=case, + **selection, collision="MRT", jet_scenario=jet_scenario, observation_mode=observation_mode, @@ -526,6 +530,7 @@ def test_cv_snapshot_common_units_and_window_endpoints(): for refined, shape, origin, diameter, impulse in ( (True, (240, 568), (38., 22.), 40, [4., -8.]), (False, (330, 1761), (.25, .5), 80, [16., -32.]), + (False, (658, 3521), (.375, .75), 160, [64., -128.]), ): rho, ux, uy, fluid = np.ones(shape), np.full(shape, .01), np.zeros(shape), np.ones(shape, bool) begin, n = round(290*diameter/r.SPEED), round(.02*diameter/r.SPEED) @@ -538,7 +543,8 @@ def test_cv_snapshot_common_units_and_window_endpoints(): assert r.cv_selected(n, diameter, "pilot") assert sum(r.cv_selected(step, diameter, "full") for step in range(begin-n, end+n+1, n)) == 501 for key in ("time_root", "interval_start_root", "interval_dt_root", "interval_impulse_root", "inventory"): - np.testing.assert_allclose(records[0][key], records[1][key], rtol=0, atol=1e-10) + for record in records[1:]: + np.testing.assert_allclose(records[0][key], record[key], rtol=0, atol=1e-10) assert records[0]["interval_dt_root"] == 80 and np.isclose(records[0]["tstar"], 290.02) np.testing.assert_array_equal(records[0]["interval_impulse_root"], [4, -8]) @@ -564,6 +570,57 @@ def test_cv_pilot_mode_and_helper_provenance(): assert r.verify_pilot(path, manifest, "MRT", "window", "fixed", True) == 3606 +def test_compact_geometry_and_cv_stencils(): + from CelerisLab.lbm.refinement import ACTIVE + from CelerisLab.lbm.descriptors import SOLID + + _, pair, _, host = r.host_geometry(r.DEFAULT_SOURCE, h, "MRT", "fixed", "compact") + assert pair.fine_shape == (168, 168) and tuple(pair.fine_origin) == (46, 46) + fluid = (pair.fine_kind == ACTIVE) & ((host.flags.reshape(pair.fine_shape) & SOLID) == 0) + rho, ux, uy = np.ones(pair.fine_shape), np.full(pair.fine_shape, .01), np.zeros(pair.fine_shape) + record = r.cv_snapshot(rho, ux, uy, fluid, pair.fine_origin, True, 1160000, 80, 40, [1, 2], "compact") + np.testing.assert_allclose(record["outward_flux"], 0, atol=1e-12) + stencil = np.zeros(pair.fine_shape, bool) + for rect in r.cv_contours(True, 40, "compact"): + x0, y0, x1, y1 = np.rint((rect - np.tile(pair.fine_origin, 2))/.5).astype(int) + stencil[y0-2:y1+2, x0-2:x0+2] = stencil[y0-2:y1+2, x1-2:x1+2] = True + stencil[y0-2:y0+2, x0-2:x1+2] = stencil[y1-2:y1+2, x0-2:x1+2] = True + assert fluid[stencil].all() and not stencil.ravel()[host.transfer_fine_cells].any() + + +def test_d160_config_and_single_case_receipts(): + from tempfile import TemporaryDirectory + from unittest.mock import patch + + cfg, _, p = r.config(h, 160, "MRT", "fixed") + assert (p["nx"], p["ny"], p["center"], p["radius"]) == (3521, 658, [320, 320.5], 80) + assert p["viscosity"] == .016 and p["mean_speed"] == .01 and not cfg["method"]["ddf_shifting"] + assert r.uniform_origin(160) == (.375, .75) + np.testing.assert_array_equal(r.cv_contours(False, 160), r.CV_CONTOURS + [.125, 0, .125, 0]) + for scenario, expected_exit in (("fixed", 0), ("zero", 2)): + with TemporaryDirectory() as tmp: + path = Path(tmp) + manifest = pilot_fixture(path, jet_scenario=scenario, case_selection="uniform", uniform_diameter=160) + assert r.verify_pilot(path, manifest, "MRT", "window", scenario, False, "uniform", 160) == 1803 + for selection, diameter, placement in (("both", 160, "wide"), ("uniform", 80, "wide"), ("uniform", 160, "compact")): + with unittest.TestCase().assertRaises(ValueError): + r.verify_pilot(path, manifest, "MRT", "window", scenario, False, selection, diameter, placement) + # Synthetic dispatch/result check: no CUDA imports or execution. + output = path / "full" + argv = ["runner", "--collision", "MRT", "--exchange-window", "--jet-scenario", scenario, + "--case", "uniform", "--uniform-diameter", "160", "--mode", "full", + "--pilot-results", str(path), "--output", str(output), "--max-wall-seconds", "10", "--gpu-gates-approved"] + result = dict(case="uniform", healthy=True, periodic=scenario == "zero", jet_diagnostic_windows=[], + status="driven_diagnostics_complete" if scenario == "fixed" else "periodic", + reference_comparison=dict(reference_agreement=False)) + with patch.object(sys, "argv", argv), patch.dict(r.os.environ, CUDA_VISIBLE_DEVICES="mock-no-gpu"), \ + patch.object(r, "run_case", return_value=result) as run: + assert r.main() == expected_exit and run.call_count == 1 + comparison = json.loads((output / "comparison.json").read_text()) + assert comparison["matched_case_pass"] is False and "refined_vs_uniform" not in comparison + assert comparison["status"].startswith("single_case_") + + if __name__ == "__main__": suite = unittest.TestSuite( unittest.FunctionTestCase(fn) diff --git a/tests/validation/run_refined_dfg.py b/tests/validation/run_refined_dfg.py index ac8f59c..d4dea16 100644 --- a/tests/validation/run_refined_dfg.py +++ b/tests/validation/run_refined_dfg.py @@ -17,30 +17,48 @@ HERE = Path(__file__).resolve().parent DEFAULT_SOURCE = HERE.parents[1] BOUNDS = (40, 24, 320, 140) BASE_BLOCK = (2, 881) # Exact 166 x 881 domain; no geometric padding. -FINE_BLOCK = (8, 8) # 240 x 568 including four fine halo cells. +FINE_BLOCK = (8, 8) # Wide 240 x 568 or compact 168 x 168, including fine halos. SPEED = 0.01 JET_PEAK = 0.001 JET_WINDOWS = [(t, t + 10) for t in range(250, 300, 10)] CV_CONTOURS = np.array([(48., 44., 160., 120.), (44., 36., 180., 128.)]) +PLACEMENTS = {"wide": BOUNDS, "compact": (48, 48, 128, 128)} +COMPACT_CV_CONTOURS = np.array([(52., 52., 112., 112.), (50., 50., 120., 120.)]) + + +def selected_cases(selection="both", uniform_diameter=80): + return [(case, diameter) for case, diameter in (("uniform", uniform_diameter), ("refined", 40)) + if selection in ("both", case)] + + +def uniform_origin(diameter): + h = 40 / diameter + return (.5 - .5*h, 1 - h) + + +def cv_contours(refined, diameter, placement="wide"): + contours = CV_CONTOURS if placement == "wide" else COMPACT_CV_CONTOURS + return contours if refined else contours + [20/diameter, 0., 20/diameter, 0.] def cv_selected(step, diameter, mode): return mode == "pilot" or round(290 * diameter / SPEED) <= step <= round(300 * diameter / SPEED) -def cv_snapshot(rho, ux, uy, fluid, origin, refined, begin, n, diameter, impulse): +def cv_snapshot(rho, ux, uy, fluid, origin, refined, begin, n, diameter, impulse, placement="wide"): """Cropped public macros only; all inventories, fluxes and impulses use root units.""" from run_jet_circle_cv import cv_from_macros - rectangles = CV_CONTOURS + (0 if refined else np.array([.25, 0., .25, 0.])) + rectangles = cv_contours(refined, diameter, placement) + h_cell = .5 if refined else 40 / diameter origin = np.asarray(origin, dtype=float) - x0, y0, x1, y1 = np.rint((rectangles[-1] - np.tile(origin, 2)) / .5).astype(int) + x0, y0, x1, y1 = np.rint((rectangles[-1] - np.tile(origin, 2)) / h_cell).astype(int) selection = np.s_[y0-2:y1+2, x0-2:x1+2] - cropped_origin = origin + .5 * np.array([x0-2, y0-2]) + cropped_origin = origin + h_cell * np.array([x0-2, y0-2]) fields = [v[selection] for v in (rho, ux, uy, fluid)] - values = [cv_from_macros(*fields, cropped_origin, rect, .004, h=.5) + values = [cv_from_macros(*fields, cropped_origin, rect, .004, h=h_cell) for rect in rectangles] - h_native = 1.0 if refined else .5 + h_native = 1.0 if refined else 40 / diameter return dict(step=begin+n, tstar=(begin+n)*SPEED/diameter, time_root=(begin+n)*h_native, interval_start_root=begin*h_native, interval_dt_root=n*h_native, @@ -132,10 +150,11 @@ def config(h, diameter, collision="SRT", jet_scenario="none"): return cfg, body, p -def plan(h, collision="SRT", observation_mode="last_base_step", jet_scenario="none"): +def plan(h, collision="SRT", observation_mode="last_base_step", jet_scenario="none", uniform_diameter=80, placement="wide"): _, _, c = config(h, 40, collision, jet_scenario) - _, _, f = config(h, 80, collision, jet_scenario) - x0, y0, x1, y1 = BOUNDS + _, _, f = config(h, uniform_diameter, collision, jet_scenario) + bounds = PLACEMENTS[placement] + x0, y0, x1, y1 = bounds fine_active = 4 * (x1 - x0) * (y1 - y0) coarse_uncovered = c["nx"] * c["ny"] - fine_active // 4 return dict( @@ -147,7 +166,8 @@ def plan(h, collision="SRT", observation_mode="last_base_step", jet_scenario="no root_gpu_gates_required=True, root=c, uniform=f, - bounds_root_edge=list(BOUNDS), + bounds_root_edge=list(bounds), + fine_origin_root_edge=[x0 - 2, y0 - 2], physical_patch_m=[ (x0 - 0.5) * c["dx"], (y0 - 1) * c["dx"], @@ -167,12 +187,14 @@ def plan(h, collision="SRT", observation_mode="last_base_step", jet_scenario="no physical_viscosity_m2_s=0.001, finest_dx_m=f["dx"], finest_dt_s=f["dt"], + refined_finest_dx_m=c["dx"]/2, + refined_finest_dt_s=c["dt"]/2, approximate_leaf_cell_ratio=(coarse_uncovered + fine_active) / (f["nx"] * f["ny"]), approximate_collision_work_ratio=(coarse_uncovered + 2 * fine_active) - / (2 * f["nx"] * f["ny"]), + / ((uniform_diameter/40) * 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.", + sampling_offset="Uniform nodes map to root edges X=.5+i*(40/D), Y=1+(j-.5)*(40/D). Refined centers are fine_origin_root_edge+(index+.5)*.5. Body, wall and source planes coincide; compare observables, not pointwise arrays.", outlet=( "SRT pressure NEQ, all nine fneq damped by .5, no backflow clamp; noncanonical DFG outlet" if collision == "SRT" else @@ -225,7 +247,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, collision="SRT", jet_scenario="none"): +def host_geometry(source, h, collision="SRT", jet_scenario="none", placement="wide"): """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 @@ -243,7 +265,7 @@ def host_geometry(source, h, collision="SRT", jet_scenario="none"): p = Path(tmp) / "cfg.json" p.write_text(json.dumps(cfgdict)) cfg = load_lbm_config(str(p)) - pair = FixedPatch2D.from_config(cfg, BOUNDS) + pair = FixedPatch2D.from_config(cfg, PLACEMENTS[placement]) layout = BlockLayout2D.build(cfg.ny, cfg.nx, *BASE_BLOCK) validate_channel_config(cfg, [BASE_BLOCK, FINE_BLOCK]) targets = blocked_base_tables(pair, layout, np.argsort(pair.coalesce_coarse))[1] @@ -341,7 +363,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, a.collision, a.jet_scenario) + cfgdict, bodydict, p = config(h, 40 if refined else a.uniform_diameter, a.collision, a.jet_scenario) cap = 5.0 if a.mode == "pilot" else (305.0 if a.jet_scenario == "reverse" else 300.0) max_steps = math.ceil(cap * p["diameter"] / SPEED) rows = [] @@ -356,12 +378,12 @@ def run_case(a, h, periodic, case): with ExitStack() as stack: cv_out = stack.enter_context((dest / "cv_history.jsonl").open("w")) if a.observe_cv else None if refined: - cfg, pair, body, host = host_geometry(a.source, h, a.collision, a.jet_scenario) + cfg, pair, body, host = host_geometry(a.source, h, a.collision, a.jet_scenario, a.placement) context = stack.enter_context(CudaContext(0)) backend = stack.enter_context( FixedPatchStepper( cfg, - BOUNDS, + PLACEMENTS[a.placement], context=context, coarse_boundary="channel", base_block=BASE_BLOCK, @@ -499,8 +521,8 @@ def run_case(a, h, periodic, case): if a.observe_cv and cv_selected(begin+n, p["diameter"], a.mode): tick = time.monotonic() record = cv_snapshot(rho, ux, uy, fluid, - pair.fine_origin if refined else (.25, .5), - refined, begin, n, p["diameter"], impulse) + pair.fine_origin if refined else uniform_origin(p["diameter"]), + refined, begin, n, p["diameter"], impulse, a.placement) cv_out.write(json.dumps(record, allow_nan=False) + "\n") cv_out.flush() cv_samples += 1 @@ -621,12 +643,16 @@ def check_deadline(deadline): ) -def verify_pilot(path, manifest, collision="SRT", observation_mode="last_base_step", jet_scenario="none", observe_cv=False): +def verify_pilot(path, manifest, collision="SRT", observation_mode="last_base_step", jet_scenario="none", observe_cv=False, + case_selection="both", uniform_diameter=80, placement="wide"): if path is None: raise ValueError( "Full comparison requires --pilot-results from a completed matched pilot" ) previous = read_finite_json(path / "plan.json") + options = dict(case_selection=(case_selection, "both"), uniform_diameter=(uniform_diameter, 80), placement=(placement, "wide")) + if any(previous.get(k, default) != expected for k, (expected, default) in options.items()): + raise ValueError("Pilot case, resolution or placement differs") if previous.get("observe_cv", False) != observe_cv: raise ValueError("Pilot CV observation mode differs") if previous.get("jet_scenario", "none") != jet_scenario: @@ -636,16 +662,17 @@ def verify_pilot(path, manifest, collision="SRT", observation_mode="last_base_st if previous.get("collision") != collision: raise ValueError("Pilot collision differs") if previous["source_manifest"] != manifest or previous["bounds_root_edge"] != list( - BOUNDS + PLACEMENTS[placement] ): raise ValueError("Pilot source or frozen geometry differs") if previous.get("runner_sha256") != runner_hash(): raise ValueError("Pilot runner differs") calibrated_seconds = 0.0 - for case, diameter in (("uniform", 80), ("refined", 40)): + for case, diameter in selected_cases(case_selection, uniform_diameter): summary = read_finite_json(path / case / "summary.json") if ( - summary.get("observe_cv", False) != observe_cv + any(summary.get(k, default) != expected for k, (expected, default) in options.items()) + or summary.get("observe_cv", False) != observe_cv or (observe_cv and summary.get("cv_samples") != 250) or summary.get("jet_scenario", "none") != jet_scenario or summary.get("observation_mode") != observation_mode @@ -701,7 +728,8 @@ def verify_pilot(path, manifest, collision="SRT", observation_mode="last_base_st raise ValueError("Unhealthy pilot observations") ready = read_finite_json(path / case / "ready.json") if ( - ready.get("observe_cv", False) != observe_cv + any(ready.get(k, default) != expected for k, (expected, default) in options.items()) + or ready.get("observe_cv", False) != observe_cv or ready.get("jet_scenario", "none") != jet_scenario or ready.get("observation_mode") != observation_mode or ready.get("collision") != collision @@ -732,6 +760,9 @@ def main(): parser.add_argument("--exchange-window", action="store_true", help="Opt in to refined window-ledger observations on the pinned candidate") parser.add_argument("--collision", choices=["SRT", "MRT"], default="SRT") + parser.add_argument("--case", choices=["both", "uniform", "refined"], default="both") + parser.add_argument("--uniform-diameter", type=int, choices=[80, 160], default=80) + parser.add_argument("--placement", choices=list(PLACEMENTS), default="wide") parser.add_argument("--jet-scenario", choices=["none", "zero", "fixed", "reverse"], default="none", help="Opt in to public unshifted MRT Jets; reverse switches at t*=300 and ends at 305") parser.add_argument("--observe-cv", action="store_true", @@ -747,6 +778,12 @@ def main(): help="Required explicit campaign wall-time ceiling for GPU execution", ) a = parser.parse_args() + if a.uniform_diameter == 160 and a.case != "uniform": + raise ValueError("D160 requires --case uniform; no matched-resolution claim") + if a.placement == "compact" and a.case != "refined": + raise ValueError("Compact placement requires --case refined") + if (a.uniform_diameter != 80 or a.placement != "wide") and a.jet_scenario == "none": + raise ValueError("Resolution/placement variants require an explicit public Jet scenario") a.source = a.source.resolve() a.observation_mode = "window" if a.exchange_window else "last_base_step" manifest = verify_source(a.source, a.collision, a.observation_mode, a.jet_scenario, a.observe_cv) @@ -755,10 +792,12 @@ def main(): a.provenance = checkout_provenance(a.source) a.provenance.update(jet_scenario=a.jet_scenario, ddf_shifting=a.jet_scenario == "none") + a.provenance.update(case_selection=a.case, uniform_diameter=a.uniform_diameter, placement=a.placement) if a.observe_cv: a.provenance["observe_cv"] = True calibration = ( - verify_pilot(a.pilot_results, manifest, a.collision, a.observation_mode, a.jet_scenario, a.observe_cv) + verify_pilot(a.pilot_results, manifest, a.collision, a.observation_mode, a.jet_scenario, a.observe_cv, + a.case, a.uniform_diameter, a.placement) if a.mode == "full" else None ) if a.mode != "plan" and ( @@ -775,7 +814,7 @@ 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, a.collision, a.observation_mode, a.jet_scenario) + specification = plan(h, a.collision, a.observation_mode, a.jet_scenario, a.uniform_diameter, a.placement) specification.update( source_manifest=manifest, **a.provenance, @@ -788,15 +827,18 @@ def main(): if a.observe_cv: specification["cv_observation"] = dict( full_tstar=[290, 300], pilot_tstar=[.02, 5], spacing_tstar=.02, - refined_contours_root=CV_CONTOURS.tolist(), - uniform_contours_root=(CV_CONTOURS + [.25, 0., .25, 0.]).tolist(), - uniform_grid_origin_root=[.25, .5], refined_grid_origin_root=[38., 22.], - cell_width_root=.5, viscosity_root=.004, components=["mass", "Px", "Py"], + refined_contours_root=cv_contours(True, 40, a.placement).tolist(), + uniform_contours_root=cv_contours(False, a.uniform_diameter, a.placement).tolist(), + uniform_grid_origin_root=uniform_origin(a.uniform_diameter), + refined_grid_origin_root=specification["fine_origin_root_edge"], + cell_width_root={"uniform": 40/a.uniform_diameter, "refined": .5}, + viscosity_root=.004, components=["mass", "Px", "Py"], units="root lattice per unit depth; outward flux per root time", interval="Impulse belongs to the interval ending at each snapshot; first retained endpoint (pilot .02, full 290) supplies initial inventory only: exclude its preceding impulse", qualification="not assessed; trapezoidal integration and time-coarsening are offline", ) - host_geometry(a.source, h, a.collision, a.jet_scenario) + if a.case != "uniform": + host_geometry(a.source, h, a.collision, a.jet_scenario, a.placement) (a.output / "plan.json").write_text(json.dumps(specification, indent=2)) if a.mode == "plan": return 0 @@ -805,8 +847,9 @@ def main(): "GPU execution blocked: root GPU gates approval and explicit device selection required" ) results = [] + cases = selected_cases(a.case, a.uniform_diameter) a.deadline = time.monotonic() + budget - for case in ("uniform", "refined"): + for case, _ in cases: try: result = run_case(a, h, periodic, case) except TimeoutError as exc: @@ -836,10 +879,10 @@ def main(): ) if a.jet_scenario in ("fixed", "reverse"): comparison.update(status=("pilot_only" if a.mode == "pilot" else "driven_diagnostics_complete") - if len(results) == 2 and all(r["healthy"] for r in results) else "invalid_state", + if len(results) == len(cases) and all(r["healthy"] for r in results) else "invalid_state", qualification="not assessed; execution completion is not physical acceptance", jet_diagnostic_windows={r["case"]: r["jet_diagnostic_windows"] for r in results}) - if len(results) == 2 and all(r["healthy"] and r["periodic"] for r in results): + if a.case == "both" and len(results) == 2 and all(r["healthy"] and r["periodic"] for r in results): comparison.update( status="periodic_comparison", refined_vs_uniform=periodic.compare( @@ -849,15 +892,20 @@ def main(): comparison["matched_case_pass"] = comparison["refined_vs_uniform"][ "reference_agreement" ] + if a.case != "both": + comparison.update(status="single_case_" + results[0]["status"], + own_reference_comparison=results[0].get("reference_comparison")) (a.output / "comparison.json").write_text( json.dumps(comparison, indent=2, allow_nan=False) ) return ( 0 - if len(results) == 2 + if len(results) == len(cases) and all(r["healthy"] for r in results) and (a.mode == "pilot" or comparison["matched_case_pass"] - or a.jet_scenario in ("fixed", "reverse")) + or a.jet_scenario in ("fixed", "reverse") + or (a.case != "both" and results[0]["periodic"] + and results[0].get("reference_comparison", {}).get("reference_agreement", False))) else 2 )