Skip to content

MPI overlap modes fail to build Eqs with coordinate guards or non-local SubDimensions (ValueError: x_m is not in list) #3094

Open

Description

@ggorman

Symptom

With DEVITO_MPI=overlap, overlap2 or full, Operator(...) raises at build time

ValueError: x_m is not in list

(or x_M / x_rtkn0; which symbol is named varies from run to run) for an Eq whose x iteration is narrowed by a coordinate guard or by a non-local one-sided SubDimension. The same Eqs build under DEVITO_MPI=1 (basic) and diag2. Nothing has to run: the failure is in code generation, and it happens with one rank as well as with four.

Reproducer

# repro.py -- mpirun -n 4 python repro.py {guard,subdim}   (one rank fails the same way)
import sys
import sympy
from devito import (Grid, TimeFunction, Eq, Operator, ConditionalDimension,
                    SubDimension, switchconfig)

grid = Grid(shape=(24, 24))
x, y = grid.dimensions
u = TimeFunction(name='u', grid=grid, space_order=4)

if sys.argv[1] == 'guard':
    # Update only 3 <= x < 10
    cd = ConditionalDimension(name='cd', parent=x, condition=sympy.And(x >= 3, x < 10))
    eqs = [Eq(u.forward, u.laplace + 1, implicit_dims=[cd])]
else:
    # Update only the first 4 global x points
    xl = SubDimension.left(name='xl', parent=x, thickness=4, local=False)
    eqs = [Eq(u.forward, u.laplace + 1).subs(x, xl)]

for mode in ['basic', 'diag2', 'overlap', 'overlap2', 'full']:
    try:
        with switchconfig(mpi=mode):
            Operator(eqs)
        msg = 'built'
    except Exception as e:
        msg = f'{type(e).__name__}: {e}'
    if grid.distributor.myrank == 0:
        print(sys.argv[1], mode, msg)

Run with DEVITO_MPI=1 DEVITO_LANGUAGE=openmp, 4 ranks, on ese-ponte:

guard   basic     built
guard   diag2     built
guard   overlap   ValueError: x_m is not in list
guard   overlap2  ValueError: x_m is not in list
guard   full      ValueError: x_m is not in list
subdim  basic     built
subdim  diag2     built
subdim  overlap   ValueError: x_M is not in list
subdim  overlap2  ValueError: x_rtkn0 is not in list
subdim  full      ValueError: x_rtkn0 is not in list

A ConditionalDimension whose condition refers to a SubDomain bound (x < sd.dimensions[0].symbolic_min, used to split x between a guarded Eq and a middle SubDomain Eq) fails the same way.

Evidence

What is known about the cause

The traceback ends in ElementalFunction.__init__, called for the compute Callable that the overlap builders create:

devito/mpi/routines.py:690   OverlapHaloExchangeBuilder._make_compute -> make_efunc(f'compute{key}', hs.body, hs.arguments, ...)
devito/ir/iet/efunc.py:119   self._mapper[i] = (parameters.index(i.symbolic_min),
devito/ir/iet/efunc.py:120                      parameters.index(i.symbolic_max))

dynamic_parameters is hs.arguments, which is HaloScheme.arguments (devito/mpi/halo_scheme.py:498-499): self.dimensions | set(flatten(self.honored.values())). parameters is derived from the HaloSpot body. For these Eqs, hs.arguments names symbols that the body never uses, so parameters.index fails. Instrumenting ElementalFunction.__init__ on main shows:

  • guard: body parameters ['u', 'x', 'h_x', 'h_y', 't0', 't1', 'y_M', 'y_m']; dynamic parameters y, x. The x loop is outside the HaloSpot body, which only contains the y loop, so x_m/x_M are absent.
  • subdim: body parameters include x_m and x_ltkn0 (the loop is xl over [x_m, x_m + x_ltkn0 - 1]); dynamic parameters are x_ltkn0, y, x, x_rtkn0, so x_M and x_rtkn0 are absent.

The symbol in the message changes between runs because HaloScheme.arguments is a set, so iteration order decides which missing symbol is reported first.

What is not known

  • Whether the right fix is to filter dynamic_parameters to what the body uses (in _make_compute or in ElementalFunction), or whether the HaloSpot should not be overlappable in these shapes at all. In particular, it is not established that the CORE/OWNED split computed from hs.omapper is correct when the x loop sits outside the HaloSpot (the guard case).
  • Whether the other consumers of hs.arguments in devito/mpi/routines.py (:794 MPIRegion, :915, and FullHaloExchangeBuilder._make_compute at :983) fail the same way once the compute Callable is fixed. Only compute has been seen failing.
  • Whether any user code in the wild uses these shapes with overlap modes. The guard shape is a common way to restrict an update to a box.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions