test: MRT refinement coverage and obsolete rejection fix
Remove MRT from the FixedPatch2D rejection matrix (TRT and other rejections retained); convert host MRT tests to stdlib unittest; add GPU gates for unshifted dense-vs-blocked MRT two-level roots (exact bits) and a shifted all-blocked three-level MRT smoke checking per-level omega. No numerical source change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
00d7a54829
commit
3ea131e92c
@@ -5,6 +5,7 @@ Parity compares the blocked MRT channel root with uniform MRT OneStep: the exist
|
||||
pressure-NEQ outlet branch differs by collision model, so SRT is never the reference.
|
||||
AMR checks are finite-evolution/split-invariance smoke tests, not benchmark validation.
|
||||
"""
|
||||
from dataclasses import replace
|
||||
import unittest
|
||||
import numpy as np
|
||||
|
||||
@@ -13,6 +14,7 @@ from CelerisLab.cuda.context import CudaContext
|
||||
from CelerisLab.lbm.population_storage import _encode_physical
|
||||
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
|
||||
from test_channel_root_gpu import run_root, state
|
||||
from test_refinement_blocked_base import raw, exact
|
||||
|
||||
|
||||
class RefinementMRTGPU(unittest.TestCase):
|
||||
@@ -51,5 +53,42 @@ class RefinementMRTGPU(unittest.TestCase):
|
||||
else:
|
||||
for a, b in zip(reference, raw.values): np.testing.assert_array_equal(a, b)
|
||||
|
||||
def test_dense_versus_blocked_root_mrt_two_level(self):
|
||||
"""Unshifted MRT: dense root (PatchCoarseStep) vs blocked root (BlockStep), same fine blocks."""
|
||||
from test_refinement_blocked_base import BASE_BLOCKS, FINE_BLOCK
|
||||
from test_refinement_blocked_fine import NX, NY, BOUNDS
|
||||
import test_refinement_blocked_fine as fixture
|
||||
cfg = LBMConfig(nx=NX, ny=NY, viscosity=.1, collision="MRT")
|
||||
with CudaContext(0) as context:
|
||||
results = {}
|
||||
for base_block in (None, *BASE_BLOCKS):
|
||||
with FixedPatchStepper(cfg, BOUNDS, context=context, fine_block=FINE_BLOCK,
|
||||
base_block=base_block) as backend:
|
||||
backend.initialize(*[fixture.state(*level.shape[1:], seed) for seed, level in enumerate(backend._levels)])
|
||||
backend.step(4)
|
||||
results[base_block] = raw(backend)
|
||||
for base_block in BASE_BLOCKS:
|
||||
for level, (a, b) in enumerate(zip(results[base_block], results[None])):
|
||||
exact(self, a, b, f"base={base_block} level={level}")
|
||||
|
||||
def test_shifted_all_blocked_three_level_mrt_smoke(self):
|
||||
"""Per-level shear rate omega_l = 1/(3*2**l*nu + 1/2); finite ACTIVE leaves."""
|
||||
cfg = LBMConfig(nx=16, ny=16, viscosity=.1, collision="MRT", ddf_shifting=True)
|
||||
kw = dict(fine_block=(4, 4), base_block=(4, 4), child=(8, 8, 16, 16), child_block=(4, 4))
|
||||
with CudaContext(0) as context:
|
||||
with FixedPatchStepper(cfg, (4, 4, 12, 12), context=context, **kw) as backend:
|
||||
self.assertEqual(len(backend._level_cfgs), 3)
|
||||
for level, level_cfg in enumerate(backend._level_cfgs):
|
||||
checked = replace(level_cfg)
|
||||
checked.validate() # omega is derived only by validate()
|
||||
self.assertEqual(checked.collision, "MRT")
|
||||
self.assertTrue(checked.ddf_shifting)
|
||||
self.assertTrue(np.isclose(checked.omega, 1 / (3 * 2**level * .1 + .5), rtol=1e-14))
|
||||
backend.initialize(*[state(*level.shape[1:]) for level in backend._levels])
|
||||
backend.step(4)
|
||||
values = backend._download_raw().values
|
||||
for a, mask in zip(values, backend._state):
|
||||
self.assertTrue(np.isfinite(a[:, mask]).all())
|
||||
|
||||
|
||||
if __name__ == "__main__": unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user