Retired with the dense refinement route (results recorded at1573942and2469af7or named as accepted losses): - test_refinement_blocked_base: BlockedBaseGPU exact parity (3 tests), DenseBlockedRouteParity (6 tests incl. MRT and two bodies), DenseBlockedRouteCPU (capability matrix, ledger comparator); - test_refinement_blocked_fine: BlockedFineGPU dense-vs-blocked (3 tests); - test_refinement_mrt_gpu: test_dense_versus_blocked_mrt_two_level; - test_raw_exchange_gpu: test_dense_fine_storage_reference (private link_exchange cut-link oracle, accepted loss); - test_refinement_gpu: test_bounded_equivalence_and_ownership (dense CELERIS_REFINEMENT_AUDIT ownership counters, accepted loss); its physics stays in test_bounded_equivalence_blocked; eight_steps loses the audit branch and the misleading 'ownership/counts PASS' label; - test_fine_surface_gpu: test_fine_surface_four_hops (dense per-hop flux ledger, CurvedLinkSoA reflection oracle, audit counts: accepted losses; raw exchange covers the boundary part only, not full flux closure) and the dense SoA fault tests (missing surface buffer, close frees SoA); blocked equivalents remain in test_refinement_blocked_fine/_base; - test_raw_exchange.test_dense_observation_rejected_before_device_access. New TileContractCPU: level_blocks omitted/None/wrong length/None entry/ wrong arity/non-integer/bool/non-positive/non-tuple/not dividing all raise before CUDA; whole-level tiles reach CUDA. Rejection tests and fixtures pass tiles; launch-order and kernel-text tests follow the blocked root; examples/fixed_periodic_patch uses whole-level tiles (+ host tile test). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
3.5 KiB
Python
71 lines
3.5 KiB
Python
"""The public examples run all-blocked: their level tiles must reach the device unchanged.
|
|
|
|
Host only: a context whose activation raises proves construction (layouts, tables,
|
|
boundary checks) succeeded up to the first CUDA call.
|
|
"""
|
|
import ast
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
import unittest
|
|
from unittest.mock import Mock
|
|
|
|
from CelerisLab.body.geometry.circle import CircleGeometry
|
|
from CelerisLab.body.objects import SimObject
|
|
from CelerisLab.config import LBMConfig
|
|
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
|
|
|
|
EXAMPLES = Path(__file__).resolve().parents[2] / "examples"
|
|
|
|
|
|
def literal(name, constant):
|
|
"""Module-level literal from an example, read without importing it (no pycuda)."""
|
|
tree = ast.parse((EXAMPLES / name).read_text())
|
|
for node in tree.body:
|
|
if isinstance(node, ast.Assign):
|
|
for target in node.targets:
|
|
names = target.elts if isinstance(target, ast.Tuple) else [target]
|
|
for i, t in enumerate(names):
|
|
if isinstance(t, ast.Name) and t.id == constant:
|
|
value = node.value.elts[i] if isinstance(target, ast.Tuple) else node.value
|
|
return ast.literal_eval(value)
|
|
raise KeyError(constant)
|
|
|
|
|
|
def forbidden():
|
|
return Mock(activate=Mock(side_effect=AssertionError("CUDA reached")), sm_arch="sm_70")
|
|
|
|
|
|
class ExampleTiles(unittest.TestCase):
|
|
def test_fixed_patch_jet_tiles(self):
|
|
bounds, blocks = literal("fixed_patch_jet.py", "BOUNDS"), literal("fixed_patch_jet.py", "LEVEL_BLOCKS")
|
|
width, amplitude = literal("fixed_patch_jet.py", "WIDTH"), literal("fixed_patch_jet.py", "AMPLITUDE")
|
|
cfg = LBMConfig(nx=48, ny=48, viscosity=.1, velocity=0., wall_slot_width=width,
|
|
wall_normal_velocity=amplitude, y_wall_bc="on_site_velocity",
|
|
top_wall_bc="reservoir")
|
|
with self.assertRaisesRegex(AssertionError, "CUDA reached"):
|
|
FixedPatchStepper(cfg, context=forbidden(), coarse_boundary="slot_reservoir",
|
|
refinements=[bounds], level_blocks=[tuple(b) for b in blocks])
|
|
|
|
def test_fixed_periodic_patch_tiles(self):
|
|
with self.assertRaisesRegex(AssertionError, "CUDA reached"):
|
|
FixedPatchStepper(LBMConfig(nx=16, ny=16, viscosity=.1, velocity=1e-3), context=forbidden(),
|
|
refinements=[(4, 4, 12, 12)], level_blocks=[(16, 16), (24, 24)])
|
|
|
|
def test_fixed_patch_circle_default_tiles(self):
|
|
bounds = literal("fixed_patch_circle.py", "BOUNDS")
|
|
nx, ny = literal("fixed_patch_circle.py", "NX"), literal("fixed_patch_circle.py", "NY")
|
|
center, radius = literal("fixed_patch_circle.py", "CENTER"), literal("fixed_patch_circle.py", "RADIUS")
|
|
body = SimObject(0, geometry=CircleGeometry(*center, radius), center=center, radius=radius)
|
|
periodic = LBMConfig(nx=nx, ny=ny, viscosity=.1)
|
|
slot = replace(periodic, velocity=0, wall_normal_velocity=.001, wall_slot_width=8,
|
|
y_wall_bc="on_site_velocity", top_wall_bc="reservoir")
|
|
for mode, cfg in (("periodic", periodic), ("slot_reservoir", slot)):
|
|
with self.subTest(mode=mode), self.assertRaisesRegex(AssertionError, "CUDA reached"):
|
|
FixedPatchStepper(cfg, context=forbidden(), coarse_boundary=mode,
|
|
refinements=[bounds], level_blocks=[(12, 8), (16, 20)],
|
|
level_objects=[(), (body,)])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|