Multipatch: validate fine block before modulo, raw-core GPU checks, README usage
FixedPatchSet2D.fine_layout rejects non-positive, float, bool or wrong-length block sizes with ValueError before any modulo (was ZeroDivisionError/TypeError). The face gap-4 GPU test now checks raw owner cores directly by kind/covered for every patch (ACTIVE finite, OUTER/holes/covered NaN; INNER not asserted), not only the masked download and reversed-order parity. README documents the body-free multipatch call, scope and level-wide fine shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0397b6ebb7
commit
6301887093
@@ -6,7 +6,8 @@ Run CPU and GPU classes in separate processes. GPU gates (frozen before any run)
|
||||
- S1 translation copy: two patches on 16x32 equal the 16x16 one-patch run tiled
|
||||
twice, bit for bit, every step;
|
||||
- reversed rectangle order gives bit-identical results;
|
||||
- face gap-4 pair (16x24): ACTIVE leaves finite, covered/hole masks exact.
|
||||
- face gap-4 pair (16x24): ACTIVE leaves finite, covered/hole masks exact, also on
|
||||
raw owner cores per patch (INNER partly invalid by contract, not asserted).
|
||||
Weighted leaf mass is printed as a diagnostic only.
|
||||
"""
|
||||
from dataclasses import replace
|
||||
@@ -16,7 +17,7 @@ import numpy as np
|
||||
import pycuda.driver as cuda
|
||||
|
||||
from CelerisLab.config import LBMConfig
|
||||
from CelerisLab.lbm.refinement import ACTIVE, FixedPatch2D, FixedPatchSet2D
|
||||
from CelerisLab.lbm.refinement import ACTIVE, OUTER_GHOST, FixedPatch2D, FixedPatchSet2D
|
||||
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
|
||||
from test_refinement_blocked_fine import BOUNDS, NX, NY, config, state, circle
|
||||
from test_refinement_blocked_base import exact, raw
|
||||
@@ -112,6 +113,9 @@ class MultipatchGPU(unittest.TestCase):
|
||||
fine = level_fine(s, [state(*p.fine_shape, 6 + i) for i, p in enumerate(s.patches)])
|
||||
kw = dict(fine_block=(4, 4), base_block=(4, 4))
|
||||
leaf = s.fine_kind == ACTIVE
|
||||
support = s.fine_layout((4, 4)).owned
|
||||
outer = support & (s.fine_kind == OUTER_GHOST)
|
||||
holes = ~support
|
||||
with CudaContext(0) as context:
|
||||
runs = [self.run_steps(context, cfg, bounds, coarse, fine, **kw)
|
||||
for bounds in (FACE, FACE[::-1])]
|
||||
@@ -123,6 +127,19 @@ class MultipatchGPU(unittest.TestCase):
|
||||
self.assertTrue(np.isnan(c[:, s.covered]).all())
|
||||
self.assertTrue(np.isfinite(f[:, leaf]).all())
|
||||
self.assertTrue(np.isnan(f[:, ~leaf]).all())
|
||||
# Raw owner cores, independent of the download mask (every patch).
|
||||
# INNER may be partly NaN after hop 2 by contract: not asserted.
|
||||
rc, rf = a[2], a[3]
|
||||
label = f"raw step {step}"
|
||||
self.assertTrue(np.isfinite(rc[:, ~s.covered]).all(), label + " coarse leaves")
|
||||
if step: # covered parent cores are poisoned by the parent step
|
||||
self.assertTrue(np.isnan(rc[:, s.covered]).all(), label + " covered")
|
||||
self.assertTrue(np.isfinite(rf[:, leaf]).all(), label + " fine ACTIVE")
|
||||
self.assertTrue(np.isnan(rf[:, outer]).all(), label + " fine OUTER")
|
||||
self.assertTrue(np.isnan(rf[:, holes]).all(), label + " fine holes")
|
||||
for i, p in enumerate(s.patches):
|
||||
active = window(s, i, rf)[:, p.fine_kind == ACTIVE]
|
||||
self.assertTrue(np.isfinite(active).all(), f"{label} patch {i} ACTIVE")
|
||||
mass = float(np.nansum(c, dtype=np.float64) + .25 * np.nansum(f, dtype=np.float64))
|
||||
print(f"face gap4 step {step}: weighted leaf mass {mass:.9g} (diagnostic)", flush=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user