Skip to content

Commit

Permalink
api: fix staggered FD corner case and enforce satggered case to be va…
Browse files Browse the repository at this point in the history
…lid staggering
  • Loading branch information
mloubout committed Mar 8, 2024
1 parent ae85ddf commit 17c53c1
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 82 deletions.
2 changes: 2 additions & 0 deletions devito/finite_differences/derivative.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ def _eval_at(self, func):
"""
# If an x0 already exists do not overwrite it
x0 = self.x0 or dict(func.indices_ref._getters)
# expr_x0 = self.expr.indices_ref._getters
# x0 = {k: v for k, v in x0.items() if k in self.dims and expr_x0[k] is not v}
if self.expr.is_Add:
# If `expr` has both staggered and non-staggered terms such as
# `(u(x + h_x/2) + v(x)).dx` then we exploit linearity of FD to split
Expand Down
9 changes: 4 additions & 5 deletions devito/finite_differences/finite_difference.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def cross_derivative(expr, dims, fd_order, deriv_order, x0=None, **kwargs):
finite difference. Defaults to `direct`.
x0 : dict, optional
Origin of the finite-difference scheme as a map dim: origin_dim.
coefficients : strong, optional
coefficients : string, optional
Use taylor or custom coefficients (weights). Defaults to taylor.
expand : bool, optional
If True, the derivative is fully expanded as a sum of products,
Expand Down Expand Up @@ -189,7 +189,7 @@ def generic_derivative(expr, dim, fd_order, deriv_order, matvec=direct, x0=None,
finite difference. Defaults to `direct`.
x0 : dict, optional
Origin of the finite-difference scheme as a map dim: origin_dim.
coefficients : strong, optional
coefficients : string, optional
Use taylor or custom coefficients (weights). Defaults to taylor.
expand : bool, optional
If True, the derivative is fully expanded as a sum of products,
Expand All @@ -201,12 +201,12 @@ def generic_derivative(expr, dim, fd_order, deriv_order, matvec=direct, x0=None,
``deriv-order`` derivative of ``expr``.
"""
side = None
# First order derivative with 2nd order FD is highly non-recommended so taking
# First order derivative with 2nd order FD is strongly discouraged so taking
# first order fd that is a lot better
if deriv_order == 1 and fd_order == 2 and coefficients != 'symbolic':
fd_order = 1

# Enforce sable time coefficients
# Enforce stable time coefficients
if dim.is_Time and coefficients != 'symbolic':
coefficients = 'taylor'

