Skip to content

Commit 3e6c852

Browse files
Merge pull request #2811 from devitocodes/grad-kwargs
api: Extend side API to all derivative operator shortcuts
2 parents f020eb1 + 575d306 commit 3e6c852

5 files changed

Lines changed: 196 additions & 36 deletions

File tree

devito/finite_differences/derivative.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Derivative(sympy.Derivative, Differentiable, Pickable):
3838
Derivative order.
3939
side : Side or tuple of Side, optional, default=centered
4040
Side of the finite difference location, centered (at x), left (at x - 1)
41-
or right (at x +1).
41+
or right (at x + 1).
4242
transpose : Transpose, optional, default=direct
4343
Forward (matvec=direct) or transpose (matvec=transpose) mode of the
4444
finite difference.

devito/finite_differences/differentiable.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ def laplace(self):
310310
"""
311311
return self.laplacian()
312312

313-
def laplacian(self, shift=None, order=None, method='FD', **kwargs):
313+
def laplacian(self, shift=None, order=None, method='FD', side=None, **kwargs):
314314
"""
315315
Laplacian of the Differentiable with shifted derivatives and custom
316316
FD order.
@@ -329,19 +329,22 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
329329
method: str, optional, default='FD'
330330
Discretization method. Options are 'FD' (default) and
331331
'RSFD' (rotated staggered grid finite-difference).
332+
side : Side or tuple of Side, optional, default=centered
333+
Side of the finite difference location, centered (at x), left (at x - 1)
334+
or right (at x + 1).
332335
weights/w: list, tuple, or dict, optional, default=None
333-
Custom weights for the finite differences.
336+
Custom weights for the finite difference coefficients.
334337
"""
335338
w = kwargs.get('weights', kwargs.get('w'))
336339
order = order or self.space_order
337340
space_dims = self.root_dimensions
338341
shift_x0 = make_shift_x0(shift, (len(space_dims),))
339342
derivs = tuple(f'd{d.name}2' for d in space_dims)
340343
return Add(*[getattr(self, d)(x0=shift_x0(shift, space_dims[i], None, i),
341-
method=method, fd_order=order, w=w)
344+
method=method, fd_order=order, side=side, w=w)
342345
for i, d in enumerate(derivs)])
343346

344-
def div(self, shift=None, order=None, method='FD', **kwargs):
347+
def div(self, shift=None, order=None, method='FD', side=None, **kwargs):
345348
"""
346349
Divergence of the input Function.
347350
@@ -357,6 +360,9 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
357360
method: str, optional, default='FD'
358361
Discretization method. Options are 'FD' (default) and
359362
'RSFD' (rotated staggered grid finite-difference).
363+
side : Side or tuple of Side, optional, default=centered
364+
Side of the finite difference location, centered (at x), left (at x - 1)
365+
or right (at x + 1).
360366
weights/w: list, tuple, or dict, optional, default=None
361367
Custom weights for the finite difference coefficients.
362368
"""
@@ -365,10 +371,11 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
365371
shift_x0 = make_shift_x0(shift, (len(space_dims),))
366372
order = order or self.space_order
367373
return Add(*[getattr(self, f'd{d.name}')(x0=shift_x0(shift, d, None, i),
368-
fd_order=order, method=method, w=w)
374+
fd_order=order, method=method, side=side,
375+
w=w)
369376
for i, d in enumerate(space_dims)])
370377

371-
def grad(self, shift=None, order=None, method='FD', **kwargs):
378+
def grad(self, shift=None, order=None, method='FD', side=None, **kwargs):
372379
"""
373380
Gradient of the input Function.
374381
@@ -384,16 +391,21 @@ def grad(self, shift=None, order=None, method='FD', **kwargs):
384391
method: str, optional, default='FD'
385392
Discretization method. Options are 'FD' (default) and
386393
'RSFD' (rotated staggered grid finite-difference).
394+
side : Side or tuple of Side, optional, default=centered
395+
Side of the finite difference location, centered (at x), left (at x - 1)
396+
or right (at x + 1).
387397
weights/w: list, tuple, or dict, optional, default=None
388-
Custom weights for the finite
398+
Custom weights for the finite difference coefficients.
389399
"""
390400
from devito.types.tensor import VectorFunction, VectorTimeFunction
391401
space_dims = self.root_dimensions
392402
shift_x0 = make_shift_x0(shift, (len(space_dims),))
393403
order = order or self.space_order
404+
394405
w = kwargs.get('weights', kwargs.get('w'))
395406
comps = [getattr(self, f'd{d.name}')(x0=shift_x0(shift, d, None, i),
396-
fd_order=order, method=method, w=w)
407+
fd_order=order, method=method, side=side,
408+
w=w)
397409
for i, d in enumerate(space_dims)]
398410
vec_func = VectorTimeFunction if self.is_TimeDependent else VectorFunction
399411
return vec_func(name=f'grad_{self.name}', time_order=self.time_order,

devito/finite_differences/operators.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
def div(func, shift=None, order=None, method='FD', **kwargs):
1+
def div(func, shift=None, order=None, method='FD', side=None, **kwargs):
22
"""
33
Divergence of the input Function.
44
@@ -14,12 +14,15 @@ def div(func, shift=None, order=None, method='FD', **kwargs):
1414
method: str, optional, default='FD'
1515
Discretization method. Options are 'FD' (default) and
1616
'RSFD' (rotated staggered grid finite-difference).
17+
side : Side or tuple of Side, optional, default=centered
18+
Side of the finite difference location, centered (at x), left (at x - 1)
19+
or right (at x + 1).
1720
weights/w: list, tuple, or dict, optional, default=None
1821
Custom weights for the finite difference coefficients.
1922
"""
2023
w = kwargs.get('weights', kwargs.get('w'))
2124
try:
22-
return func.div(shift=shift, order=order, method=method, w=w)
25+
return func.div(shift=shift, order=order, method=method, side=side, w=w)
2326
except AttributeError:
2427
return 0
2528

@@ -41,7 +44,7 @@ def div45(func, shift=None, order=None):
4144
return div(func, shift=shift, order=order, method='RSFD')
4245

4346

44-
def grad(func, shift=None, order=None, method='FD', **kwargs):
47+
def grad(func, shift=None, order=None, method='FD', side=None, **kwargs):
4548
"""
4649
Gradient of the input Function.
4750
@@ -57,12 +60,15 @@ def grad(func, shift=None, order=None, method='FD', **kwargs):
5760
method: str, optional, default='FD'
5861
Discretization method. Options are 'FD' (default) and
5962
'RSFD' (rotated staggered grid finite-difference).
63+
side : Side or tuple of Side, optional, default=centered
64+
Side of the finite difference location, centered (at x), left (at x - 1)
65+
or right (at x + 1).
6066
weights/w: list, tuple, or dict, optional, default=None
6167
Custom weights for the finite difference coefficients.
6268
"""
6369
w = kwargs.get('weights', kwargs.get('w'))
6470
try:
65-
return func.grad(shift=shift, order=order, method=method, w=w)
71+
return func.grad(shift=shift, order=order, method=method, side=side, w=w)
6672
except AttributeError:
6773
raise AttributeError("Gradient not supported for class %s" % func.__class__)
6874

@@ -84,7 +90,7 @@ def grad45(func, shift=None, order=None):
8490
return grad(func, shift=shift, order=order, method='RSFD')
8591

8692

87-
def curl(func, shift=None, order=None, method='FD', **kwargs):
93+
def curl(func, shift=None, order=None, method='FD', side=None, **kwargs):
8894
"""
8995
Curl of the input Function. Only supported for VectorFunction
9096
@@ -100,12 +106,15 @@ def curl(func, shift=None, order=None, method='FD', **kwargs):
100106
method: str, optional, default='FD'
101107
Discretization method. Options are 'FD' (default) and
102108
'RSFD' (rotated staggered grid finite-difference).
109+
side : Side or tuple of Side, optional, default=centered
110+
Side of the finite difference location, centered (at x), left (at x - 1)
111+
or right (at x + 1).
103112
weights/w: list, tuple, or dict, optional, default=None
104113
Custom weights for the finite difference coefficients.
105114
"""
106115
w = kwargs.get('weights', kwargs.get('w'))
107116
try:
108-
return func.curl(shift=shift, order=order, method=method, w=w)
117+
return func.curl(shift=shift, order=order, method=method, side=side, w=w)
109118
except AttributeError:
110119
raise AttributeError("Curl only supported for 3D VectorFunction")
111120

@@ -128,7 +137,7 @@ def curl45(func, shift=None, order=None):
128137
return curl(func, shift=shift, order=order, method='RSFD')
129138

130139

131-
def laplace(func, shift=None, order=None, method='FD', **kwargs):
140+
def laplace(func, shift=None, order=None, method='FD', side=None, **kwargs):
132141
"""
133142
Laplacian of the input Function.
134143
@@ -143,12 +152,15 @@ def laplace(func, shift=None, order=None, method='FD', **kwargs):
143152
Uses `func.space_order` when not specified
144153
method: str, optional, default='FD'
145154
Discretization method. Options are 'FD' (default) and 'RSFD'
155+
side : Side or tuple of Side, optional, default=centered
156+
Side of the finite difference location, centered (at x), left (at x - 1)
157+
or right (at x + 1).
146158
weights/w: list, tuple, or dict, optional, default=None
147159
Custom weights for the finite difference coefficients.
148160
"""
149161
w = kwargs.get('weights', kwargs.get('w'))
150162
try:
151-
return func.laplacian(shift=shift, order=order, method=method, w=w)
163+
return func.laplacian(shift=shift, order=order, method=method, side=side, w=w)
152164
except AttributeError:
153165
return 0
154166

devito/types/tensor.py

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def values(self):
220220
else:
221221
return super().values()
222222

223-
def div(self, shift=None, order=None, method='FD', **kwargs):
223+
def div(self, shift=None, order=None, method='FD', side=None, **kwargs):
224224
"""
225225
Divergence of the TensorFunction (is a VectorFunction).
226226
@@ -234,6 +234,9 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
234234
method: str, optional, default='FD'
235235
Discretization method. Options are 'FD' (default) and
236236
'RSFD' (rotated staggered grid finite-difference).
237+
side : Side or tuple of Side, optional, default=centered
238+
Side of the finite difference location, centered (at x), left (at x - 1)
239+
or right (at x + 1).
237240
weights/w: list, tuple, or dict, optional, default=None
238241
Custom weights for the finite differences.
239242
"""
@@ -247,7 +250,7 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
247250
for i in range(len(self.space_dimensions)):
248251
comps.append(sum([getattr(self[j, i], 'd%s' % d.name)
249252
(x0=shift_x0(shift, d, i, j), fd_order=order,
250-
method=method, w=w)
253+
method=method, side=side, w=w)
251254
for j, d in enumerate(space_dims)]))
252255
return func._new(comps)
253256

@@ -258,7 +261,7 @@ def laplace(self):
258261
"""
259262
return self.laplacian()
260263

