Fix periodic-seam cut-link addressing in map_cut_links
Source (write) and reverse-donor addresses are now the receiver's local core address +/- (ey*local_nx + ex), i.e. the window image the next local pull reads. block_cell preferred the in-window core image on a one-block periodic axis, so BFL wrote a copy the pull never reads. Physical neighbors are still formed only to reject non-periodic exteriors. block_cell semantics unchanged; docstring notes the image ambiguity. Adds an end-to-end synthetic seam test (x=0/x=nx-1/corner wraps) on one-block-x, one-block-y and 1x1 periodic layouts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2aadffe183
commit
2a68d7e7c7
@@ -152,7 +152,9 @@ class BlockLayout2D:
|
||||
def block_cell(self, block, y, x):
|
||||
"""Address of in-grid cell (y, x) in ``block``'s own storage, core or halo.
|
||||
|
||||
Periodic axes resolve to the image inside the block's halo window.
|
||||
Periodic axes resolve to the image inside the block's halo window;
|
||||
if two images fit, the core-side one is returned (use local offsets,
|
||||
not this lookup, when a stencil must follow a specific image).
|
||||
Raises if the cell is not represented there or lies across an exterior.
|
||||
"""
|
||||
by, bx = self.block
|
||||
@@ -187,6 +189,7 @@ class BlockLayout2D:
|
||||
grid. Halo must be at least one cell (always true here).
|
||||
"""
|
||||
ny, nx = self.shape
|
||||
lx = self.local_shape[1]
|
||||
cells = int(np.prod(self.local_shape))
|
||||
rows, seen, writers = [], set(), set()
|
||||
for link in links:
|
||||
@@ -197,16 +200,20 @@ class BlockLayout2D:
|
||||
y, x = divmod(r, nx)
|
||||
receiver = int(self.owner[y, x])
|
||||
block = receiver // cells
|
||||
sy, sx = self._neighbor(y, x, D2Q9_EY[q], D2Q9_EX[q])
|
||||
# Local stencil offsets from the core receiver: the window image the
|
||||
# next local pull reads, even where a periodic seam wraps physically.
|
||||
# Physical neighbors are formed only to reject non-periodic exteriors.
|
||||
step = D2Q9_EY[q] * lx + D2Q9_EX[q]
|
||||
self._neighbor(y, x, D2Q9_EY[q], D2Q9_EX[q])
|
||||
opp = q + 1 if q % 2 else q - 1
|
||||
write = int(self.slot(self.block_cell(block, sy, sx), opp))
|
||||
write = int(self.slot(receiver + step, opp))
|
||||
if write in writers:
|
||||
raise ValueError("duplicate local boundary writer")
|
||||
writers.add(write)
|
||||
donor = NO_DONOR
|
||||
if float(link.q) < .5 and int(link.fallback) == 0:
|
||||
dy, dx = self._neighbor(y, x, -D2Q9_EY[q], -D2Q9_EX[q])
|
||||
donor = self.block_cell(block, dy, dx)
|
||||
self._neighbor(y, x, -D2Q9_EY[q], -D2Q9_EX[q])
|
||||
donor = receiver - step
|
||||
rows.append((block, receiver, donor, write))
|
||||
table = np.array(rows, dtype=np.uint64).reshape(-1, 4)
|
||||
return BlockCutLinks(_readonly(table[:, 0], np.uint32),
|
||||
|
||||
Reference in New Issue
Block a user