Expand All @@ -219,7 +219,6 @@ def make_derivative(expr, dim, fd_order, deriv_order, side, matvec, x0, coeffici
# The stencil indices
indices, x0 = generate_indices(expr, dim, fd_order, side=side, matvec=matvec,
x0=x0)

# Finite difference weights corresponding to the indices. Computed via the
# `coefficients` method (`taylor` or `symbolic`)
weights = fd_weights_registry[coefficients](expr, deriv_order, indices, x0)
Expand Down
4 changes: 2 additions & 2 deletions devito/finite_differences/rsfd.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def drot(expr, dim, dir=1, x0=None):
Rotated finite differences based on:
https://www.sciencedirect.com/science/article/pii/S0165212599000232
The rotated axis (the four diagonals of a cube) are:
The rotated axes (the four diagonals of a cube) are:
d1 = dx/dr x + dz/dl y + dy/dl z
d2 = dx/dl x + dz/dl y - dy/dr z
d3 = dx/dr x - dz/dl y + dy/dl z
Expand Down Expand Up @@ -131,7 +131,7 @@ def d45(expr, dim, x0=None, expand=True):
Expand the expression. Defaults to True.
"""
# Make sure the grid supports RSFD
if expr.grid.dim == 1:
if expr.grid.dim not in [2, 3]:
raise ValueError('RSFD only supported in 2D and 3D')

# Diagonals weights
Expand Down
17 changes: 11 additions & 6 deletions devito/finite_differences/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def generate_indices(expr, dim, order, side=None, matvec=None, x0=None):
-------
An IndexSet, representing an ordered list of indices.
"""
if expr.is_Staggered and not dim.is_Time:
if expr.is_Staggered and not dim.is_Time and side is None:
x0, indices = generate_indices_staggered(expr, dim, order, side=side, x0=x0)
else:
x0 = (x0 or {dim: dim}).get(dim, dim)
Expand Down Expand Up @@ -363,7 +363,7 @@ def generate_indices_staggered(expr, dim, order, side=None, x0=None):
indices = [start - diff/2, start + diff/2]
indices = IndexSet(dim, indices)
else:
o_min = -order//2+1
o_min = -order//2 + 1
o_max = order//2

d = make_stencil_dimension(expr, o_min, o_max)
Expand All @@ -374,11 +374,16 @@ def generate_indices_staggered(expr, dim, order, side=None, x0=None):
indices = [start, start - diff]
indices = IndexSet(dim, indices)
else:
o_min = -order//2
o_max = order//2

if start is dim:
o_min = -order//2 + 1
o_max = order//2
start = dim + diff/2
else:
o_min = -order//2
o_max = order//2 - 1
start = dim
d = make_stencil_dimension(expr, o_min, o_max)
iexpr = start + d * diff
iexpr = ind0 + d * diff
indices = IndexSet(dim, expr=iexpr)

return start, indices
Expand Down
2 changes: 1 addition & 1 deletion examples/seismic/elastic/elastic_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def run(shape=(50, 50), spacing=(20.0, 20.0), tn=1000.0,
def test_elastic(dtype):
_, _, _, [rec1, rec2, v, tau] = run(dtype=dtype)
assert np.isclose(norm(rec1), 19.25636, atol=1e-3, rtol=0)
assert np.isclose(norm(rec2), 0.627606, atol=1e-3, rtol=0)
assert np.isclose(norm(rec2), 0.644412, atol=1e-3, rtol=0)


@pytest.mark.parametrize('shape', [(51, 51), (16, 16, 16)])
Expand Down
22 changes: 10 additions & 12 deletions examples/seismic/tti/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ def particle_velocity_fields(model, space_order):
x, z = model.space_dimensions
stagg_x = x
stagg_z = z
x, z = model.grid.dimensions
# Create symbols for forward wavefield, source and receivers
vx = TimeFunction(name='vx', grid=model.grid, staggered=stagg_x,
time_order=1, space_order=space_order)
Expand All @@ -235,7 +234,6 @@ def particle_velocity_fields(model, space_order):
stagg_x = x
stagg_y = y
stagg_z = z
x, y, z = model.grid.dimensions
# Create symbols for forward wavefield, source and receivers
vx = TimeFunction(name='vx', grid=model.grid, staggered=stagg_x,
time_order=1, space_order=space_order)
Expand Down Expand Up @@ -277,31 +275,31 @@ def kernel_staggered_2d(model, u, v, **kwargs):

if forward:
# Stencils
phdx = costheta * u.dx - sintheta * u.dy
phdx = costheta * u.dx - sintheta * u.dyc
u_vx = Eq(vx.forward, dampl * vx - dampl * s * phdx)

pvdz = sintheta * v.dx + costheta * v.dy
pvdz = sintheta * v.dxc + costheta * v.dy
u_vz = Eq(vz.forward, dampl * vz - dampl * s * pvdz)

dvx = costheta * vx.forward.dx - sintheta * vx.forward.dy
dvz = sintheta * vz.forward.dx + costheta * vz.forward.dy
dvx = costheta * vx.forward.dx - sintheta * vx.forward.dyc
dvz = sintheta * vz.forward.dxc + costheta * vz.forward.dy

# u and v equations
pv_eq = Eq(v.forward, dampl * (v - s / m * (delta * dvx + dvz)) + s / m * qv)
ph_eq = Eq(u.forward, dampl * (u - s / m * (epsilon * dvx + delta * dvz)) +
s / m * qu)
else:
# Stencils
phdx = ((costheta*epsilon*u).dx - (sintheta*epsilon*u).dy +
(costheta*delta*v).dx - (sintheta*delta*v).dy)
phdx = ((costheta*epsilon*u).dx - (sintheta*epsilon*u).dyc +
(costheta*delta*v).dxc - (sintheta*delta*v).dy)
u_vx = Eq(vx.backward, dampl * vx + dampl * s * phdx)

pvdz = ((sintheta*delta*u).dx + (costheta*delta*u).dy +
(sintheta*v).dx + (costheta*v).dy)
pvdz = ((sintheta*delta*u).dx + (costheta*delta*u).dyc +
(sintheta*v).dxc + (costheta*v).dy)
u_vz = Eq(vz.backward, dampl * vz + dampl * s * pvdz)

dvx = (costheta * vx.backward).dx - (sintheta * vx.backward).dy
dvz = (sintheta * vz.backward).dx + (costheta * vz.backward).dy
dvx = (costheta * vx.backward).dx - (sintheta * vx.backward).dyc
dvz = (sintheta * vz.backward).dxc + (costheta * vz.backward).dy

# u and v equations
pv_eq = Eq(v.backward, dampl * (v + s / m * dvz))
Expand Down
10 changes: 3 additions & 7 deletions examples/seismic/tti/wavesolver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# coding: utf-8
from devito import (Function, TimeFunction, warning,
from devito import (Function, TimeFunction, warning, NODE,
DevitoCheckpoint, CheckpointOperator, Revolver)
from devito.tools import memoized_meth
from examples.seismic.tti.operators import ForwardOperator, AdjointOperator
Expand Down Expand Up @@ -118,9 +118,7 @@ def forward(self, src=None, rec=None, u=None, v=None, model=None,
"""
if self.kernel == 'staggered':
time_order = 1
dims = self.model.space_dimensions
stagg_u = (-dims[-1])
stagg_v = (-dims[0], -dims[1]) if self.model.grid.dim == 3 else (-dims[0])
stagg_u = stagg_v = NODE
else:
time_order = 2
stagg_u = stagg_v = None
Expand Down Expand Up @@ -193,9 +191,7 @@ def adjoint(self, rec, srca=None, p=None, r=None, model=None,
"""
if self.kernel == 'staggered':
time_order = 1
dims = self.model.space_dimensions
stagg_p = (-dims[-1])
stagg_r = (-dims[0], -dims[1]) if self.model.grid.dim == 3 else (-dims[0])
stagg_p = stagg_r = NODE
else:
time_order = 2
stagg_p = stagg_r = None
Expand Down
66 changes: 31 additions & 35 deletions examples/seismic/tutorials/06_elastic_varying_parameters.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -392,22 +392,22 @@
"name": "stderr",
"output_type": "stream",
"text": [
"Operator `Kernel` ran in 0.23 s\n"
"Operator `Kernel` ran in 0.24 s\n"
]
},
{
"data": {
"text/plain": [
"PerformanceSummary([(PerfKey(name='section0', rank=None),\n",
" PerfEntry(time=0.20520499999999994, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.2058980000000001, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section1', rank=None),\n",
" PerfEntry(time=0.005932999999999998, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.006354999999999981, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section2', rank=None),\n",
" PerfEntry(time=0.006593000000000015, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.007110000000000014, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section3', rank=None),\n",
" PerfEntry(time=0.005976000000000029, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.006563000000000019, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section4', rank=None),\n",
" PerfEntry(time=0.00602000000000003, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
" PerfEntry(time=0.006876000000000027, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
]
},
"execution_count": 14,
Expand Down Expand Up @@ -511,22 +511,22 @@
"name": "stderr",
"output_type": "stream",
"text": [
"Operator `Kernel` ran in 0.27 s\n"
"Operator `Kernel` ran in 0.31 s\n"
]
},
{
"data": {
"text/plain": [
"PerformanceSummary([(PerfKey(name='section0', rank=None),\n",
" PerfEntry(time=0.23217499999999996, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.24031900000000017, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section1', rank=None),\n",
" PerfEntry(time=0.008015000000000006, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.015194000000000017, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section2', rank=None),\n",
" PerfEntry(time=0.012265999999999938, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.015348, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section3', rank=None),\n",
" PerfEntry(time=0.007797000000000036, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.015376999999999998, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section4', rank=None),\n",
" PerfEntry(time=0.009437999999999978, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
" PerfEntry(time=0.015624999999999997, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
]
},
"execution_count": 17,
Expand Down Expand Up @@ -699,20 +699,20 @@
"name": "stderr",
"output_type": "stream",
"text": [
"Operator `Kernel` ran in 0.24 s\n"
"Operator `Kernel` ran in 0.23 s\n"
]
},
{
"data": {
"text/plain": [
"PerformanceSummary([(PerfKey(name='section0', rank=None),\n",
" PerfEntry(time=0.21262299999999978, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.20202699999999996, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section1', rank=None),\n",
" PerfEntry(time=0.008176999999999999, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.007293999999999994, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section2', rank=None),\n",
" PerfEntry(time=0.008674000000000015, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.007614000000000006, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section3', rank=None),\n",
" PerfEntry(time=0.008485000000000003, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
" PerfEntry(time=0.007164000000000016, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
]
},
"execution_count": 24,
Expand Down Expand Up @@ -796,20 +796,20 @@
"name": "stderr",
"output_type": "stream",
"text": [
"Operator `Kernel` ran in 0.25 s\n"
"Operator `Kernel` ran in 0.23 s\n"
]
},
{
"data": {
"text/plain": [
"PerformanceSummary([(PerfKey(name='section0', rank=None),\n",
" PerfEntry(time=0.2165199999999999, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.19974000000000014, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section1', rank=None),\n",
" PerfEntry(time=0.00951100000000004, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.007187999999999981, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section2', rank=None),\n",
" PerfEntry(time=0.01492799999999995, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.007523000000000016, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section3', rank=None),\n",
" PerfEntry(time=0.00861800000000002, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
" PerfEntry(time=0.007113000000000016, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
]
},
"execution_count": 26,
Expand Down Expand Up @@ -946,16 +946,12 @@
{
"data": {
"text/latex": [
"$\\displaystyle \\left(- \\frac{f(x - h_x, y - h_y)}{4 h_{x}} + \\frac{f(x + h_x, y + h_y)}{4 h_{x}}\\right) + \\left(- \\frac{f(x - h_x, y + h_y)}{4 h_{x}} + \\frac{f(x + h_x, y - h_y)}{4 h_{x}}\\right)$"
"$\\displaystyle \\left(\\frac{f(x, y)}{2 h_{x}} - \\frac{f(x - h_x, y - h_y)}{2 h_{x}}\\right) + \\left(\\frac{f(x, y)}{2 h_{x}} - \\frac{f(x - h_x, y + h_y)}{2 h_{x}}\\right)$"
],
"text/plain": [
" f(x - hₓ, y - h_y) f(x + hₓ, y + h_y) f(x - hₓ, y + h_y) f(x + hₓ, y\n",
"- ────────────────── + ────────────────── + - ────────────────── + ───────────\n",
" 4⋅hₓ 4⋅hₓ 4⋅hₓ 4⋅hₓ\n",
"\n",
" - h_y)\n",
"───────\n",
" "
"f(x, y) f(x - hₓ, y - h_y) f(x, y) f(x - hₓ, y + h_y)\n",
"─────── - ────────────────── + ─────── - ──────────────────\n",
" 2⋅hₓ 2⋅hₓ 2⋅hₓ 2⋅hₓ "
]
},
"execution_count": 32,
Expand Down Expand Up @@ -1023,15 +1019,15 @@
"data": {
"text/plain": [
"PerformanceSummary([(PerfKey(name='section0', rank=None),\n",
" PerfEntry(time=0.5155960000000004, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.5144760000000006, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section1', rank=None),\n",
" PerfEntry(time=0.011958000000000087, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.012137000000000096, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section2', rank=None),\n",
" PerfEntry(time=0.013548000000000008, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.013851000000000006, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section3', rank=None),\n",
" PerfEntry(time=0.012433999999999917, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" PerfEntry(time=0.012857999999999913, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[])),\n",
" (PerfKey(name='section4', rank=None),\n",
" PerfEntry(time=0.012537999999999919, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
" PerfEntry(time=0.012548999999999916, gflopss=0.0, gpointss=0.0, oi=0.0, ops=0, itershapes=[]))])"
]
},
"execution_count": 34,
Expand Down
2 changes: 1 addition & 1 deletion examples/seismic/viscoelastic/viscoelastic_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def run(shape=(50, 50), spacing=(20.0, 20.0), tn=1000.0,
def test_viscoelastic(dtype):
_, _, _, [rec1, rec2, v, tau] = run(dtype=dtype)
assert np.isclose(norm(rec1), 12.28040, atol=1e-3, rtol=0)
assert np.isclose(norm(rec2), 0.312461, atol=1e-3, rtol=0)
assert np.isclose(norm(rec2), 0.320738, atol=1e-3, rtol=0)


@pytest.mark.parametrize('shape', [(51, 51), (16, 16, 16)])
Expand Down
Loading

0 comments on commit 17c53c1

Please sign in to comment.