261-
def laplacian(self, shift=None, order=None, method='FD', **kwargs):
264+
def laplacian(self, shift=None, order=None, method='FD', side=None, **kwargs):
262265
"""
263266
Laplacian of the TensorFunction with shifted derivatives and custom
264267
FD order.
@@ -277,6 +280,9 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
277280
method: str, optional, default='FD'
278281
Discretization method. Options are 'FD' (default) and
279282
'RSFD' (rotated staggered grid finite-difference).
283+
side : Side or tuple of Side, optional, default=centered
284+
Side of the finite difference location, centered (at x), left (at x - 1)
285+
or right (at x + 1).
280286
weights/w: list, tuple, or dict, optional, default=None
281287
Custom weights for the finite
282288
"""
@@ -290,7 +296,7 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
290296
for j in range(ndim):
291297
comps.append(sum([getattr(self[j, i], 'd%s2' % d.name)
292298
(x0=shift_x0(shift, d, j, i), fd_order=order,
293-
method=method, w=w)
299+
method=method, side=side, w=w)
294300
for i, d in enumerate(space_dims)]))
295301
return func._new(comps)
296302

@@ -358,7 +364,7 @@ def __str__(self):
358364

359365
__repr__ = __str__
360366

361-
def div(self, shift=None, order=None, method='FD', **kwargs):
367+
def div(self, shift=None, order=None, method='FD', side=None, **kwargs):
362368
"""
363369
Divergence of the VectorFunction, creates the divergence Function.
364370
@@ -372,6 +378,9 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
372378
method: str, optional, default='FD'
373379
Discretization method. Options are 'FD' (default) and
374380
'RSFD' (rotated staggered grid finite-difference).
381+
side : Side or tuple of Side, optional, default=centered
382+
Side of the finite difference location, centered (at x), left (at x - 1)
383+
or right (at x + 1).
375384
weights/w: list, tuple, or dict, optional, default=None
376385
Custom weights for the finite difference coefficients.
377386
"""
@@ -380,7 +389,8 @@ def div(self, shift=None, order=None, method='FD', **kwargs):
380389
order = order or self.space_order
381390
space_dims = self.root_dimensions
382391
return sum([getattr(self[i], 'd%s' % d.name)(x0=shift_x0(shift, d, None, i),
383-
fd_order=order, method=method, w=w)
392+
fd_order=order, method=method,
393+
side=side, w=w)
384394
for i, d in enumerate(space_dims)])
385395

