From a79f4b0df2d168abe574d2ff3e124ef29b631912 Mon Sep 17 00:00:00 2001 From: Edward Caunt Date: Mon, 3 Aug 2026 15:13:17 +0000 Subject: [PATCH 1/2] compiler: Fix handling for determining if functions on subdomains touch the halo --- devito/ir/support/basic.py | 14 ++++++++++++-- tests/test_mpi.py | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/devito/ir/support/basic.py b/devito/ir/support/basic.py index 9283f2c2df..1fbfd378ad 100644 --- a/devito/ir/support/basic.py +++ b/devito/ir/support/basic.py @@ -20,6 +20,7 @@ ComponentAccess, CriticalRegion, Dimension, DimensionTuple, Fence, Function, Symbol, TBArray, Temp, TempArray ) +from devito.types.dimension import Thickness __all__ = ['ExprGeometry', 'IterationInstance', 'Scope', 'TimedAccess'] @@ -515,8 +516,17 @@ def touched_halo(self, findex): # If `m + (self[d] - d) < self.function._size_nodomain[d].left`, then `self` # will definitely touch the left-halo, at least when `d=0` size_nodomain_left = self.function._size_nodomain[findex].left + + # Symbolic thicknesses may appear in indices for Functions defined on SubDomains + # These are used to offset the loop index values to correctly index into the reduced + # array allocated on the SubDomain. As such, they do not represent a shift of index + # on the physical grid and can (and should) be zeroed for the purpose of determining + # if the halo is touched. + tkns_subs = {tkn: 0 for tkn in self[findex].free_symbols if isinstance(tkn, Thickness)} + findex_wo_thickness = self[findex].subs(tkns_subs) if tkns_subs else self[findex] + try: - touch_halo_left = bool(m + (self[findex] - d) < size_nodomain_left) + touch_halo_left = bool(m + (findex_wo_thickness - d) > size_nodomain_left) except TypeError: # Two reasons we might end up here: # * `d` is a constant integer @@ -529,7 +539,7 @@ def touched_halo(self, findex): # If `M + (self[d] - d) > self.function._size_nodomain[d].left`, then # `self` will definitely touch the right-halo, at least when `d=d_M` try: - touch_halo_right = bool(M + (self[findex] - d) > size_nodomain_left) + touch_halo_right = bool(M + (findex_wo_thickness - d) > size_nodomain_left) except TypeError: # See comments in the except block above touch_halo_right = True diff --git a/tests/test_mpi.py b/tests/test_mpi.py index 16ddf89779..18eb63795c 100644 --- a/tests/test_mpi.py +++ b/tests/test_mpi.py @@ -1330,6 +1330,8 @@ def test_hoist_haloupdate_with_subdims(self, mode): op = Operator(eqns) + print(op.ccode) + assert len(op._func_table) == 4 # There are exactly two halo exchange calls in the Operator body @@ -2323,6 +2325,28 @@ def test_merge_subset_comms_w_overlap(self, mode): halo_update1 = body[1].body[0] assert isinstance(halo_update1, HaloUpdateList) + @pytest.mark.parallel(mode=1) + def test_function_on_subdomain_no_exchange(self, mode): + + class Boundary(SubDomain): + name = 'boundary' + + def define(self, dimensions): + x, y, z = dimensions + return {x: ('left', 1), y: ('middle', 1, 1), z: ('right', 1)} + + grid = Grid(shape=(6, 6, 6)) + boundary = Boundary(grid=grid) + + f = TimeFunction(name='f', grid=boundary, space_order=2) + + op = Operator(Eq(f.forward, f)) + _ = op.cfunction + + # Halo should not be considered touched, despite symbolic offsets in indices due + # to Function on SubDomain + check_halo_exchanges(op, 0, 0) + class TestOperatorAdvanced: From 326224bce5fdc38520c807f08f1226c61682f893 Mon Sep 17 00:00:00 2001 From: Edward Caunt Date: Tue, 4 Aug 2026 12:35:35 +0100 Subject: [PATCH 2/2] misc: Cleanup --- devito/ir/support/basic.py | 16 ++++++++-------- tests/test_mpi.py | 2 -- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/devito/ir/support/basic.py b/devito/ir/support/basic.py index 1fbfd378ad..52799a52af 100644 --- a/devito/ir/support/basic.py +++ b/devito/ir/support/basic.py @@ -10,7 +10,7 @@ from devito.ir.support.utils import AccessMode, extrema from devito.ir.support.vector import LabeledVector, Vector from devito.symbolics import ( - compare_ops, q_affine, q_comp_acc, q_constant, retrieve_indexed + compare_ops, q_affine, q_comp_acc, q_constant, retrieve_indexed, search ) from devito.tools import ( CacheInstances, Tag, as_mapper, as_tuple, cached_hash, filter_sorted, flatten, @@ -518,15 +518,15 @@ def touched_halo(self, findex): size_nodomain_left = self.function._size_nodomain[findex].left # Symbolic thicknesses may appear in indices for Functions defined on SubDomains - # These are used to offset the loop index values to correctly index into the reduced - # array allocated on the SubDomain. As such, they do not represent a shift of index - # on the physical grid and can (and should) be zeroed for the purpose of determining - # if the halo is touched. - tkns_subs = {tkn: 0 for tkn in self[findex].free_symbols if isinstance(tkn, Thickness)} - findex_wo_thickness = self[findex].subs(tkns_subs) if tkns_subs else self[findex] + # These are used to offset the loop index values to correctly index into the + # reduced array allocated on the SubDomain. As such, they do not represent a + # shift of index on the physical grid and can (and should) be zeroed for the + # purpose of determining if the halo is touched. + tkns_subs = {tkn: 0 for tkn in search(self[findex], Thickness)} + findex_wo_thickness = self[findex].subs(tkns_subs) try: - touch_halo_left = bool(m + (findex_wo_thickness - d) > size_nodomain_left) + touch_halo_left = bool(m + (findex_wo_thickness - d) < size_nodomain_left) except TypeError: # Two reasons we might end up here: # * `d` is a constant integer diff --git a/tests/test_mpi.py b/tests/test_mpi.py index 18eb63795c..d3fc001146 100644 --- a/tests/test_mpi.py +++ b/tests/test_mpi.py @@ -1330,8 +1330,6 @@ def test_hoist_haloupdate_with_subdims(self, mode): op = Operator(eqns) - print(op.ccode) - assert len(op._func_table) == 4 # There are exactly two halo exchange calls in the Operator body