From be21ee71cb230ee5ff7871667dbf8d808c8df14e Mon Sep 17 00:00:00 2001 From: Edward Caunt Date: Wed, 10 Dec 2025 12:37:01 +0000 Subject: [PATCH 1/4] dsl: Tweak SpaceDimension lower bounds behaviour to use fewer registers --- devito/types/dimension.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devito/types/dimension.py b/devito/types/dimension.py index 6e000349e9..5764506936 100644 --- a/devito/types/dimension.py +++ b/devito/types/dimension.py @@ -457,6 +457,10 @@ class SpaceDimension(BasicDimension): is_Space = True + @property + def symbolic_min(self): + return sympy.S.Zero + class TimeDimension(BasicDimension): From 025d11a97c4c04319fd101d01c4d97185bf31b8d Mon Sep 17 00:00:00 2001 From: Edward Caunt Date: Fri, 12 Dec 2025 14:47:45 +0000 Subject: [PATCH 2/4] tests: Update tests --- tests/test_dimension.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_dimension.py b/tests/test_dimension.py index f43ae795eb..e2155685fc 100644 --- a/tests/test_dimension.py +++ b/tests/test_dimension.py @@ -754,7 +754,7 @@ def test_arrays_defined_over_subdims(self): op = Operator([Eq(a[xi], 1), Eq(f, f + a[xi + 1], subdomain=grid.interior)], opt=('advanced', {'openmp': False})) - assert len(op.parameters) == 6 + assert len(op.parameters) == 5 # neither `x_size` nor `xi_size` are expected here assert not any(i.name in ('x_size', 'xi_size') for i in op.parameters) # Try running it -- regardless of what it will produce, this should run @@ -779,6 +779,7 @@ def test_expandingbox_like(self, opt): op = Operator(eqn, opt=opt) + # TODO: Why are bounds overridden here? op.apply(time=3, x_m=2, x_M=5, y_m=2, y_M=5, x_ltkn0=0, x_rtkn0=0, y_ltkn0=0, y_rtkn0=0) From 95b7c388e9a4b16a6403ade9a27fa59f751d6355 Mon Sep 17 00:00:00 2001 From: Edward Caunt Date: Mon, 15 Dec 2025 15:05:55 +0000 Subject: [PATCH 3/4] examples: Update notebooks --- examples/seismic/tutorials/16_ader_fd.ipynb | 2 +- examples/userapi/02_apply.ipynb | 26 +++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/seismic/tutorials/16_ader_fd.ipynb b/examples/seismic/tutorials/16_ader_fd.ipynb index 27443675a5..758b3ba8d8 100644 --- a/examples/seismic/tutorials/16_ader_fd.ipynb +++ b/examples/seismic/tutorials/16_ader_fd.ipynb @@ -5,7 +5,7 @@ "id": "0", "metadata": {}, "source": [ - "# 15 - ADER-FD\n", + "# 16 - ADER-FD\n", "\n", "This notebook demonstrates the implementation of a finite-difference scheme for solving the first-order formulation of the acoustic wave equation using ADER (Arbitrary-order-accuracy via DERivatives) time integration. This enables a temporal discretisation up the order of the spatial discretisation, whilst preventing the grid-grid decoupling (often referred to as checkerboarding) associated with solving first-order systems of equations on a single finite-difference grid.\n", "\n", diff --git a/examples/userapi/02_apply.ipynb b/examples/userapi/02_apply.ipynb index 1c3fac6ae8..5106a7c7de 100644 --- a/examples/userapi/02_apply.ipynb +++ b/examples/userapi/02_apply.ipynb @@ -8,9 +8,9 @@ "\n", "This tutorial describes three fundamental user APIs:\n", "\n", - "* Operator.apply\n", - "* Operator.arguments\n", - "* Operator.estimate_memory\n", + "* `Operator.apply`\n", + "* `Operator.arguments`\n", + "* `Operator.estimate_memory`\n", "\n", "We will use a trivial `Operator` that, at each time step, increments by 1 all points in the physical domain." ] @@ -57,7 +57,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Under the hood, some code has been generated (`print(op)` to display the generated code), JIT-compiled, and executed. Since no additional arguments have been passed, `op` has used `u` as input. We can verify that the content of `u.data` is as expected" + "Under the hood, some code has been generated, JIT-compiled, and executed. Note that one can print `op.ccode` to display the generated code. Since no additional arguments have been passed, `op` has used `u` as input. We can verify that the content of `u.data` is as expected" ] }, { @@ -162,7 +162,7 @@ "source": [ "`'u'` stores a pointer to the allocated data; `'timers'` stores a pointer to a data structure used for C-level performance profiling.\n", "\n", - "One may want to replace some of these default arguments. For example, we could increase the minimum iteration point along the spatial Dimensions `x` and `y`, and execute only the very first timestep:" + "One may want to replace some of these default arguments. For example, we could reduce the maximum iteration point along the spatial Dimensions `x` and `y`, and execute only the very first timestep:" ] }, { @@ -174,14 +174,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "Operator `Kernel` run in 0.00 s\n" + "Operator `Kernel` ran in 0.01 s\n" ] } ], "source": [ "#NBVAL_IGNORE_OUTPUT\n", "u.data[:] = 0. # Explicit reset to initial value\n", - "summary = op.apply(x_m=2, y_m=2, time_M=0)" + "summary = op.apply(x_M=1, y_M=1, time_M=0)" ] }, { @@ -204,10 +204,10 @@ " [0., 0., 0., 0.],\n", " [0., 0., 0., 0.]],\n", "\n", - " [[0., 0., 0., 0.],\n", - " [0., 0., 0., 0.],\n", - " [0., 0., 1., 1.],\n", - " [0., 0., 1., 1.]],\n", + " [[1., 1., 1., 0.],\n", + " [1., 1., 1., 0.],\n", + " [1., 1., 1., 0.],\n", + " [0., 0., 0., 0.]],\n", "\n", " [[0., 0., 0., 0.],\n", " [0., 0., 0., 0.],\n", @@ -228,12 +228,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "Side note: in practice, iterating over a subset of the grid by directly overriding the minimum and maximum values of a dimension is not advised. Instead, a `SubDomain` interface is available for this purpose (detailed in tutorial `03_subdomains`).\n", + "\n", "Given a generic `Dimension` `d`, the naming convention is such that:\n", "\n", "* `d_m` is the minimum iteration point\n", "* `d_M` is the maximum iteration point\n", "\n", - "Hence, `op.apply(..., d_m=4, d_M=7, ...)` will run `op` in the compact interval `[4, 7]` along `d`. For historical reasons, `d=...` aliases to `d_M=...`; in many Devito examples it happens to see `op.apply(..., time=10, ...)` -- this is just equivalent to `op.apply(..., time_M=10, ...)`.\n", + "Hence, `op.apply(..., d_m=4, d_M=7, ...)` will run `op` in the compact interval `[4, 7]` along `d`. For historical reasons, `d=...` aliases to `d_M=...`; in many Devito examples it happens to see `op.apply(..., time=10, ...)` -- this is just equivalent to `op.apply(..., time_M=10, ...)`. `SpaceDimension`s, such as those attached to a `Grid` do not have a `d_m`, as these dimensions will essentially always be indexed from zero to `d_M` along each axis.\n", "\n", "If we try to specify an invalid iteration extreme, Devito will raise an exception." ] From 4f17e94fd61e2af5807c064acede2d78fdabf0d6 Mon Sep 17 00:00:00 2001 From: Edward Caunt Date: Mon, 15 Dec 2025 15:06:51 +0000 Subject: [PATCH 4/4] tests: Update tests based on x_m --- tests/test_dimension.py | 4 +--- tests/test_dle.py | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/test_dimension.py b/tests/test_dimension.py index e2155685fc..a31aa42bc3 100644 --- a/tests/test_dimension.py +++ b/tests/test_dimension.py @@ -779,9 +779,7 @@ def test_expandingbox_like(self, opt): op = Operator(eqn, opt=opt) - # TODO: Why are bounds overridden here? - op.apply(time=3, x_m=2, x_M=5, y_m=2, y_M=5, - x_ltkn0=0, x_rtkn0=0, y_ltkn0=0, y_rtkn0=0) + op.apply(time=3, x_ltkn0=2, x_rtkn0=2, y_ltkn0=2, y_rtkn0=2) assert np.all(u.data[0, 2:-2, 2:-2] == 4.) assert np.all(u.data[1, 2:-2, 2:-2] == 3.) diff --git a/tests/test_dle.py b/tests/test_dle.py index c49f3fa67b..c9d68236b7 100644 --- a/tests/test_dle.py +++ b/tests/test_dle.py @@ -146,7 +146,7 @@ def test_cache_blocking_structure_subdims(): # zi is rebuilt with name z, so check symbolic max and min are preserved # Also check the zi was rebuilt assert not tree[4].dim.is_Block and tree[4].dim is not zi and\ - str(tree[4].dim.symbolic_min) == 'z_m + z_ltkn0' and\ + str(tree[4].dim.symbolic_min) == 'z_ltkn0' and\ str(tree[4].dim.symbolic_max) == 'z_M - z_rtkn0' and\ tree[4].dim.parent is z @@ -536,7 +536,7 @@ def test_cache_blocking_imperfect_nest(blockinner): assert trees[0].root.dim.is_Block assert trees[1].root.dim.is_Block assert op1.parameters[7] is trees[0][0].step - assert op1.parameters[10] is trees[0][1].step + assert op1.parameters[9] is trees[0][1].step u.data[:] = 0.2 v.data[:] = 1.5 @@ -1380,7 +1380,7 @@ def test_nested_cache_blocking_structure_subdims(self, blocklevels): if blocklevels == 1: assert not tree[4].dim.is_Block and tree[4].dim is not zi and\ - str(tree[4].dim.symbolic_min) == 'z_m + z_ltkn0' and\ + str(tree[4].dim.symbolic_min) == 'z_ltkn0' and\ str(tree[4].dim.symbolic_max) == 'z_M - z_rtkn0' and\ tree[4].dim.parent is z elif blocklevels == 2: @@ -1391,7 +1391,7 @@ def test_nested_cache_blocking_structure_subdims(self, blocklevels): assert tree[5].dim.is_Block and tree[5].dim.parent is tree[3].dim and\ tree[5].dim.root is y assert not tree[6].dim.is_Block and tree[6].dim is not zi and\ - str(tree[6].dim.symbolic_min) == 'z_m + z_ltkn0' and\ + str(tree[6].dim.symbolic_min) == 'z_ltkn0' and\ str(tree[6].dim.symbolic_max) == 'z_M - z_rtkn0' and\ tree[6].dim.parent is z