From 1a274817cddd0c61a7b6a27a9e77bcabf89526c8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 04:45:57 +0000 Subject: [PATCH] Test: Astra's actuated seam fixture (angle 0.7, half-width 0.85) Asserts 21 aperture links, all with nonzero velocity, and 3 halo-writer plus 2 halo-donor aperture rows in each decomposed layout (actuation coverage across seams, not only geometric cut-link coverage). Velocity is given in coarse units; prepare_fine_boundary scales it once. The GPU gate remains storage equivalence; no zero-mass-change claim. Co-Authored-By: Claude Opus 5.5 --- .../multigrid/test_refinement_blocked_fine.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/validation/multigrid/test_refinement_blocked_fine.py b/tests/validation/multigrid/test_refinement_blocked_fine.py index 95876a8..7f65274 100644 --- a/tests/validation/multigrid/test_refinement_blocked_fine.py +++ b/tests/validation/multigrid/test_refinement_blocked_fine.py @@ -55,8 +55,10 @@ def circle(spec=None): def actuation(speed): - """Aperture centred on +x: hits links straddling the horizontal y 15|16 seam.""" - return SurfaceActuation(0.0, 0.6, speed) + """Astra's seam fixture: 21 aperture links; in each decomposed layout 3 of them + write a halo image and 2 read a q<.5 donor from a halo. Coarse lattice units: + prepare_fine_boundary does the (acoustic) fine scaling, never scale twice.""" + return SurfaceActuation(0.7, 0.85, speed) def fine_circle(mode, spec=None): @@ -233,16 +235,20 @@ class BlockedFineCPU(unittest.TestCase): np.testing.assert_array_equal(aperture, soa.aperture) self.assertEqual(curved_links.surface_link_velocity( (circle(),), cfg, boundary.flags, fluid_idx, dirs, body_id, rx, ry), (None, None)) - # The aperture must actually cross a block seam in both decomposed layouts. + # Actuated (not just geometric) seam coverage in both decomposed layouts. + self.assertEqual(int(aperture.sum()), 21, mode) + self.assertTrue(np.all(np.any(velocity[aperture] != 0, axis=1)), mode) for by, bx in FINE_BLOCKS[1:]: layout = BlockLayout2D.build(*patch.fine_shape, by, bx, periodic=(False, False)) _, mapped = blocked_link_tables(layout, boundary.flags, fluid_idx, dirs, boundary.curved_host[2], boundary.curved_host[7]) L = int(np.prod(layout.local_shape)) core = set(layout.owner.ravel().tolist()) - seam = [int(w) // (9 * L) * L + int(w) % L not in core for w in mapped.write] - self.assertTrue(np.any(np.array(seam) & aperture & np.any(velocity != 0, axis=1)), - (mode, by, bx)) + halo_write = np.array([int(w) // (9 * L) * L + int(w) % L not in core + for w in mapped.write]) + halo_donor = np.array([d != NO_DONOR and int(d) not in core for d in mapped.donor]) + self.assertEqual((int((halo_write & aperture).sum()), + int((halo_donor & aperture).sum())), (3, 2), (mode, by, bx)) def test_tables_map_back_to_dense_slots_in_order(self): patch = FixedPatch2D.from_config(config("periodic"), BOUNDS)