From c02ea78e76024b225a114f4804e245fc303143fb Mon Sep 17 00:00:00 2001 From: mloubout Date: Wed, 21 Oct 2026 10:52:03 -0400 Subject: [PATCH 1/2] types: Fix AbstractTensor name and rebuild for base names containing underscores The tensor name was inferred as the component name up to its first underscore, so e.g. tau_s was reported as tau. Use the stored name, falling back to stripping the last _suffix, and rebuild component names by replacing only the leading base name. --- devito/types/basic.py | 10 ++++++++-- tests/test_tensors.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/devito/types/basic.py b/devito/types/basic.py index dcd9d5e266..fc8940f5e9 100644 --- a/devito/types/basic.py +++ b/devito/types/basic.py @@ -1640,9 +1640,15 @@ def grid(self): @property def name(self): + # `_name` may be unset if `__init_finalize__` was skipped in `_fromrep` + name = getattr(self, '_name', None) + if name is not None: + return name + # Components are named `{name}_{suffix}`, with the suffix built from + # the Dimension names, so the base name is everything before the last `_` for c in self.values(): try: - return c.name.split('_')[0] + return c.name.rsplit('_', 1)[0] except AttributeError: # `c` is not a devito object pass @@ -1660,7 +1666,7 @@ def _rebuild(self, *args, **kwargs): # We need to rebuild the components with the new name then # rebuild the matrix newname = kwargs.pop('name', self.name) - comps = [f.func(*args, name=f.name.replace(self.name, newname), **kwargs) + comps = [f.func(*args, name=f"{newname}{f.name[len(self.name):]}", **kwargs) for f in self.flat()] # Rebuild the matrix with the new components return self._new(*self.shape, comps) diff --git a/tests/test_tensors.py b/tests/test_tensors.py index 0b4ad4603a..e8ac22cf6e 100644 --- a/tests/test_tensors.py +++ b/tests/test_tensors.py @@ -487,6 +487,22 @@ def test_rebuild(func1): assert j.dimensions == tuple(new_dims) +@pytest.mark.parametrize('func1', [TensorFunction, TensorTimeFunction, + VectorFunction, VectorTimeFunction]) +@pytest.mark.parametrize('name', ['tau_s', 'my_tau_x', 'x']) +def test_name_with_underscore(func1, name): + grid = Grid(tuple([5]*3)) + f1 = func1(name=name, grid=grid) + assert f1.name == name + assert (2 * f1).name == name + assert (f1 + f1).name == name + + f2 = f1.func(name='f2') + assert f2.name == 'f2' + for (i, j) in zip(f1.flat(), f2.flat(), strict=True): + assert j.name == f"f2{i.name[len(name):]}" + + @pytest.mark.parametrize('func1', [Function, TimeFunction, TensorFunction, TensorTimeFunction, VectorFunction, VectorTimeFunction]) From 620f4343d244a0ac02242d54b1a6734a6448ae22 Mon Sep 17 00:00:00 2001 From: Fabio Luporini Date: Fri, 23 Oct 2026 09:35:04 +0100 Subject: [PATCH 2/2] compiler: Tweak GuardOverflow for reconstruction --- devito/ir/support/guards.py | 3 ++- tests/test_pickle.py | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/devito/ir/support/guards.py b/devito/ir/support/guards.py index 8a3842ddfd..3c4b573c03 100644 --- a/devito/ir/support/guards.py +++ b/devito/ir/support/guards.py @@ -214,7 +214,8 @@ class BaseGuardOverflow(Guard): A guard for buffer overflow. """ - pass + def __new__(cls, p0, p1, **kwargs): + return super().__new__(cls, p0, p1, evaluate=False) class GuardOverflowGe(BaseGuardOverflow, Ge): diff --git a/tests/test_pickle.py b/tests/test_pickle.py index aea96df5e9..8bd989d31f 100644 --- a/tests/test_pickle.py +++ b/tests/test_pickle.py @@ -13,14 +13,16 @@ ) from devito.data import LEFT, OWNED from devito.finite_differences.tools import centered, direct, left, right, transpose -from devito.ir import Backward, Forward, GuardBound, GuardBoundNext, GuardFactor +from devito.ir import ( + Backward, Forward, GuardBound, GuardBoundNext, GuardFactor, GuardOverflow +) from devito.mpi.halo_scheme import Halo from devito.mpi.routines import ( MPIMsgEnriched, MPIRegion, MPIRequestObject, MPIStatusObject ) from devito.symbolics import ( CallFromPointer, Cast, DefFunction, FieldFromPointer, IntDiv, ListInitializer, SizeOf, - indexify, pow_to_mul + as_long, indexify, pow_to_mul ) from devito.symbolics.unevaluation import Mod from devito.tools import EnrichedTuple @@ -566,6 +568,22 @@ def test_guard_bound_next(self, pickle, direction): assert str(gbn) == str(new_gbn) + @pytest.mark.parametrize('negated', [False, True]) + def test_guard_overflow(self, pickle, negated): + d = Dimension(name='d') + freespace = Scalar(name='freespace') + size = SizeOf(np.float32)*as_long((d + 4)*(d + 8)) + + guard = GuardOverflow(freespace, size) + if negated: + guard = guard.negated + + new_guard = pickle.loads(pickle.dumps(guard)) + + assert type(new_guard) is type(guard) + assert str(new_guard) == str(guard) + assert new_guard.canonical is new_guard + def test_temp_function(self, pickle): grid = Grid(shape=(3, 3)) d = Dimension(name='d')