diff --git a/devito/types/array.py b/devito/types/array.py index 34237f01bf..62c1b62f49 100644 --- a/devito/types/array.py +++ b/devito/types/array.py @@ -368,6 +368,8 @@ def __args_setup__(cls, *args, **kwargs): raise ValueError("Component type must be subclass of AbstractFunction") if len({i.__padding_dtype__ for i in components}) != 1: raise ValueError("Components must have the same padding dtype") + if len({i.properties for i in components}) != 1: + raise ValueError("Components must have the same properties") return args, kwargs @@ -441,12 +443,13 @@ def initvalue(self): # Overrides defaulting to self.c0's behaviour - for i in ['_mem_internal_eager', '_mem_internal_lazy', '_mem_local', + for i in ('_mem_internal_eager', '_mem_internal_lazy', '_mem_local', '_mem_mapped', '_mem_host', '_mem_stack', '_mem_constant', '_mem_shared', '__padding_dtype__', '_size_domain', '_size_halo', '_size_owned', '_size_padding', '_size_nopad', '_size_nodomain', '_offset_domain', '_offset_halo', '_offset_owned', '_dist_dimensions', - '_C_get_field', 'grid', 'symbolic_shape']: + '_C_get_field', 'grid', 'symbolic_shape', + *AbstractFunction.__properties__): locals()[i] = property(lambda self, v=i: getattr(self.c0, v)) @property diff --git a/devito/types/basic.py b/devito/types/basic.py index 7a6a349100..4b0ea425c4 100644 --- a/devito/types/basic.py +++ b/devito/types/basic.py @@ -861,6 +861,8 @@ class AbstractFunction(sympy.Function, Basic, Pickable, Evaluable): __rkwargs__ = ('name', 'dtype', 'grid', 'halo', 'padding', 'ghost', 'alias', 'space', 'function', 'is_transient', 'avg_mode') + __properties__ = ('is_const', 'is_transient') + def __new__(cls, *args, **kwargs): # Preprocess arguments args, kwargs = cls.__args_setup__(*args, **kwargs) @@ -970,8 +972,6 @@ def __init_finalize__(self, *args, **kwargs): # A `Distributor` to handle domain decomposition self._distributor = self.__distributor_setup__(**kwargs) - # Symbol properties - # "Aliasing" another AbstractFunction means that `self` logically # represents another object. For example, `self` might be used as the # formal parameter of a routine generated by the compiler, where the @@ -1274,6 +1274,10 @@ def is_const(self): def is_transient(self): return self._is_transient + @cached_property + def properties(self): + return frozendict([(i, getattr(self, i)) for i in self.__properties__]) + @property def avg_mode(self): return self._avg_mode