From 17c53c159f13e1187d4f641b6706ff4709e3968e Mon Sep 17 00:00:00 2001 From: mloubout Date: Fri, 8 Mar 2024 10:44:12 -0500 Subject: [PATCH] api: fix staggered FD corner case and enforce satggered case to be valid staggering --- devito/finite_differences/derivative.py | 2 + .../finite_differences/finite_difference.py | 9 ++- devito/finite_differences/rsfd.py | 4 +- devito/finite_differences/tools.py | 17 +++-- examples/seismic/elastic/elastic_example.py | 2 +- examples/seismic/tti/operators.py | 22 +++---- examples/seismic/tti/wavesolver.py | 10 +-- .../06_elastic_varying_parameters.ipynb | 66 +++++++++---------- .../viscoelastic/viscoelastic_example.py | 2 +- tests/test_derivatives.py | 34 ++++++---- 10 files changed, 86 insertions(+), 82 deletions(-) diff --git a/devito/finite_differences/derivative.py b/devito/finite_differences/derivative.py index 9e134541707..21dda752362 100644 --- a/devito/finite_differences/derivative.py +++ b/devito/finite_differences/derivative.py @@ -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 diff --git a/devito/finite_differences/finite_difference.py b/devito/finite_differences/finite_difference.py index 187f29df782..718d0242259 100644 --- a/devito/finite_differences/finite_difference.py +++ b/devito/finite_differences/finite_difference.py @@ -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, @@ -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, @@ -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' @@ -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) diff --git a/devito/finite_differences/rsfd.py b/devito/finite_differences/rsfd.py index 3a98336910d..f8b48682a7b 100644 --- a/devito/finite_differences/rsfd.py +++ b/devito/finite_differences/rsfd.py @@ -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 @@ -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 diff --git a/devito/finite_differences/tools.py b/devito/finite_differences/tools.py index 0b6f9b9fef3..be5b94d51f2 100644 --- a/devito/finite_differences/tools.py +++ b/devito/finite_differences/tools.py @@ -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) @@ -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) @@ -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 diff --git a/examples/seismic/elastic/elastic_example.py b/examples/seismic/elastic/elastic_example.py index bd1845baaa7..bc2d56af9af 100644 --- a/examples/seismic/elastic/elastic_example.py +++ b/examples/seismic/elastic/elastic_example.py @@ -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)]) diff --git a/examples/seismic/tti/operators.py b/examples/seismic/tti/operators.py index b7813fd772b..227ebabdd52 100644 --- a/examples/seismic/tti/operators.py +++ b/examples/seismic/tti/operators.py @@ -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) @@ -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) @@ -277,14 +275,14 @@ 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) @@ -292,16 +290,16 @@ def kernel_staggered_2d(model, u, v, **kwargs): 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)) diff --git a/examples/seismic/tti/wavesolver.py b/examples/seismic/tti/wavesolver.py index 982731f0319..d797a685344 100644 --- a/examples/seismic/tti/wavesolver.py +++ b/examples/seismic/tti/wavesolver.py @@ -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 @@ -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 @@ -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 diff --git a/examples/seismic/tutorials/06_elastic_varying_parameters.ipynb b/examples/seismic/tutorials/06_elastic_varying_parameters.ipynb index 5e77fec46b1..c52ad836c8f 100644 --- a/examples/seismic/tutorials/06_elastic_varying_parameters.ipynb +++ b/examples/seismic/tutorials/06_elastic_varying_parameters.ipynb @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, diff --git a/examples/seismic/viscoelastic/viscoelastic_example.py b/examples/seismic/viscoelastic/viscoelastic_example.py index 7d4fba7b47f..045aef18000 100644 --- a/examples/seismic/viscoelastic/viscoelastic_example.py +++ b/examples/seismic/viscoelastic/viscoelastic_example.py @@ -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)]) diff --git a/tests/test_derivatives.py b/tests/test_derivatives.py index 8fd43630e56..e6f5849925b 100644 --- a/tests/test_derivatives.py +++ b/tests/test_derivatives.py @@ -265,14 +265,14 @@ def test_fd_space(self, derivative, space_order): @pytest.mark.parametrize('staggered', [(True, True), (False, False), (True, False), (False, True)]) @pytest.mark.parametrize('space_order', [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]) - def test_fd_space_45(self, staggered, space_order): + @pytest.mark.parametrize('ndim', [2, 3]) + def test_fd_space_45(self, staggered, space_order, ndim): """ Rotated derivatives require at least 2D to get access to diagonal points. We create a simple 1D gradient over a 2D grid to check against a polynomial """ # dummy axis dimension nx = 100 - ny = nx xx = np.linspace(-1, 1, nx) dx = xx[1] - xx[0] if staggered[0] and not staggered[1]: @@ -282,7 +282,7 @@ def test_fd_space_45(self, staggered, space_order): else: xx_s = xx # Symbolic data - grid = Grid(shape=(nx, ny), dtype=np.float32) + grid = Grid(shape=tuple([nx]*ndim), dtype=np.float32) x = grid.dimensions[0] u = Function(name="u", grid=grid, space_order=space_order, staggered=None if staggered[0] else grid.dimensions) @@ -293,8 +293,7 @@ def test_fd_space_45(self, staggered, space_order): polynome = sum([coeffs[i]*x**i for i in range(0, space_order)]) polyvalues = np.array([polynome.subs(x, xi) for xi in xx], np.float32) # Fill original data with the polynomial values - for i in range(ny): - u.data[:, i] = polyvalues + u.data[:] = polyvalues.reshape(nx, *[1]*(ndim-1)) # True derivative of the polynome Dpolynome = diff(polynome) Dpolyvalues = np.array([Dpolynome.subs(x, xi) for xi in xx_s], np.float32) @@ -307,13 +306,15 @@ def test_fd_space_45(self, staggered, space_order): # Check exactness of the numerical derivative except inside space_brd space_border = space_order - error = abs(du.data[space_border:-space_border, ny//2] - + mid = tuple([slice(space_border, -space_border, 1)] + + [nx//2 for i in range(ndim-1)]) + error = abs(du.data[mid] - Dpolyvalues[space_border:-space_border]) assert np.isclose(np.mean(error), 0., atol=1e-3) - @pytest.mark.parametrize('space_order', [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]) @pytest.mark.parametrize('stagger', [centered, left, right]) + @pytest.mark.parametrize('space_order', [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]) # Only test x and t as y and z are the same as x def test_fd_space_staggered(self, space_order, stagger): """ @@ -333,26 +334,32 @@ def test_fd_space_staggered(self, space_order, stagger): if stagger == left: off = -.5 side = -x - xx2 = xx + off * dx + xx_u = xx + off * dx + duside = NODE + xx_du = xx elif stagger == right: off = .5 side = x - xx2 = xx + off * dx + xx_u = xx + off * dx + duside = NODE + xx_du = xx else: side = NODE - xx2 = xx + xx_u = xx + xx_du = xx + .5 * dx + duside = x u = Function(name="u", grid=grid, space_order=space_order, staggered=side) - du = Function(name="du", grid=grid, space_order=space_order, staggered=side) + du = Function(name="du", grid=grid, space_order=space_order, staggered=duside) # Define polynomial with exact fd coeffs = np.ones((space_order-1,), dtype=np.float32) polynome = sum([coeffs[i]*x**i for i in range(0, space_order-1)]) - polyvalues = np.array([polynome.subs(x, xi) for xi in xx2], np.float32) + polyvalues = np.array([polynome.subs(x, xi) for xi in xx_u], np.float32) # Fill original data with the polynomial values u.data[:] = polyvalues # True derivative of the polynome Dpolynome = diff(polynome) - Dpolyvalues = np.array([Dpolynome.subs(x, xi) for xi in xx2], np.float32) + Dpolyvalues = np.array([Dpolynome.subs(x, xi) for xi in xx_du], np.float32) # Compute numerical FD stencil = Eq(du, u.dx) op = Operator(stencil, subs={x.spacing: dx}) @@ -788,6 +795,7 @@ def test_dx2(self): assert isinstance(term0, EvalDerivative) term1 = f.dx2._evaluate(expand=False) + print(type(term1)) assert isinstance(term1, DiffDerivative) assert term1.depth == 1 term1 = term1.evaluate