Skip to content

Commit 9d42649

Browse files
committed
dsl: Add handling for missing subdomain specification in Eq
1 parent 910d27e commit 9d42649

9 files changed

Lines changed: 259 additions & 128 deletions

File tree

devito/finite_differences/differentiable.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
318318
"""
319319
w = kwargs.get('weights', kwargs.get('w'))
320320
order = order or self.space_order
321-
space_dims = [d.root for d in self.dimensions if d.is_Space]
321+
space_dims = self.root_dimensions
322322
shift_x0 = make_shift_x0(shift, (len(space_dims),))
323323
derivs = tuple('d%s2' % d.name for d in space_dims)
324324
return Add(*[getattr(self, d)(x0=shift_x0(shift, space_dims[i], None, i),
@@ -345,7 +345,7 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
345345
Custom weights for the finite difference coefficients.
346346
"""
347347
w = kwargs.get('weights', kwargs.get('w'))
348-
space_dims = [d.root for d in self.dimensions if d.is_Space]
348+
space_dims = self.root_dimensions
349349
shift_x0 = make_shift_x0(shift, (len(space_dims),))
350350
order = order or self.space_order
351351
return Add(*[getattr(self, 'd%s' % d.name)(x0=shift_x0(shift, d, None, i),
@@ -372,7 +372,7 @@ def grad(self, shift=None, order=None, method='FD', **kwargs):
372372
Custom weights for the finite
373373
"""
374374
from devito.types.tensor import VectorFunction, VectorTimeFunction
375-
space_dims = [d.root for d in self.dimensions if d.is_Space]
375+
space_dims = self.root_dimensions
376376
shift_x0 = make_shift_x0(shift, (len(space_dims),))
377377
order = order or self.space_order
378378
w = kwargs.get('weights', kwargs.get('w'))
@@ -388,7 +388,7 @@ def biharmonic(self, weight=1):
388388
Generates a symbolic expression for the weighted biharmonic operator w.r.t.
389389
all spatial Dimensions Laplace(weight * Laplace (self))
390390
"""
391-
space_dims = [d.root for d in self.dimensions if d.is_Space]
391+
space_dims = self.root_dimensions
392392
derivs = tuple('d%s2' % d.name for d in space_dims)
393393
return Add(*[getattr(self.laplace * weight, d) for d in derivs])
394394

devito/ir/equations/algorithms.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def lower_exprs(expressions, subs=None, **kwargs):
113113
def _lower_exprs(expressions, subs):
114114
processed = []
115115
for expr in as_tuple(expressions):
116-
dimension_map = make_dimension_map(expr)
116+
dimension_map = _make_dimension_map(expr)
117117

118118
# Handle Functions (typical case)
119119
mapper = {f: _lower_exprs(f.indexify(subs=dimension_map), subs)
@@ -157,7 +157,7 @@ def _lower_exprs(expressions, subs):
157157
return processed.pop()
158158

159159

160-
def make_dimension_map(expr):
160+
def _make_dimension_map(expr):
161161
"""
162162
Make the dimension_map for an expression. In the basic case, this is extracted
163163
directly from the SubDomain attached to the expression.
@@ -233,6 +233,7 @@ def _(expr, mapper, rebuilt, sregistry):
233233
thicknesses = {i for i in expr.free_symbols if isinstance(i, Thickness)}
234234
symbols = expr.free_symbols.difference(thicknesses)
235235

236+
# Iterate over all other symbols before iterating over standalone thicknesses
236237
for d in tuple(symbols) + tuple(thicknesses):
237238
_concretize_subdims(d, mapper, rebuilt, sregistry)
238239

devito/operations/interpolators.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def wrapper(interp, *args, **kwargs):
3333
return wrapper
3434

3535

36-
def extract_subdomain(variables):
36+
def _extract_subdomain(variables):
3737
"""
3838
Check if any of the variables provided are defined on a SubDomain
3939
and extract it if this is the case.
@@ -194,6 +194,10 @@ def __init__(self, sfunction):
194194
def grid(self):
195195
return self.sfunction.grid
196196

197+
@property
198+
def r(self):
199+
return self.sfunction.r
200+
197201
@memoized_meth
198202
def _weights(self, subdomain=None):
199203
raise NotImplementedError
@@ -202,10 +206,6 @@ def _weights(self, subdomain=None):
202206
def _gdims(self):
203207
return self.grid.dimensions
204208

205-
@property
206-
def r(self):
207-
return self.sfunction.r
208-
209209
@cached_property
210210
def _cdim(self):
211211
"""Base CustomDimensions used to construct _rdim"""
@@ -366,7 +366,7 @@ def _interpolate(self, expr, increment=False, self_subs={}, implicit_dims=None):
366366
_expr = expr
367367

368368
variables = list(retrieve_function_carriers(_expr))
369-
subdomain = extract_subdomain(variables)
369+
subdomain = _extract_subdomain(variables)
370370

371371
# Implicit dimensions
372372
implicit_dims = self._augment_implicit_dims(implicit_dims, variables)
@@ -416,7 +416,7 @@ def _inject(self, field, expr, implicit_dims=None):
416416
else:
417417
assert len(exprs) == len(fields)
418418

419-
subdomain = extract_subdomain(fields)
419+
subdomain = _extract_subdomain(fields)
420420

421421
# Derivatives must be evaluated before the introduction of indirect accesses
422422
try:

devito/types/basic.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,11 @@ def space_dimensions(self):
11271127
"""Tuple of Dimensions defining the physical space."""
11281128
return tuple(d for d in self.dimensions if d.is_Space)
11291129

1130+
@cached_property
1131+
def root_dimensions(self):
1132+
"""Tuple of root Dimensions of the physical space Dimensions."""
1133+
return tuple(d.root for d in self.space_dimensions)
1134+
11301135
@property
11311136
def base(self):
11321137
return self.indexed
@@ -1461,7 +1466,7 @@ def _offset_subdomain(self):
14611466
"""Offset of subdomain indices versus the global index."""
14621467
# If defined on a SubDomain, then need to offset indices accordingly
14631468
if not self._is_on_subdomain:
1464-
return (0,)*len(self.dimensions)
1469+
return DimensionTuple(*[0 for _ in self.dimensions], getters=self.dimensions)
14651470
# Symbolic offsets to avoid potential issues with user overrides
14661471
offsets = []
14671472
for d in self.dimensions:

devito/types/equation.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""User API to specify equations."""
22
import sympy
33

4+
from functools import cached_property
5+
46
from devito.deprecations import deprecations
57
from devito.tools import as_tuple, frozendict, Pickable
68
from devito.types.lazy import Evaluable
@@ -140,10 +142,26 @@ def _flatten(self):
140142
else:
141143
return [self]
142144

143-
@property
145+
@cached_property
144146
def subdomain(self):
145147
"""The SubDomain in which the Eq is defined."""
146-
return self._subdomain
148+
if self._subdomain is not None:
149+
return self._subdomain
150+
151+
from devito.symbolics.search import retrieve_functions # noqa
152+
153+
funcs = retrieve_functions(self)
154+
subdomains = {f.grid for f in funcs} - {None}
155+
subdomains = {g for g in subdomains if g.is_SubDomain}
156+
157+
if len(subdomains) == 0:
158+
return None
159+
elif len(subdomains) == 1:
160+
return subdomains.pop()
161+
else:
162+
raise ValueError("Multiple `SubDomain`s detected. Provide a `SubDomain`"
163+
" explicitly (i.e., via `Eq(..., subdomain=...)`)"
164+
" to unambiguously define the `Eq`'s iteration domain.")
147165

148166
@property
149167
def substitutions(self):

devito/types/tensor.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ def space_dimensions(self):
159159
"""Spatial dimensions."""
160160
return self._space_dimensions
161161

162+
@cached_property
163+
def root_dimensions(self):
164+
"""Tuple of root Dimensions of the physical space Dimensions."""
165+
return tuple(d.root for d in self.space_dimensions)
166+
162167
@cached_property
163168
def space_order(self):
164169
"""The space order for all components."""
@@ -209,7 +214,7 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
209214
comps = []
210215
func = vec_func(self)
211216
ndim = len(self.space_dimensions)
212-
space_dims = [d.root for d in self.space_dimensions]
217+
space_dims = self.root_dimensions
213218
shift_x0 = make_shift_x0(shift, (ndim, ndim))
214219
order = order or self.space_order
215220
for i in range(len(self.space_dimensions)):
@@ -252,7 +257,7 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
252257
comps = []
253258
func = vec_func(self)
254259
order = order or self.space_order
255-
space_dims = [d.root for d in self.space_dimensions]
260+
space_dims = self.root_dimensions
256261
ndim = len(self.space_dimensions)
257262
shift_x0 = make_shift_x0(shift, (ndim, ndim))
258263
for j in range(ndim):
@@ -345,7 +350,7 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
345350
w = kwargs.get('weights', kwargs.get('w'))
346351
shift_x0 = make_shift_x0(shift, (len(self.space_dimensions),))
347352
order = order or self.space_order
348-
space_dims = [d.root for d in self.space_dimensions]
353+
space_dims = self.root_dimensions
349354
return sum([getattr(self[i], 'd%s' % d.name)(x0=shift_x0(shift, d, None, i),
350355
fd_order=order, method=method, w=w)
351356
for i, d in enumerate(space_dims)])
@@ -378,7 +383,7 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
378383
func = vec_func(self)
379384
shift_x0 = make_shift_x0(shift, (len(self.space_dimensions),))
380385
order = order or self.space_order
381-
space_dims = [d.root for d in self.space_dimensions]
386+
space_dims = self.root_dimensions
382387
comps = [sum([getattr(s, 'd%s2' % d.name)(x0=shift_x0(shift, d, None, i),
383388
fd_order=order, w=w, method=method)
384389
for i, d in enumerate(space_dims)])
@@ -406,7 +411,7 @@ def curl(self, shift=None, order=None, method='FD', **kwargs):
406411
raise AttributeError("Curl only supported for 3D VectorFunction")
407412
# The curl of a VectorFunction is a VectorFunction
408413
w = kwargs.get('weights', kwargs.get('w'))
409-
dims = [d.root for d in self.space_dimensions]
414+
dims = self.root_dimensions
410415
derivs = ['d%s' % d.name for d in dims]
411416
shift_x0 = make_shift_x0(shift, (len(dims), len(dims)))
412417
order = order or self.space_order
@@ -447,7 +452,7 @@ def grad(self, shift=None, order=None, method='FD', **kwargs):
447452
ndim = len(self.space_dimensions)
448453
shift_x0 = make_shift_x0(shift, (ndim, ndim))
449454
order = order or self.space_order
450-
space_dims = [d.root for d in self.space_dimensions]
455+
space_dims = self.root_dimensions
451456
comps = [[getattr(f, 'd%s' % d.name)(x0=shift_x0(shift, d, i, j), w=w,
452457
fd_order=order, method=method)
453458
for j, d in enumerate(space_dims)]

examples/userapi/03_subdomains.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@
234234
"source": [
235235
"The Devito `SubDomain` API features two steps. The first of these is to create a subclass of `SubDomain`, which encapsulates the template by which `SubDomain`s should be constructed. This is not tied to a specific `Grid`. On a basic level, this specification is created by defining a suitable `define` method for the subclass.\n",
236236
"\n",
237-
"Note if one intends to introduce a custom `__init__` when subclassing `SubDomain`, then it is necessary to provide the `kwarg` `grid=None`, and pass this through to `super().__init__()`. Such a custom `__init__` may be useful in applications such as creating many `SubDomain` instances with similar properties from a single template.\n",
237+
"Note if one intends to introduce a custom `__init__` when subclassing `SubDomain`, then it is necessary for this `__init__` to take the `kwarg` `grid=None`, passing it through to `super().__init__(grid=grid)`. Such a custom `__init__` may be useful in applications such as creating many `SubDomain` instances with similar properties from a single template.\n",
238238
"\n",
239239
"Here is an example of how to define a subdomain that spans an entire 3D computational grid (this is similar to how 'domain' is defined internally):"
240240
]
@@ -314,7 +314,7 @@
314314
"\n",
315315
"The two other options available are `'left'` and `'right'`. For a statement of the form `d: ('left', N)` the `SubDomain` spans a contiguous region of `N` points starting at `d`\\'s left extreme. A statement of the form `('right', N)` is analogous to the previous case but starting at the dimensions right extreme instead.\n",
316316
"\n",
317-
"We can also attach this subdomain to the grid."
317+
"We then attach this subdomain to the grid."
318318
]
319319
},
320320
{

0 commit comments

Comments
 (0)