diff --git a/devito/ir/support/basic.py b/devito/ir/support/basic.py index 9283f2c2df..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, @@ -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 search(self[findex], Thickness)} + findex_wo_thickness = self[findex].subs(tkns_subs) + 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..d3fc001146 100644 --- a/tests/test_mpi.py +++ b/tests/test_mpi.py @@ -2323,6 +2323,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: