diff --git a/src/CelerisLab/lbm/refinement.py b/src/CelerisLab/lbm/refinement.py index 0069026..fc30a9f 100644 --- a/src/CelerisLab/lbm/refinement.py +++ b/src/CelerisLab/lbm/refinement.py @@ -282,8 +282,9 @@ def prepare_fine_boundary(cfg, patch, objects, *, wall_aware=False): y, x = divmod(k, cfg.nx) if x0 <= x < x1 and y0 <= y < y1: raise ValueError("Transfer coarse donor/target is not an uncovered bulk cell") - # Coarse reconstruction targets y=1,ny-2 pull from y=0..2,ny-3..ny-1. - if wall_aware and (y <= 2 or y >= cfg.ny-3): + # Rows 0/ny-1 are never computed and rows 1/ny-2 are reconstructed after + # coalescence; rows 2/ny-3 are ordinary bulk cells only read as donors. + if wall_aware and (y <= 1 or y >= cfg.ny-2): raise ValueError("Transfer footprint touches the coarse wall reconstruction stencil") return FineBoundary2D(tuple(local), _readonly(flags, np.uint16), tuple(_readonly(a, a.dtype) for a in pack_cut_links_to_soa(links)), diff --git a/tests/unit/test_fine_surface.py b/tests/unit/test_fine_surface.py index 00bf96c..d289473 100644 --- a/tests/unit/test_fine_surface.py +++ b/tests/unit/test_fine_surface.py @@ -213,3 +213,21 @@ def test_fine_rejects_ghost_solids_unresolved_circle_and_overlap(objects): cfg, patch = setup_patch() with pytest.raises(ValueError): refinement.prepare_fine_boundary(cfg, patch, objects) + + +@pytest.mark.parametrize('margin, ok', [(4, True), (3, False)]) +def test_fine_wall_guard_allows_read_only_bulk_donor_rows(margin, ok): + cfg = LBMConfig(nx=24, ny=24, viscosity=.05) + cfg.validate() + patch = FixedPatch2D.from_config(cfg, (4, margin, 20, 24-margin)) + _, coarse, _ = refinement._transfer_footprint(patch) + rows = {k // cfg.nx for k in coarse} + assert min(rows) == margin-2 and max(rows) == cfg.ny-margin+1 + source = circle(center=(12.25, 12.25)) + # Footprint never violates the plain bulk-cell checks; only the wall rule differs. + refinement.prepare_fine_boundary(cfg, patch, [source]) + if ok: + refinement.prepare_fine_boundary(cfg, patch, [source], wall_aware=True) + else: + with pytest.raises(ValueError, match='wall reconstruction'): + refinement.prepare_fine_boundary(cfg, patch, [source], wall_aware=True)