diff --git a/devito/builtins/initializers.py b/devito/builtins/initializers.py index 83bad735fa..7d9c0a23f0 100644 --- a/devito/builtins/initializers.py +++ b/devito/builtins/initializers.py @@ -135,7 +135,7 @@ class ObjectiveDomain(dv.SubDomain): name = 'objective_domain' def __init__(self, lw): - super(ObjectiveDomain, self).__init__() + super().__init__() self.lw = lw def define(self, dimensions): diff --git a/devito/data/allocators.py b/devito/data/allocators.py index 95fa95a2a9..d8626fd153 100644 --- a/devito/data/allocators.py +++ b/devito/data/allocators.py @@ -268,7 +268,7 @@ def initialize(cls): cls.lib = lib def __init__(self, node): - super(NumaAllocator, self).__init__() + super().__init__() self._node = node def _alloc_C_libcall(self, size, ctype): diff --git a/devito/data/data.py b/devito/data/data.py index ef3bad7091..77328a2a1b 100644 --- a/devito/data/data.py +++ b/devito/data/data.py @@ -243,7 +243,7 @@ def __getitem__(self, glb_idx, comm_type, gather_rank=None): # Retrieve the pertinent local data prior to MPI send/receive operations data_idx = loc_data_idx(loc_idx) self._index_stash = flip_idx(glb_idx, self._decomposition) - local_val = super(Data, self).__getitem__(data_idx) + local_val = super().__getitem__(data_idx) self._index_stash = None comm = self._distributor.comm @@ -314,7 +314,7 @@ def __getitem__(self, glb_idx, comm_type, gather_rank=None): return None else: self._index_stash = glb_idx - retval = super(Data, self).__getitem__(loc_idx) + retval = super().__getitem__(loc_idx) self._index_stash = None return retval @@ -328,9 +328,9 @@ def __setitem__(self, glb_idx, val, comm_type): if index_is_basic(loc_idx): # Won't go through `__getitem__` as it's basic indexing mode, # so we should just propage `loc_idx` - super(Data, self).__setitem__(loc_idx, val) + super().__setitem__(loc_idx, val) else: - super(Data, self).__setitem__(glb_idx, val) + super().__setitem__(glb_idx, val) elif isinstance(val, Data) and val._is_distributed: if comm_type is index_by_index: glb_idx, val = self._process_args(glb_idx, val) @@ -353,7 +353,7 @@ def __setitem__(self, glb_idx, val, comm_type): self.__setitem__(idx_global[j], data_global[j]) elif self._is_distributed: # `val` is decomposed, `self` is decomposed -> local set - super(Data, self).__setitem__(glb_idx, val) + super().__setitem__(glb_idx, val) else: # `val` is decomposed, `self` is replicated -> gatherall-like raise NotImplementedError @@ -389,13 +389,13 @@ def __setitem__(self, glb_idx, val, comm_type): else: # `val` is replicated`, `self` is replicated -> plain ndarray.__setitem__ pass - super(Data, self).__setitem__(glb_idx, val) + super().__setitem__(glb_idx, val) elif isinstance(val, Iterable): if self._is_mpi_distributed: raise NotImplementedError("With MPI, data can only be set " "via scalars, numpy arrays or " "other data ") - super(Data, self).__setitem__(glb_idx, val) + super().__setitem__(glb_idx, val) else: raise ValueError("Cannot insert obj of type `%s` into a Data" % type(val)) diff --git a/devito/data/decomposition.py b/devito/data/decomposition.py index c9cc01be9d..532e03e3c6 100644 --- a/devito/data/decomposition.py +++ b/devito/data/decomposition.py @@ -59,7 +59,7 @@ def __new__(cls, items, local): raise TypeError("Illegal Decomposition element type") if not is_integer(local) and (0 <= local < len(items)): raise ValueError("`local` must be an index in ``items``.") - obj = super(Decomposition, cls).__new__(cls, [np.array(i) for i in items]) + obj = super().__new__(cls, [np.array(i) for i in items]) obj._local = local return obj diff --git a/devito/data/meta.py b/devito/data/meta.py index e4e297f232..a3b74647a5 100644 --- a/devito/data/meta.py +++ b/devito/data/meta.py @@ -23,7 +23,7 @@ def __str__(self): class DataSide(Tag): def __init__(self, name, val, flipto=None): - super(DataSide, self).__init__(name, val) + super().__init__(name, val) self.flipto = flipto if flipto is not None: flipto.flipto = self diff --git a/devito/finite_differences/differentiable.py b/devito/finite_differences/differentiable.py index d0308e2e69..607ab7693b 100644 --- a/devito/finite_differences/differentiable.py +++ b/devito/finite_differences/differentiable.py @@ -159,7 +159,7 @@ def _fd_priority(self): return .75 if self.is_TimeDependent else .5 def __hash__(self): - return super(Differentiable, self).__hash__() + return super().__hash__() def __getattr__(self, name): """ @@ -245,7 +245,7 @@ def __neg__(self): return Mul(sympy.S.NegativeOne, self) def __eq__(self, other): - ret = super(Differentiable, self).__eq__(other) + ret = super().__eq__(other) if ret is NotImplemented or not ret: # Non comparable or not equal as sympy objects return False @@ -734,7 +734,7 @@ class IndexDerivative(IndexSum): __rargs__ = ('expr', 'mapper') def __new__(cls, expr, mapper, **kwargs): - dimensions = as_tuple(mapper.values()) + dimensions = as_tuple(set(mapper.values())) # Detect the Weights among the arguments weightss = [] @@ -799,7 +799,7 @@ def _evaluate(self, **kwargs): mapper = {w.subs(d, i): f.weights[n] for n, i in enumerate(d.range)} expr = expr.xreplace(mapper) - return expr + return EvalDerivative(expr, base=self.base) # SymPy args ordering is the same for Derivatives and IndexDerivatives diff --git a/devito/ir/clusters/cluster.py b/devito/ir/clusters/cluster.py index 69ee00c6c5..30a746b731 100644 --- a/devito/ir/clusters/cluster.py +++ b/devito/ir/clusters/cluster.py @@ -427,7 +427,7 @@ class ClusterGroup(tuple): """ def __new__(cls, clusters, ispace=None): - obj = super(ClusterGroup, cls).__new__(cls, flatten(as_tuple(clusters))) + obj = super().__new__(cls, flatten(as_tuple(clusters))) obj._ispace = ispace return obj diff --git a/devito/ir/clusters/visitors.py b/devito/ir/clusters/visitors.py index c080dabab6..7c858c707f 100644 --- a/devito/ir/clusters/visitors.py +++ b/devito/ir/clusters/visitors.py @@ -127,7 +127,7 @@ def __init__(self): self.scopes = {} def __init__(self, state=None): - super(QueueStateful, self).__init__() + super().__init__() self.state = state or QueueStateful.State() def _fetch_scope(self, clusters): diff --git a/devito/ir/equations/equation.py b/devito/ir/equations/equation.py index 0fbfff9cf9..bdcaa3c802 100644 --- a/devito/ir/equations/equation.py +++ b/devito/ir/equations/equation.py @@ -199,7 +199,7 @@ def __new__(cls, *args, **kwargs): rhs = diff2sympy(expr.rhs) # Finally create the LoweredEq with all metadata attached - expr = super(LoweredEq, cls).__new__(cls, expr.lhs, rhs, evaluate=False) + expr = super().__new__(cls, expr.lhs, rhs, evaluate=False) expr._ispace = ispace expr._conditionals = conditionals diff --git a/devito/ir/iet/efunc.py b/devito/ir/iet/efunc.py index 7c8974b804..a711d4b747 100644 --- a/devito/ir/iet/efunc.py +++ b/devito/ir/iet/efunc.py @@ -33,12 +33,12 @@ def __init__(self, name, arguments=None, mapper=None, dynamic_args_mapper=None, for i, j in zip(self._mapper[k], tv): arguments[i] = j if incr is False else (arguments[i] + j) - super(ElementalCall, self).__init__(name, arguments, retobj, is_indirect) + super().__init__(name, arguments, retobj, is_indirect) def _rebuild(self, *args, dynamic_args_mapper=None, incr=False, retobj=None, **kwargs): # This guarantees that `ec._rebuild(arguments=ec.arguments) == ec` - return super(ElementalCall, self)._rebuild( + return super()._rebuild( *args, dynamic_args_mapper=dynamic_args_mapper, incr=incr, retobj=retobj, **kwargs ) @@ -63,7 +63,7 @@ class ElementalFunction(Callable): def __init__(self, name, body, retval='void', parameters=None, prefix=('static',), dynamic_parameters=None): - super(ElementalFunction, self).__init__(name, body, retval, parameters, prefix) + super().__init__(name, body, retval, parameters, prefix) self._mapper = {} for i in as_tuple(dynamic_parameters): diff --git a/devito/ir/iet/nodes.py b/devito/ir/iet/nodes.py index 7b242c6a97..486e7e4b80 100644 --- a/devito/ir/iet/nodes.py +++ b/devito/ir/iet/nodes.py @@ -68,7 +68,7 @@ class Node(Signer): """ def __new__(cls, *args, **kwargs): - obj = super(Node, cls).__new__(cls) + obj = super().__new__(cls) argnames, _, _, defaultvalues, _, _, _ = inspect.getfullargspec(cls.__init__) try: defaults = dict(zip(argnames[-len(defaultvalues):], defaultvalues)) @@ -1064,7 +1064,7 @@ class Section(List): is_Section = True def __init__(self, name, body=None, is_subsection=False): - super(Section, self).__init__(body=body) + super().__init__(body=body) self.name = name self.is_subsection = is_subsection @@ -1085,7 +1085,7 @@ class ExpressionBundle(List): is_ExpressionBundle = True def __init__(self, ispace, ops, traffic, body=None): - super(ExpressionBundle, self).__init__(body=body) + super().__init__(body=body) self.ispace = ispace self.ops = ops self.traffic = traffic @@ -1332,7 +1332,7 @@ class HaloSpot(Node): _traversable = ['body'] def __init__(self, body, halo_scheme): - super(HaloSpot, self).__init__() + super().__init__() if isinstance(body, Node): self._body = body diff --git a/devito/ir/iet/utils.py b/devito/ir/iet/utils.py index a473668814..17f640fbc4 100644 --- a/devito/ir/iet/utils.py +++ b/devito/ir/iet/utils.py @@ -26,10 +26,10 @@ def dimensions(self): return [i.dim for i in self] def __repr__(self): - return "IterationTree%s" % super(IterationTree, self).__repr__() + return "IterationTree%s" % super().__repr__() def __getitem__(self, key): - ret = super(IterationTree, self).__getitem__(key) + ret = super().__getitem__(key) return IterationTree(ret) if isinstance(key, slice) else ret diff --git a/devito/ir/iet/visitors.py b/devito/ir/iet/visitors.py index d98ea6100c..38145cac3a 100644 --- a/devito/ir/iet/visitors.py +++ b/devito/ir/iet/visitors.py @@ -66,7 +66,7 @@ class PrintAST(Visitor): """ def __init__(self, verbose=True): - super(PrintAST, self).__init__() + super().__init__() self.verbose = verbose @classmethod @@ -802,7 +802,7 @@ def default_retval(cls): """ def __init__(self, parent_type=None, child_types=None, mode=None): - super(MapNodes, self).__init__() + super().__init__() if parent_type is None: self.parent_type = Iteration elif parent_type == 'any': @@ -958,7 +958,7 @@ def default_retval(cls): } def __init__(self, match, mode='type'): - super(FindNodes, self).__init__() + super().__init__() self.match = match self.rule = self.rules[mode] @@ -1038,7 +1038,7 @@ class IsPerfectIteration(Visitor): """ def __init__(self, depth=None): - super(IsPerfectIteration, self).__init__() + super().__init__() assert depth is None or isinstance(depth, Iteration) self.depth = depth @@ -1091,7 +1091,7 @@ class Transformer(Visitor): """ def __init__(self, mapper, nested=False): - super(Transformer, self).__init__() + super().__init__() self.mapper = mapper self.nested = nested diff --git a/devito/ir/stree/tree.py b/devito/ir/stree/tree.py index 40fe388224..f461c91367 100644 --- a/devito/ir/stree/tree.py +++ b/devito/ir/stree/tree.py @@ -42,7 +42,7 @@ class NodeIteration(ScheduleTree): is_Iteration = True def __init__(self, ispace, parent=None, properties=None): - super(NodeIteration, self).__init__(parent) + super().__init__(parent) self.ispace = ispace self.properties = properties @@ -78,7 +78,7 @@ class NodeConditional(ScheduleTree): is_Conditional = True def __init__(self, guard, parent=None): - super(NodeConditional, self).__init__(parent) + super().__init__(parent) self.guard = guard @property @@ -91,7 +91,7 @@ class NodeSync(ScheduleTree): is_Sync = True def __init__(self, sync_ops, parent=None): - super(NodeSync, self).__init__(parent) + super().__init__(parent) self.sync_ops = sync_ops @property @@ -104,7 +104,7 @@ class NodeExprs(ScheduleTree): is_Exprs = True def __init__(self, exprs, ispace, dspace, ops, traffic, parent=None): - super(NodeExprs, self).__init__(parent) + super().__init__(parent) self.exprs = exprs self.ispace = ispace self.dspace = dspace diff --git a/devito/ir/support/basic.py b/devito/ir/support/basic.py index 6c13a3f006..30a0923fb0 100644 --- a/devito/ir/support/basic.py +++ b/devito/ir/support/basic.py @@ -799,11 +799,11 @@ def inplace(self, dim=None): def __add__(self, other): assert isinstance(other, DependenceGroup) - return DependenceGroup(super(DependenceGroup, self).__or__(other)) + return DependenceGroup(super().__or__(other)) def __sub__(self, other): assert isinstance(other, DependenceGroup) - return DependenceGroup(super(DependenceGroup, self).__sub__(other)) + return DependenceGroup(super().__sub__(other)) def project(self, function): """ diff --git a/devito/ir/support/properties.py b/devito/ir/support/properties.py index e9317ba1be..1b0e5fc872 100644 --- a/devito/ir/support/properties.py +++ b/devito/ir/support/properties.py @@ -6,7 +6,7 @@ class Property(Tag): _KNOWN = [] def __init__(self, name, val=None): - super(Property, self).__init__(name, val) + super().__init__(name, val) Property._KNOWN.append(self) diff --git a/devito/ir/support/space.py b/devito/ir/support/space.py index bb8c3c7823..c1170839b8 100644 --- a/devito/ir/support/space.py +++ b/devito/ir/support/space.py @@ -124,7 +124,7 @@ class Interval(AbstractInterval): is_Defined = True def __init__(self, dim, lower=0, upper=0, stamp=S0): - super(Interval, self).__init__(dim, stamp) + super().__init__(dim, stamp) try: self.lower = int(lower) @@ -147,7 +147,7 @@ def __eq__(self, o): if self is o: return True - return (super(Interval, self).__eq__(o) and + return (super().__eq__(o) and self.lower == o.lower and self.upper == o.upper) @@ -526,16 +526,16 @@ def expand(self, d=None): def index(self, key): if isinstance(key, Interval): - return super(IntervalGroup, self).index(key) + return super().index(key) elif isinstance(key, Dimension): - return super(IntervalGroup, self).index(self[key]) + return super().index(self[key]) raise ValueError("Expected Interval or Dimension, got `%s`" % type(key)) def __getitem__(self, key): if is_integer(key): - return super(IntervalGroup, self).__getitem__(key) + return super().__getitem__(key) elif isinstance(key, slice): - retval = super(IntervalGroup, self).__getitem__(key) + retval = super().__getitem__(key) return IntervalGroup(retval, relations=self.relations, mode=self.mode) if not self.is_well_defined: @@ -699,7 +699,7 @@ def __eq__(self, other): self.parts == other.parts) def __hash__(self): - return hash((super(DataSpace, self).__hash__(), self.parts)) + return hash((super().__hash__(), self.parts)) @classmethod def union(cls, *others): @@ -753,7 +753,7 @@ class IterationSpace(Space): """ def __init__(self, intervals, sub_iterators=None, directions=None): - super(IterationSpace, self).__init__(intervals) + super().__init__(intervals) # Normalize sub-iterators sub_iterators = dict([(k, tuple(filter_ordered(as_tuple(v)))) @@ -788,7 +788,7 @@ def __lt__(self, other): return len(self.itintervals) < len(other.itintervals) def __hash__(self): - return hash((super(IterationSpace, self).__hash__(), self.sub_iterators, + return hash((super().__hash__(), self.sub_iterators, self.directions)) def __contains__(self, d): diff --git a/devito/ir/support/vector.py b/devito/ir/support/vector.py index 2a68c07504..1fa90379af 100644 --- a/devito/ir/support/vector.py +++ b/devito/ir/support/vector.py @@ -50,7 +50,7 @@ class Vector(tuple): """ def __new__(cls, *items, smart=False): - obj = super(Vector, cls).__new__(cls, items) + obj = super().__new__(cls, items) obj.smart = smart return obj @@ -70,7 +70,7 @@ def wrapper(self, other): return __asvector def __hash__(self): - return super(Vector, self).__hash__() + return super().__hash__() @_asvector() def __add__(self, other): @@ -90,11 +90,11 @@ def __rsub__(self, other): @_asvector(relax=True) def __eq__(self, other): - return super(Vector, self).__eq__(other) + return super().__eq__(other) @_asvector(relax=True) def __ne__(self, other): - return super(Vector, self).__ne__(other) + return super().__ne__(other) def __lt__(self, other): # This might raise an exception if the distance between the i-th entry @@ -210,7 +210,7 @@ def __ge__(self, other): return other.__le__(self) def __getitem__(self, key): - ret = super(Vector, self).__getitem__(key) + ret = super().__getitem__(key) return Vector(*ret, smart=self.smart) if isinstance(key, slice) else ret def __repr__(self): @@ -277,7 +277,7 @@ def __new__(cls, items=None): if not all(isinstance(i, Dimension) for i in labels): raise ValueError("All labels must be of type Dimension, got [%s]" % ','.join(i.__class__.__name__ for i in labels)) - obj = super(LabeledVector, cls).__new__(cls, *values) + obj = super().__new__(cls, *values) obj.labels = labels return obj @@ -306,7 +306,7 @@ def __hash__(self): def __eq__(self, other): if isinstance(other, LabeledVector) and self.labels != other.labels: raise TypeError("Cannot compare due to mismatching `labels`") - return super(LabeledVector, self).__eq__(other) + return super().__eq__(other) def __ne__(self, other): return not self.__eq__(other) @@ -314,7 +314,7 @@ def __ne__(self, other): def __lt__(self, other): if isinstance(other, LabeledVector) and self.labels != other.labels: raise TypeError("Cannot compare due to mismatching `labels`") - return super(LabeledVector, self).__lt__(other) + return super().__lt__(other) def __gt__(self, other): return other.__lt__(self) @@ -327,12 +327,12 @@ def __le__(self, other): def __getitem__(self, index): if isinstance(index, (slice, int)): - return super(LabeledVector, self).__getitem__(index) + return super().__getitem__(index) elif isinstance(index, Dimension): for d in self.labels: if d._defines & index._defines: i = self.labels.index(d) - return super(LabeledVector, self).__getitem__(i) + return super().__getitem__(i) return None else: raise TypeError("Indices must be integers, slices, or Dimensions, not %s" diff --git a/devito/mpi/routines.py b/devito/mpi/routines.py index dacf64a0f5..83cbb73cce 100644 --- a/devito/mpi/routines.py +++ b/devito/mpi/routines.py @@ -1018,7 +1018,7 @@ def _call_poke(self, poke): class MPICallable(CommCallable): def __init__(self, name, body, parameters): - super(MPICallable, self).__init__(name, body, 'void', parameters, ('static',)) + super().__init__(name, body, 'void', parameters, ('static',)) class CopyBuffer(MPICallable): @@ -1028,7 +1028,7 @@ class CopyBuffer(MPICallable): class SendRecv(MPICallable): def __init__(self, name, body, parameters, bufg, bufs): - super(SendRecv, self).__init__(name, body, parameters) + super().__init__(name, body, parameters) self.bufg = bufg self.bufs = bufs @@ -1036,7 +1036,7 @@ def __init__(self, name, body, parameters, bufg, bufs): class HaloUpdate(MPICallable): def __init__(self, name, body, parameters): - super(HaloUpdate, self).__init__(name, body, parameters) + super().__init__(name, body, parameters) class Remainder(ElementalFunction): @@ -1308,7 +1308,7 @@ def __init__(self, prefix, key, arguments, owned): else: fields.append((i.name, c_int)) - super(MPIRegion, self).__init__(name, pname, fields) + super().__init__(name, pname, fields) def __value_setup__(self, dtype, value): # We eventually produce an array of `struct region` that is as big as diff --git a/devito/operator/operator.py b/devito/operator/operator.py index 3ed9709a1d..e8767b8aaf 100644 --- a/devito/operator/operator.py +++ b/devito/operator/operator.py @@ -25,7 +25,7 @@ from devito.tools import (DAG, OrderedSet, Signer, ReducerMap, as_tuple, flatten, filter_sorted, frozendict, is_integer, split, timed_pass, timed_region, contains_val) -from devito.types import Grid, Evaluable +from devito.types import Grid, Evaluable, SubFunction __all__ = ['Operator'] @@ -141,7 +141,7 @@ def __new__(cls, expressions, **kwargs): if expressions is None: # Return a dummy Callable. This is exploited by unpickling. Users # can't do anything useful with it - return super(Operator, cls).__new__(cls, **kwargs) + return super().__new__(cls, **kwargs) # Parse input arguments kwargs = parse_kwargs(**kwargs) @@ -648,7 +648,8 @@ def _postprocess_arguments(self, args, **kwargs): subfuncs = (args[getattr(p, s).name] for s in p._sub_functions) p._arg_apply(args[p.name], *subfuncs, alias=kwargs.get(p.name)) except AttributeError: - p._arg_apply(args[p.name], alias=kwargs.get(p.name)) + if not (isinstance(p, SubFunction) and p.parent in self.parameters): + p._arg_apply(args[p.name], alias=kwargs.get(p.name)) @cached_property def _known_arguments(self): diff --git a/devito/operator/profiling.py b/devito/operator/profiling.py index 53f16e526f..fd0defd089 100644 --- a/devito/operator/profiling.py +++ b/devito/operator/profiling.py @@ -386,7 +386,7 @@ def __init__(self, name): if self.path is None: self.initialized = False else: - super(AdvisorProfiler, self).__init__(name) + super().__init__(name) # Make sure future compilations will get the proper header and # shared object files compiler = configuration['compiler'] @@ -418,7 +418,7 @@ def instrument(self, iet, timer): class PerformanceSummary(OrderedDict): def __init__(self, *args, **kwargs): - super(PerformanceSummary, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.subsections = DefaultOrderedDict(lambda: OrderedDict()) self.input = OrderedDict() self.globals = {} diff --git a/devito/parameters.py b/devito/parameters.py index 885d8a56e4..c97c38b89c 100644 --- a/devito/parameters.py +++ b/devito/parameters.py @@ -27,7 +27,7 @@ class Parameters(OrderedDict, Signer): """ def __init__(self, name=None, **kwargs): - super(Parameters, self).__init__(**kwargs) + super().__init__(**kwargs) self._name = name self._accepted = {} @@ -74,7 +74,7 @@ def _preprocess(self, key, value): @_check_key_deprecation def __getitem__(self, key, *args): - return super(Parameters, self).__getitem__(key) + return super().__getitem__(key) @_check_key_deprecation @_check_key_value @@ -83,7 +83,7 @@ def __setitem__(self, key, value): if key in self._update_functions: value = self._update_functions[key](value) if value is not None: - super(Parameters, self).__setitem__(key, value) + super().__setitem__(key, value) @_check_key_deprecation @_check_key_value @@ -93,7 +93,7 @@ def update(self, key, value): ``self[key] = value`` as both preprocessor and callback, if any, are bypassed. """ - super(Parameters, self).__setitem__(key, value) + super().__setitem__(key, value) def add(self, key, value, accepted=None, preprocessor=None, callback=None, impacts_jit=True, deprecate=None): @@ -109,7 +109,7 @@ def add(self, key, value, accepted=None, preprocessor=None, callback=None, that the parameter doesn't affect code generation, so it can be excluded from the construction of the hash key. """ - super(Parameters, self).__setitem__(key, value) + super().__setitem__(key, value) self._accepted[key] = accepted self._defaults[key] = value self._impact_jit[key] = impacts_jit diff --git a/devito/passes/clusters/aliases.py b/devito/passes/clusters/aliases.py index f8cc8a2333..7a8321a7f9 100644 --- a/devito/passes/clusters/aliases.py +++ b/devito/passes/clusters/aliases.py @@ -922,10 +922,15 @@ def lower_schedule(schedule, meta, sregistry, ftemps): # Drop or weaken parallelism if necessary for d, v in meta.properties.items(): - if any(i.is_Modulo for i in ispace.sub_iterators[d]): - properties[d] = normalize_properties(v, {SEQUENTIAL}) - elif d not in writeto.itdims: - properties[d] = normalize_properties(v, {PARALLEL_IF_PVT}) - {ROUNDABLE} + try: + if any(i.is_Modulo for i in ispace.sub_iterators[d]): + properties[d] = normalize_properties(v, {SEQUENTIAL}) + elif d not in writeto.itdims: + properties[d] = normalize_properties(v, {PARALLEL_IF_PVT}) - \ + {ROUNDABLE} + except KeyError: + # Non-dimension key such as (x, y) for diagonal stencil u(x+i hx, y+i hy) + pass # Track star-shaped stencils for potential future optimization if len(writeto) > 1 and schedule.is_frame: @@ -1307,7 +1312,7 @@ def is_frame(self): class Schedule(tuple): def __new__(cls, *items, dmapper=None, rmapper=None, is_frame=False): - obj = super(Schedule, cls).__new__(cls, items) + obj = super().__new__(cls, items) obj.dmapper = dmapper or {} obj.rmapper = rmapper or {} obj.is_frame = is_frame diff --git a/devito/passes/clusters/misc.py b/devito/passes/clusters/misc.py index d8017af3c6..32f26ad782 100644 --- a/devito/passes/clusters/misc.py +++ b/devito/passes/clusters/misc.py @@ -26,7 +26,7 @@ class Lift(Queue): @timed_pass(name='lift') def process(self, elements): - return super(Lift, self).process(elements) + return super().process(elements) def callback(self, clusters, prefix): if not prefix: diff --git a/devito/symbolics/extended_sympy.py b/devito/symbolics/extended_sympy.py index c827a990ac..8626ecf094 100644 --- a/devito/symbolics/extended_sympy.py +++ b/devito/symbolics/extended_sympy.py @@ -196,8 +196,7 @@ def __str__(self): __repr__ = __str__ def _hashable_content(self): - return super(CallFromPointer, self)._hashable_content() +\ - (self.call, self.pointer) + self.params + return super()._hashable_content() + (self.call, self.pointer) + self.params @property def base(self): diff --git a/devito/tools/abc.py b/devito/tools/abc.py index 61d3de64db..2682e595ad 100644 --- a/devito/tools/abc.py +++ b/devito/tools/abc.py @@ -259,7 +259,7 @@ class Singleton(type): def __call__(cls, *args, **kwargs): if cls not in cls._instances: - cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] diff --git a/devito/tools/data_structures.py b/devito/tools/data_structures.py index 1ebfc3698a..2a3a5529a5 100644 --- a/devito/tools/data_structures.py +++ b/devito/tools/data_structures.py @@ -44,7 +44,7 @@ class EnrichedTuple(tuple, Pickable): """ def __new__(cls, *items, getters=None, **kwargs): - obj = super(EnrichedTuple, cls).__new__(cls, items) + obj = super().__new__(cls, items) obj.__dict__.update(kwargs) obj._getters = OrderedDict(zip(getters or [], items)) return obj diff --git a/devito/types/array.py b/devito/types/array.py index e790a39c52..e51edd27ed 100644 --- a/devito/types/array.py +++ b/devito/types/array.py @@ -116,7 +116,7 @@ def __new__(cls, *args, **kwargs): return AbstractFunction.__new__(cls, *args, **kwargs) def __init_finalize__(self, *args, **kwargs): - super(Array, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) self._liveness = kwargs.get('liveness', 'lazy') assert self._liveness in ['eager', 'lazy'] @@ -328,7 +328,7 @@ def __new__(cls, *args, **kwargs): return AbstractFunction.__new__(cls, *args, **kwargs) def __init_finalize__(self, *args, **kwargs): - super(PointerArray, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) self._array = kwargs['array'] assert self._array.is_Array diff --git a/devito/types/basic.py b/devito/types/basic.py index 6ec4cfab28..e72b531d75 100644 --- a/devito/types/basic.py +++ b/devito/types/basic.py @@ -664,6 +664,22 @@ def _fromrep(cls, rep): pass return newobj + @classmethod + def __subfunc_setup__(cls, *args, **kwargs): + """Setup each component of the tensor as a Devito type.""" + return [] + + @property + def grid(self): + """ + A Tensor is expected to have all its components defined over the same grid + """ + grids = {getattr(c, 'grid', None) for c in self.flat()} - {None} + if len(grids) == 0: + return None + assert len(grids) == 1 + return grids.pop() + def _infer_dims(self): grids = {getattr(c, 'grid', None) for c in self.flat()} - {None} dimensions = {d for c in self.flat() @@ -743,11 +759,6 @@ def _eval_matrix_mul(self, other): newcls = self.classof_prod(other, new_mat) return newcls._new(self.rows, other.cols, new_mat, copy=False) - @classmethod - def __subfunc_setup__(cls, *args, **kwargs): - """Setup each component of the tensor as a Devito type.""" - return [] - class AbstractFunction(sympy.Function, Basic, Pickable, Evaluable): diff --git a/devito/types/dense.py b/devito/types/dense.py index 0cc0536424..9d33777551 100644 --- a/devito/types/dense.py +++ b/devito/types/dense.py @@ -65,7 +65,7 @@ def __init_finalize__(self, *args, function=None, **kwargs): # Now that *all* __X_setup__ hooks have been called, we can let the # superclass constructor do its job - super(DiscreteFunction, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) # Symbolic (finite difference) coefficients self._coefficients = kwargs.get('coefficients', 'standard') @@ -982,7 +982,7 @@ def _cache_meta(self): return {'nbytes': self.size} def __init_finalize__(self, *args, **kwargs): - super(Function, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) # Space order space_order = kwargs.get('space_order', 1) @@ -1323,7 +1323,7 @@ class TimeFunction(Function): def __init_finalize__(self, *args, **kwargs): self.time_dim = kwargs.get('time_dim', self.dimensions[self._time_position]) self._time_order = kwargs.get('time_order', 1) - super(TimeFunction, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) # Check we won't allocate too much memory for the system available_mem = virtual_memory().available @@ -1391,7 +1391,7 @@ def __shape_setup__(cls, **kwargs): raise TypeError("`dimensions` required if both `grid` and " "`shape` are provided") else: - shape = super(TimeFunction, cls).__shape_setup__( + shape = super().__shape_setup__( grid=grid, shape=shape, dimensions=dimensions ) @@ -1457,6 +1457,12 @@ class SubFunction(Function): DiscreteFunction it's bound to. """ + __rkwargs__ = DiscreteFunction.__rkwargs__ + ('dimensions', 'shape') + + def __init_finalize__(self, *args, **kwargs): + self._parent = kwargs.pop('parent', None) + super().__init_finalize__(*args, **kwargs) + def __padding_setup__(self, **kwargs): # SubFunctions aren't expected to be used in time-consuming loops return tuple((0, 0) for i in range(self.ndim)) @@ -1465,17 +1471,28 @@ def _halo_exchange(self): return def _arg_values(self, **kwargs): - if self.name in kwargs: + if self._parent is not None and self.parent.name not in kwargs: + return self._parent._arg_defaults(alias=self._parent).reduce_all() + elif self.name in kwargs: raise RuntimeError("`%s` is a SubFunction, so it can't be assigned " "a value dynamically" % self.name) + else: + return self._arg_defaults(alias=self) - return self._arg_defaults(alias=self) + def _arg_apply(self, *args, **kwargs): + if self._parent is not None: + return self._parent._arg_apply(*args, **kwargs) + return super()._arg_apply(*args, **kwargs) @property def origin(self): # SubFunction have zero origin return DimensionTuple(*(0 for _ in range(self.ndim)), getters=self.dimensions) + @property + def parent(self): + return self._parent + class TempFunction(DiscreteFunction): diff --git a/devito/types/object.py b/devito/types/object.py index 17c63c1b82..869e794481 100644 --- a/devito/types/object.py +++ b/devito/types/object.py @@ -91,7 +91,7 @@ class Object(AbstractObject, ArgProvider, Uncached): is_Object = True def __init__(self, name, dtype, value=None): - super(Object, self).__init__(name, dtype) + super().__init__(name, dtype) self.value = value __hash__ = Uncached.__hash__ @@ -137,7 +137,7 @@ class CompositeObject(Object): def __init__(self, name, pname, pfields, value=None): dtype = CtypesFactory.generate(pname, pfields) value = self.__value_setup__(dtype, value) - super(CompositeObject, self).__init__(name, dtype, value) + super().__init__(name, dtype, value) def __value_setup__(self, dtype, value): return value or byref(dtype._type_()) diff --git a/devito/types/sparse.py b/devito/types/sparse.py index 75dbdf502b..93e1bf0e5e 100644 --- a/devito/types/sparse.py +++ b/devito/types/sparse.py @@ -47,7 +47,7 @@ class AbstractSparseFunction(DiscreteFunction): __rkwargs__ = DiscreteFunction.__rkwargs__ + ('npoint_global', 'space_order') def __init_finalize__(self, *args, **kwargs): - super(AbstractSparseFunction, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) self._npoint = kwargs.get('npoint', kwargs.get('npoint_global')) self._space_order = kwargs.get('space_order', 0) @@ -72,11 +72,22 @@ def __shape_setup__(cls, **kwargs): if grid is None: raise TypeError('Need `grid` argument') shape = kwargs.get('shape') + dimensions = kwargs.get('dimensions') npoint = kwargs.get('npoint', kwargs.get('npoint_global')) + glb_npoint = SparseDistributor.decompose(npoint, grid.distributor) if shape is None: - glb_npoint = SparseDistributor.decompose(npoint, grid.distributor) - shape = (glb_npoint[grid.distributor.myrank],) - return shape + loc_shape = (glb_npoint[grid.distributor.myrank],) + else: + loc_shape = [] + assert len(dimensions) == len(shape) + for i, (d, s) in enumerate(zip(dimensions, shape)): + if i == cls._sparse_position: + loc_shape.append(glb_npoint[grid.distributor.myrank]) + elif d in grid.dimensions: + loc_shape.append(grid.dimension_map[d].loc) + else: + loc_shape.append(s) + return tuple(loc_shape) def __fd_setup__(self): """ @@ -89,11 +100,13 @@ def __distributor_setup__(self, **kwargs): A `SparseDistributor` handles the SparseFunction decomposition based on physical ownership, and allows to convert between global and local indices. """ - return SparseDistributor( - kwargs.get('npoint', kwargs.get('npoint_global')), - self._sparse_dim, - kwargs['grid'].distributor - ) + distributor = kwargs.get('distributor') + if distributor is None: + distributor = SparseDistributor( + kwargs.get('npoint', kwargs.get('npoint_global')), + self._sparse_dim, kwargs['grid'].distributor) + + return distributor def __subfunc_setup__(self, key, suffix, dtype=None): # Shape and dimensions from args @@ -142,7 +155,7 @@ def __subfunc_setup__(self, key, suffix, dtype=None): sf = SubFunction( name=name, dtype=dtype, dimensions=dimensions, shape=shape, space_order=0, initializer=key, alias=self.alias, - distributor=self._distributor + distributor=self._distributor, parent=self ) if self.npoint == 0: @@ -154,9 +167,13 @@ def __subfunc_setup__(self, key, suffix, dtype=None): return sf + @property + def sparse_position(self): + return self._sparse_position + @property def _sparse_dim(self): - return self.dimensions[self._sparse_position] + return self.dimensions[self.sparse_position] @property def _mpitype(self): diff --git a/devito/types/tensor.py b/devito/types/tensor.py index f2cab51825..9be56fd093 100644 --- a/devito/types/tensor.py +++ b/devito/types/tensor.py @@ -187,10 +187,10 @@ def values(self): if self.is_diagonal: return [self[i, i] for i in range(self.shape[0])] elif self.is_symmetric: - val = super(TensorFunction, self).values() + val = super().values() return list(OrderedDict.fromkeys(val)) else: - return super(TensorFunction, self).values() + return super().values() def div(self, shift=None, order=None): """ diff --git a/devito/types/utils.py b/devito/types/utils.py index 81daf1eb5c..83dcce1eda 100644 --- a/devito/types/utils.py +++ b/devito/types/utils.py @@ -10,7 +10,7 @@ class Buffer(Tag): def __init__(self, value): - super(Buffer, self).__init__('Buffer', value) + super().__init__('Buffer', value) class Stagger(Tag): diff --git a/examples/seismic/model.py b/examples/seismic/model.py index 7c553739f6..eb78d97ed3 100644 --- a/examples/seismic/model.py +++ b/examples/seismic/model.py @@ -57,7 +57,7 @@ class PhysicalDomain(SubDomain): name = 'physdomain' def __init__(self, so, fs=False): - super(PhysicalDomain, self).__init__() + super().__init__() self.so = so self.fs = fs @@ -73,7 +73,7 @@ class FSDomain(SubDomain): name = 'fsdomain' def __init__(self, so): - super(FSDomain, self).__init__() + super().__init__() self.size = so def define(self, dimensions): @@ -270,8 +270,8 @@ class SeismicModel(GenericModel): def __init__(self, origin, spacing, shape, space_order, vp, nbl=20, fs=False, dtype=np.float32, subdomains=(), bcs="mask", grid=None, **kwargs): - super(SeismicModel, self).__init__(origin, spacing, shape, space_order, nbl, - dtype, subdomains, grid=grid, bcs=bcs, fs=fs) + super().__init__(origin, spacing, shape, space_order, nbl, + dtype, subdomains, grid=grid, bcs=bcs, fs=fs) # Initialize physics self._initialize_physics(vp, space_order, **kwargs) diff --git a/examples/seismic/source.py b/examples/seismic/source.py index cdaf1ef4ae..a736c5bb4f 100644 --- a/examples/seismic/source.py +++ b/examples/seismic/source.py @@ -124,7 +124,7 @@ def __init_finalize__(self, *args, **kwargs): data = kwargs.pop('data', None) kwargs.setdefault('time_order', 2) - super(PointSource, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) self._time_range = time_range._rebuild() @@ -205,10 +205,10 @@ class WaveletSource(PointSource): def __args_setup__(cls, *args, **kwargs): kwargs.setdefault('npoint', 1) - return super(WaveletSource, cls).__args_setup__(*args, **kwargs) + return super().__args_setup__(*args, **kwargs) def __init_finalize__(self, *args, **kwargs): - super(WaveletSource, self).__init_finalize__(*args, **kwargs) + super().__init_finalize__(*args, **kwargs) self.f0 = kwargs.get('f0') self.a = kwargs.get('a') diff --git a/tests/test_mpi.py b/tests/test_mpi.py index 1bc5330889..12733de0a2 100644 --- a/tests/test_mpi.py +++ b/tests/test_mpi.py @@ -616,12 +616,12 @@ class SparseFirst(SparseFunction): ds = DefaultDimension("ps", default_value=3) grid = Grid((11, 11)) dims = grid.dimensions - s = SparseFirst(name="s", grid=grid, npoint=2, dimensions=(dr, ds), shape=(2, 3), - coordinates=[[.5, .5], [.2, .2]]) + s = SparseFirst(name="s", grid=grid, npoint=4, dimensions=(dr, ds), shape=(4, 3), + coordinates=[[.1, .1], [.2, .2], [.3, .3], [.5, .5]]) # Check dimensions and shape are correctly initialized assert s.indices[s._sparse_position] == dr - assert s.shape == (2, 3) + assert s.shape == (1, 3) assert s.coordinates.indices[0] == dr # Operator diff --git a/tests/test_sparse.py b/tests/test_sparse.py index 04545d7cc6..b2c1acb841 100644 --- a/tests/test_sparse.py +++ b/tests/test_sparse.py @@ -4,7 +4,7 @@ import numpy as np import scipy.sparse -from devito import Grid, TimeFunction, Eq, Operator, Dimension +from devito import Grid, TimeFunction, Eq, Operator, Dimension, Function from devito import (SparseFunction, SparseTimeFunction, PrecomputedSparseFunction, PrecomputedSparseTimeFunction, MatrixSparseTimeFunction) @@ -455,6 +455,37 @@ def test_subs(self, sptype): assert getattr(sps, subf).indices[0] == new_spdim assert np.all(getattr(sps, subf).data == getattr(sp, subf).data) + @pytest.mark.parallel(mode=[1, 4]) + def test_mpi_no_data(self): + grid = Grid((11, 11), extent=(10, 10)) + time = grid.time_dim + # Base object + sp = SparseTimeFunction(name="s", grid=grid, npoint=1, nt=1, + coordinates=[[5., 5.]]) + + m = TimeFunction(name="m", grid=grid, space_order=2, time_order=1) + eq = [Eq(m.forward, m + m.laplace)] + + op = Operator(eq + sp.inject(field=m.forward, expr=time)) + # Not using the source data so can run with any time_M + op(time_M=5) + + expected = np.array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 4., -10., 4., 0., 0., 0., 0.], + [0., 0., 0., 6., -30., 55., -30., 6., 0., 0., 0.], + [0., 0., 4., -30., 102., -158., 102., -30., 4., 0., 0.], + [0., 1., -10., 55., -158., 239., -158., 55., -10., 1., 0.], + [0., 0., 4., -30., 102., -158., 102., -30., 4., 0., 0.], + [0., 0., 0., 6., -30., 55., -30., 6., 0., 0., 0.], + [0., 0., 0., 0., 4., -10., 4., 0., 0., 0., 0.], + [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]]) + + ftest = Function(name='ftest', grid=grid, space_order=2) + ftest.data[:] = expected + assert np.all(m.data[0, :, :] == ftest.data[:]) + if __name__ == "__main__": - TestMatrixSparseTimeFunction().test_mpi() + TestMatrixSparseTimeFunction().test_mpi_no_data()