-
Notifications
You must be signed in to change notification settings - Fork 238
dsl: Superstep #2658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
dsl: Superstep #2658
Conversation
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:01Z "In Nemeth et al k=30 is chosen." |
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:01Z Line #3. src_term = source.inject(field=u.forward, expr=source*velocity*velocity*dt*dt)
|
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:02Z Typo: arguemnts
"the size of the superstep: k in the paper,
"Written in maths:" <- odd phrasing, reconsider |
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:03Z Line #1. # Should the timer context be removed??? Leftover? |
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:03Z Line #7. # Fetch and setup the Set up the what? |
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:04Z "we would have to redefine much of what we have done above." What would need redefining? |
View / edit / reply to this conversation on ReviewNB EdCaunt commented on 2025-07-04T10:14:05Z x10^-4 |
devito/timestepping/superstep.py
Outdated
|
||
def superstep_generator_iterative(field, stencil, k, tn=0): | ||
''' Generate superstep iteratively: | ||
A^j+1 = A·A^j |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some brackets here would improve readability and reduce ambiguity
# New fields, for vector formulation both current and previous timestep are needed | ||
name = field.name | ||
grid = field.grid | ||
u = TimeFunction(name=f'{name}_ss', grid=grid, time_order=2, space_order=2*k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I presume the space_order=2*k
is to ensure the halo is sufficiently wide for the operators? Would taking the space order from the original fields and using padding here be strictly more correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to use ._rebuild
(or .func
) to make sure it's consistent with field
u = field._rebuild(name=f'{name}_ss', space_order=2*k)
u_prev = field._rebuild(name=f'{name}_ss', space_order=2*k)
return u, u_prev, Eq(u.forward, stencil_next), Eq(u_prev.forward, current) | ||
|
||
|
||
def superstep_generator(field, stencil, k, tn=0): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there both superstep_generator
and superstep_generator_iterative
? There is also some code overlap between these two functions which should be consolidated. Perhaps a SuperStepGenerator
class with suitable methods?
ss_stencil = stencil.subs({field: u, field.backward: u_prev}, postprocess=False) | ||
ss_stencil = ss_stencil.expand().expand(add=True, nest=True) | ||
|
||
# Binary decomposition algorithm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: this could use more comments
''' Transfer state from a previous TimeFunction to a 2 field superstep | ||
Used after injecting source using standard timestepping. | ||
''' | ||
idx = tn % 3 if old.save is None else -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should check if there is a buffer, then either check the buffer size or take the last index, rather than hardcoding 3
''' | ||
# Placeholder fields for forming the superstep | ||
grid = u.grid | ||
a_tmp = Function(name="a_tmp", grid=grid, space_order=2*k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these Function
s just used as symbolic objects? If so, why not just use Symbol
?
data = acoustic_model(model, step=step, snapshots=m) | ||
time = np.linspace(model.t1, model.t2, (m - 1)//step + 1) | ||
idx = 0 | ||
for ii, ax in enumerate(ax_row): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would set up a separate plotting function for the contents of this loop to improve readability
|
||
|
||
def superstep_generator_iterative(field, stencil, k, tn=0): | ||
''' Generate superstep iteratively: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking: For consistency with codebase, use """ and start doctrine on next line"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seconded
# New fields, for vector formulation both current and previous timestep are needed | ||
name = field.name | ||
grid = field.grid | ||
u = TimeFunction(name=f'{name}_ss', grid=grid, time_order=2, space_order=2*k) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to use ._rebuild
(or .func
) to make sure it's consistent with field
u = field._rebuild(name=f'{name}_ss', space_order=2*k)
u_prev = field._rebuild(name=f'{name}_ss', space_order=2*k)
|
||
# Substitute new fields into stencil | ||
ss_stencil = stencil.subs({field: u, field.backward: u_prev}, postprocess=False) | ||
ss_stencil = ss_stencil.expand().expand(add=True, nest=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why double expand?
{u: a_tmp, u_prev: b_tmp}, postprocess=False).subs( | ||
{a_tmp: ss_stencil, b_tmp: u}, postprocess=False | ||
) | ||
current = current.expand().expand(add=True, nest=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same?
|
||
if k >= 2: | ||
for _ in range(k - 2): | ||
current = current.subs( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split in two lines for readability?
|
||
|
||
def marmousi(grid, step=0): | ||
# Grab dataset from pwd or download |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should just throw a warning/erro people should git clone the data repo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And it's a preset in the Model as well so this should be reusing the examples
# Stencil and operator | ||
idx = tn1 % 3 | ||
if step == 1: | ||
# Non-superstep case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get that case, it just copies into a new Function to do the same thing?
else: | ||
new_u, new_u_p, *stencil = superstep_generator(u, stencil.rhs, step) | ||
|
||
new_u.data[0, :] = u.data[idx - 1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why isn't superstep_generator doing that?
return u_save.data | ||
|
||
|
||
layered_model = model( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
USe existing preset
@@ -0,0 +1,114 @@ | |||
''' Script that demonstrates the functionality of the superstep in 2D |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a lot of duplicate from the 1D case, can probably be merged into one file with 1d/2d as input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces superstep functionality to Devito, enabling multi-step time advancement with larger effective time steps while maintaining stability. The implementation includes both iterative and binary decomposition algorithms for generating superstep operators.
- Adds core superstep generation functionality with two algorithmic approaches
- Provides comprehensive examples demonstrating 1D and 2D wave propagation scenarios
- Updates test configuration to support higher-order spatial discretizations
Reviewed Changes
Copilot reviewed 5 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
devito/timestepping/superstep.py | Core superstep implementation with generator functions and solution transfer utilities |
examples/timestepping/superstep_1d.py | 1D wave equation example demonstrating superstep functionality |
examples/timestepping/superstep_2d.py | 2D ripple simulation example with visualization |
examples/timestepping/acoustic_superstep_2d.py | Advanced 2D acoustic modeling with source injection and velocity models |
tests/test_pickle.py | Updates space_order from 2 to 4 for derivative testing |
Comments suppressed due to low confidence (2)
examples/timestepping/superstep_1d.py:49
- [nitpick] Variable name 'newu' is inconsistent with the naming convention used elsewhere in the codebase. Consider using 'new_u' to match the pattern used in line 55 and other files.
newu = u
examples/timestepping/acoustic_superstep_2d.py:28
- Class name 'model' should follow Python naming conventions and be capitalized as 'Model'.
class model:
b_tmp = Function(name="b_tmp", grid=grid, space_order=2*k) | ||
|
||
if k >= 2: | ||
for _ in range(k - 2): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The loop variable is unused. Consider using a more descriptive name like 'step' or 'iteration' to improve code readability, or use 'for step in range(k - 2):' if the index might be useful for debugging.
for _ in range(k - 2): | |
for step in range(k - 2): |
Copilot uses AI. Check for mistakes.
# 3 should be replaced with `old.time_order + 1` although this needs some thought | ||
idx = tn % 3 if old.save is None else -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO comment indicates incomplete implementation. The hardcoded value '3' should be replaced with a proper calculation based on time_order, or this limitation should be documented if intentional.
# 3 should be replaced with `old.time_order + 1` although this needs some thought | |
idx = tn % 3 if old.save is None else -1 | |
# Dynamically calculate the modulo base using `old.time_order + 1` | |
idx = tn % (old.time_order + 1) if old.save is None else -1 |
Copilot uses AI. Check for mistakes.
|
||
def marmousi(grid, step=0): | ||
# Grab dataset from pwd or download | ||
url = 'https://github.com/devitocodes/data/raw/refs/heads/master/Simple2D/vp_marmousi_bi' # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The long URL should be broken into multiple lines or stored as a constant to improve readability instead of using noqa comment.
url = 'https://github.com/devitocodes/data/raw/refs/heads/master/Simple2D/vp_marmousi_bi' # noqa: E501 | |
url = MARMOUSI_URL |
Copilot uses AI. Check for mistakes.
))) | ||
ax.set_xlim(model.origin[0], model.origin[0] + model.extent[0]) | ||
yticks = ax.get_yticks() | ||
ax.set_yticks(np.concat(((model.origin[1],), yticks[2::2]))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using np.concat with nested tuples is unnecessarily complex. Consider using np.concatenate([model.origin[1:2], yticks[2::2]]) or np.hstack for better readability.
ax.set_yticks(np.concat(((model.origin[1],), yticks[2::2]))) | |
ax.set_yticks(np.concatenate([model.origin[1:2], yticks[2::2]])) |
Copilot uses AI. Check for mistakes.
4fb9198
to
1268740
Compare
438a601
to
b1b0846
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2658 +/- ##
=======================================
Coverage ? 83.76%
=======================================
Files ? 248
Lines ? 49625
Branches ? 4366
=======================================
Hits ? 41569
Misses ? 7274
Partials ? 782
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somewhere, add a docstring referencing Tamas 's paper? or have I missed it?
Perhaps add it to a short README to examples/timestepping, which would also help navigating the directory?
|
||
|
||
def superstep_generator_iterative(field, stencil, k, tn=0): | ||
''' Generate superstep iteratively: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seconded
solve, | ||
) | ||
from devito.timestepping.superstep import superstep_generator | ||
from scipy.interpolate import interpn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imports from third-parties should go in between those from the stdlin and the devito ones
see here https://github.com/devitocodes/devito/blob/main/CONTRIBUTING.md#coding-guidelines
|
||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
from devito import ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blankline between third-party imports and devito imports
pde = (1/velocity**2)*u.dt2 - u.laplace | ||
stencil = Eq(u.forward, solve(pde, u.forward)) | ||
|
||
tn1 = int(np.ceil((t1 - t0)/model.critical_dt)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpicking, for homogeneity: why not just tn? rather, "nt", since it's "number of tiemsteps"?
new.data[0, :] = old.data[idx - 1] | ||
new.data[1, :] = old.data[idx] | ||
new_p.data[0, :] = old.data[idx - 2] | ||
new_p.data[1, :] = old.data[idx - 1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this is very suspicious...
However, you may as well throw a warning for now
Currently a PR into #2559 as the diff is smaller
Adds superstep functionality as well as example scripts and notebook