test(D1): exchange, Jet and fine-surface checks run on all-blocked storage
- test_exchange_window and test_raw_exchange_gpu fine(): dense root becomes a (12, 8) blocked root (fine(None) stays only for the dense reference test that D2 retires); - jets: G1/G3 compare blocked layouts against the FINE_BLOCKS[0] reference (blocked root); the dense run is a separate leg D2 removes; G2 legacy actuation vs Jet on the blocked reference; CPU fixtures use a blocked root; - test_refinement_blocked_fine.raw reads every level through its layout; - test_fine_surface_gpu: new test_fine_surface_blocked_matches_uniform_four_hops (fine ROI after each of four hops vs the uniform 48^2 solver with the same tolerances, blowing/suction mass sign from raw exchange, zero actuation == passive bit for bit); the cross-interface donor rejection passes tiles. The dense hook/ledger/audit probes in test_fine_surface_four_hops and the dense SoA fault tests stay until D2 retires them by name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
452eaf32de
commit
104f74632f
@@ -3,11 +3,13 @@
|
||||
Jets use the same coarse cell-edge frame as fine_objects. The equivalent jet
|
||||
of Astra's actuated fixture is SurfaceActuation(0.7, 0.85, U).as_jet((16, 12),
|
||||
2.15). Frozen GPU gates (8 coarse steps, both coarse boundary modes):
|
||||
G1 jet run: dense vs 1x1/2x2/4x2 fine blocks bit-identical (values + NaN masks);
|
||||
G2 jet vs legacy actuation (dense): max |dG| over finite fine ACTIVE fluid
|
||||
G1 jet run: 1x1/2x2/4x2 fine blocks (blocked (12, 8) root) bit-identical to the
|
||||
FINE_BLOCKS[0] reference (values + NaN masks); dense leg kept until dense retirement;
|
||||
G2 jet vs legacy actuation (blocked reference): max |dG| over finite fine ACTIVE fluid
|
||||
populations <= 1e-6 (velocity rows differ only by FP32 rounding; reported);
|
||||
G3 amplitude change after 4 steps (+U -> -U), 4 more steps: dense vs blocked
|
||||
bit-identical and the run differs from the unchanged run.
|
||||
G3 amplitude change after 4 steps (+U -> -U), 4 more steps: blocked layouts
|
||||
bit-identical to the FINE_BLOCKS[0] reference (dense leg until retirement) and the
|
||||
run differs from the unchanged run.
|
||||
"""
|
||||
from contextlib import nullcontext
|
||||
import unittest
|
||||
@@ -26,6 +28,11 @@ from test_refinement_blocked_fine import (BOUNDS, FINE_BLOCKS, NX, NY, STEPS, ac
|
||||
SPEED = .002
|
||||
|
||||
|
||||
def root_and(fine_block):
|
||||
"""All-blocked levels with a (12, 8) root tile; fine_block None is the dense route."""
|
||||
return [None if fine_block is None else (12, 8), fine_block]
|
||||
|
||||
|
||||
def jet(speed=SPEED):
|
||||
return actuation(speed).as_jet((16.0, 12.0), 2.15)
|
||||
|
||||
@@ -42,7 +49,7 @@ def mocked(objects, jets, fine_block):
|
||||
patch.object(cuda, "mem_alloc", side_effect=lambda size: Mock()), \
|
||||
patch.object(cuda, "memcpy_htod", htod):
|
||||
backend = FixedPatchStepper(config("periodic"), context=context, refinements=[BOUNDS],
|
||||
level_blocks=[None, fine_block], level_objects=[(), tuple(objects)],
|
||||
level_blocks=root_and(fine_block), level_objects=[(), tuple(objects)],
|
||||
level_jets=[(), tuple(jets)])
|
||||
return backend, htod
|
||||
|
||||
@@ -161,7 +168,7 @@ def run(mode, fine_block, *, objects, jets, switch=None):
|
||||
patch_ = FixedPatch2D.from_config(cfg, BOUNDS)
|
||||
with CudaContext(0) as context, FixedPatchStepper(
|
||||
cfg, context=context, coarse_boundary=mode, refinements=[BOUNDS],
|
||||
level_blocks=[None, fine_block], level_objects=[(), tuple(objects)],
|
||||
level_blocks=root_and(fine_block), level_objects=[(), tuple(objects)],
|
||||
level_jets=[(), tuple(jets)]) as backend:
|
||||
backend.initialize(state(NY, NX, 1), state(*patch_.fine_shape, 2))
|
||||
if switch is None:
|
||||
@@ -179,29 +186,32 @@ class JetStepperGPU(unittest.TestCase):
|
||||
patch_, boundary = fine_circle(mode)
|
||||
fluid = (patch_.fine_kind == ACTIVE) & (
|
||||
(boundary.flags.reshape(patch_.fine_shape) & SOLID) == 0)
|
||||
dense = run(mode, None, objects=[circle()], jets=[jet()])
|
||||
self.assertTrue(np.isfinite(dense[1][1][:, fluid]).all(), mode)
|
||||
for fine_block in FINE_BLOCKS:
|
||||
reference = run(mode, FINE_BLOCKS[0], objects=[circle()], jets=[jet()])
|
||||
self.assertTrue(np.isfinite(reference[1][1][:, fluid]).all(), mode)
|
||||
for fine_block in FINE_BLOCKS[1:]:
|
||||
public, raw_arrays = run(mode, fine_block, objects=[circle()], jets=[jet()])
|
||||
for a, b in zip(public + tuple(raw_arrays), dense[0] + tuple(dense[1])):
|
||||
for a, b in zip(public + tuple(raw_arrays), reference[0] + tuple(reference[1])):
|
||||
np.testing.assert_array_equal(a, b, err_msg=f"G1 {mode} {fine_block}")
|
||||
legacy = run(mode, None, objects=[circle(actuation(SPEED))], jets=())
|
||||
diff = np.abs(dense[1][1][:, fluid] - legacy[1][1][:, fluid]).max()
|
||||
dense = run(mode, None, objects=[circle()], jets=[jet()]) # dense leg (D2 retires)
|
||||
for a, b in zip(dense[0] + tuple(dense[1]), reference[0] + tuple(reference[1])):
|
||||
np.testing.assert_array_equal(a, b, err_msg=f"G1 {mode} dense")
|
||||
legacy = run(mode, FINE_BLOCKS[0], objects=[circle(actuation(SPEED))], jets=())
|
||||
diff = np.abs(reference[1][1][:, fluid] - legacy[1][1][:, fluid]).max()
|
||||
print(f"G2 {mode}: jet vs legacy fine max |dG| = {diff:.3e}", flush=True)
|
||||
self.assertLessEqual(diff, 1e-6, mode)
|
||||
|
||||
def test_g3_amplitude_switch_layouts_identical(self):
|
||||
for mode in ("periodic", "slot_reservoir"):
|
||||
dense = run(mode, None, objects=[circle()], jets=[jet()], switch=-SPEED)
|
||||
steady = run(mode, None, objects=[circle()], jets=[jet()])
|
||||
self.assertFalse(np.array_equal(dense[1][1], steady[1][1], equal_nan=True), mode)
|
||||
for fine_block in FINE_BLOCKS:
|
||||
reference = run(mode, FINE_BLOCKS[0], objects=[circle()], jets=[jet()], switch=-SPEED)
|
||||
steady = run(mode, FINE_BLOCKS[0], objects=[circle()], jets=[jet()])
|
||||
self.assertFalse(np.array_equal(reference[1][1], steady[1][1], equal_nan=True), mode)
|
||||
for fine_block in (*FINE_BLOCKS[1:], None): # None: dense leg (D2 retires)
|
||||
public, raw_arrays = run(mode, fine_block, objects=[circle()], jets=[jet()],
|
||||
switch=-SPEED)
|
||||
for a, b in zip(public + tuple(raw_arrays), dense[0] + tuple(dense[1])):
|
||||
for a, b in zip(public + tuple(raw_arrays), reference[0] + tuple(reference[1])):
|
||||
np.testing.assert_array_equal(a, b, err_msg=f"G3 {mode} {fine_block}")
|
||||
print(f"G3 {mode}: amplitude switch dense vs {len(FINE_BLOCKS)} layouts identical",
|
||||
flush=True)
|
||||
print(f"G3 {mode}: amplitude switch, {len(FINE_BLOCKS) - 1} layouts + dense "
|
||||
f"identical to {FINE_BLOCKS[0]}", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user