386396
@property
@@ -390,7 +400,7 @@ def laplace(self):
390400
"""
391401
return self.laplacian()
392402

393-
def laplacian(self, shift=None, order=None, method='FD', **kwargs):
403+
def laplacian(self, shift=None, order=None, method='FD', side=None, **kwargs):
394404
"""
395405
Laplacian of the VectorFunction, creates the Laplacian VectorFunction.
396406
@@ -404,6 +414,9 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
404414
method: str, optional, default='FD'
405415
Discretization method. Options are 'FD' (default) and
406416
'RSFD' (rotated staggered grid finite-difference).
417+
side : Side or tuple of Side, optional, default=centered
418+
Side of the finite difference location, centered (at x), left (at x - 1)
419+
or right (at x + 1).
407420
weights/w: list, tuple, or dict, optional, default=None
408421
Custom weights for the finite
409422
"""
@@ -413,12 +426,13 @@ def laplacian(self, shift=None, order=None, method='FD', **kwargs):
413426
order = order or self.space_order
414427
space_dims = self.root_dimensions
415428
comps = [sum([getattr(s, 'd%s2' % d.name)(x0=shift_x0(shift, d, None, i),
416-
fd_order=order, w=w, method=method)
429+
fd_order=order, method=method,
430+
side=side, w=w)
417431
for i, d in enumerate(space_dims)])
418432
for s in self]
419433
return func._new(comps)
420434

421-
def curl(self, shift=None, order=None, method='FD', **kwargs):
435+
def curl(self, shift=None, order=None, method='FD', side=None, **kwargs):
422436
"""
423437
Gradient of the (3D) VectorFunction, creates the curl VectorFunction.
424438
@@ -432,6 +446,9 @@ def curl(self, shift=None, order=None, method='FD', **kwargs):
432446
method: str, optional, default='FD'
433447
Discretization method. Options are 'FD' (default) and
434448
'RSFD' (rotated staggered grid finite-difference).
449+
side : Side or tuple of Side, optional, default=centered
450+
Side of the finite difference location, centered (at x), left (at x - 1)
451+
or right (at x + 1).
435452
weights/w: list, tuple, or dict, optional, default=None
436453
Custom weights for the finite difference coefficients.
437454
"""
@@ -444,21 +461,27 @@ def curl(self, shift=None, order=None, method='FD', **kwargs):
444461
shift_x0 = make_shift_x0(shift, (len(dims), len(dims)))
445462
order = order or self.space_order
446463
comp1 = (getattr(self[2], derivs[1])(x0=shift_x0(shift, dims[1], 2, 1),
447-
fd_order=order, method=method, w=w) -
464+
fd_order=order, method=method,
465+
side=side, w=w) -
448466
getattr(self[1], derivs[2])(x0=shift_x0(shift, dims[2], 1, 2),
449-
fd_order=order, method=method, w=w))
467+
fd_order=order, method=method,
468+
side=side, w=w))
450469
comp2 = (getattr(self[0], derivs[2])(x0=shift_x0(shift, dims[2], 0, 2),
451-
fd_order=order, method=method, w=w) -
470+
fd_order=order, method=method,
471+
side=side, w=w) -
452472
getattr(self[2], derivs[0])(x0=shift_x0(shift, dims[0], 2, 0),
453-
fd_order=order, method=method, w=w))
473+
fd_order=order, method=method,
474+
side=side, w=w))
454475
comp3 = (getattr(self[1], derivs[0])(x0=shift_x0(shift, dims[0], 1, 0),
455-
fd_order=order, method=method, w=w) -
476+
fd_order=order, method=method,
477+
side=side, w=w) -
456478
getattr(self[0], derivs[1])(x0=shift_x0(shift, dims[1], 0, 1),
457-
fd_order=order, method=method, w=w))
479+
fd_order=order, method=method,
480+
side=side, w=w))
458481
func = vec_func(self)
459482
return func._new(3, 1, [comp1, comp2, comp3])
460483

461-
def grad(self, shift=None, order=None, method='FD', **kwargs):
484+
def grad(self, shift=None, order=None, method='FD', side=None, **kwargs):
462485
"""
463486
Gradient of the VectorFunction, creates the gradient TensorFunction.
464487
@@ -472,6 +495,9 @@ def grad(self, shift=None, order=None, method='FD', **kwargs):
472495
method: str, optional, default='FD'
473496
Discretization method. Options are 'FD' (default) and
474497
'RSFD' (rotated staggered grid finite-difference).
498+
side : Side or tuple of Side, optional, default=centered
499+
Side of the finite difference location, centered (at x), left (at x - 1)
500+
or right (at x + 1).
475501
weights/w: list, tuple, or dict, optional, default=None
476502
Custom weights for the finite difference coefficients.
477503
"""
@@ -481,8 +507,9 @@ def grad(self, shift=None, order=None, method='FD', **kwargs):
481507
shift_x0 = make_shift_x0(shift, (ndim, ndim))
482508
order = order or self.space_order
483509
space_dims = self.root_dimensions
484-
comps = [[getattr(f, 'd%s' % d.name)(x0=shift_x0(shift, d, i, j), w=w,
485-
fd_order=order, method=method)
510+
comps = [[getattr(f, 'd%s' % d.name)(x0=shift_x0(shift, d, i, j),
511+
fd_order=order, method=method,
512+
side=side, w=w)
486513
for j, d in enumerate(space_dims)]
487514
for i, f in enumerate(self)]
488515
return func._new(comps)

0 commit comments

Comments
 (0)