beamax.solvers.kwave_solver
Wrapper around k-wave-python for forward, time reversal, and adjoint workflows.
Notes
- Optional dependency: install with
pip install .[kwave]. - Supports 2D/3D k-Wave backends.
API Reference
beamax.solvers.kwave_solver
KWaveSolver(simulation_options=None, execution_options=None, **kwargs)
Bases: Solver
:mod:k-wave-python wrapper (2D/3D) for forward, time-reversal, and adjoint solves.
Provides a :class:beamax.solvers.Solver-compatible interface backed by
the k-Wave pseudo-spectral time-domain solver. Used as the "reference" in
examples and as the low-frequency leg of :class:HybridSolver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
simulation_options
|
SimulationOptions
|
Legacy simulation-options object. If provided with
|
None
|
execution_options
|
SimulationExecutionOptions
|
Legacy execution-options object. See |
None
|
**kwargs
|
Unified k-Wave arguments forwarded to
:func: |
{}
|
Notes
- Requires the
[kwave]extra (pip install 'beamax[kwave]'). - Boundary handling uses a PML; :attr:
Domain.periodicflags control PML-inside vs. PML-outside placement via the k-Wave options. - Forward solves run on the C++ backend by default; time-reversal and
adjoint currently fall back to the pure-Python backend until the
upstream
CppSimulationpath ships source preprocessing for time-varying pressure sources. binary_pathcan be supplied directly or viaBEAMAX_KWAVE_BINARY_PATH. Direct kwargs take precedence.
Examples:
>>> import jax.numpy as jnp
>>> from beamax import Domain, Sensor
>>> from beamax.solvers import KWaveSolver
>>> domain = Domain(N=(64, 64), dx=(1e-3, 1e-3), c=1500.0, periodic=(False, False))
>>> solver = KWaveSolver(pml_size=10, device="cpu")
Initialize k-Wave solver options.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
simulation_options
|
SimulationOptions
|
Legacy simulation options object. |
None
|
execution_options
|
SimulationExecutionOptions
|
Legacy execution options object. |
None
|
**kwargs
|
Unified keyword options forwarded to
:func: |
{}
|
forward(p0: Union[np.ndarray, jnp.ndarray], domain: Domain, sensors: Union[np.ndarray, jnp.ndarray], ts: Union[np.ndarray, jnp.ndarray], *, record: str = 'p') -> np.ndarray
Forward k-Wave simulation for linear wave equation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
p0
|
array
|
Initial pressure. |
required |
domain
|
Domain
|
|
required |
sensors
|
array
|
Sensor mask or positions (solver expects mask). |
required |
ts
|
(array, shape(Nt))
|
|
required |
record
|
('p', ...)
|
Quantity to record. |
"p"
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Sensor time series |
time_reversal(data: Union[np.ndarray, jnp.ndarray], domain, sensors, sources, ts: Union[np.ndarray, jnp.ndarray], *, record: str = 'p_final', data_layout: str = 'auto') -> np.ndarray
Run classic k-Wave time reversal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
(ndarray or ndarray, shape(Ns, Nt) or (Nt, Ns))
|
Sensor measurements. |
required |
domain
|
Domain
|
Reconstruction domain. |
required |
sensors
|
array - like
|
Sensor mask. |
required |
sources
|
array - like
|
Source mask where the reversed data are injected. |
required |
ts
|
(ndarray or ndarray, shape(Nt))
|
Time grid. |
required |
record
|
str
|
k-Wave field to return. |
"p_final"
|
data_layout
|
('auto', 'ns_nt', 'nt_ns')
|
Sensor-data layout interpretation. |
"auto"
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Requested k-Wave record. |
Notes
Enforces p(x_s, t) = sensor_data(t, x_s) as a Dirichlet source.
adjoint(data: Union[np.ndarray, jnp.ndarray], domain, sensors, sources, ts: Union[np.ndarray, jnp.ndarray], *, record: str = 'p_final', data_layout: str = 'auto') -> np.ndarray
k-Wave adjoint following MATLAB demo convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
(array, shape(Ns, Nt) or (Nt, Ns))
|
Sensor measurements. |
required |
domain
|
Domain
|
|
required |
sensors
|
array
|
Sensor mask. |
required |
sources
|
array
|
Source mask. |
required |
ts
|
(array, shape(Nt))
|
|
required |
record
|
str
|
What to record at the end (e.g., "p_final"). |
'p_final'
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Adjoint image |
Based off the original MATLAB k-Wave adjoint example: https://github.com/ucl-bug/k-wave/blob/main/k-Wave/examples/example_pr_2D_adjoint.m
|
|
TimedKWaveSolver(*args, mode: str = 'stdout', **kwargs)
Bases: KWaveSolver
k-Wave wrapper that also returns a timing.
Timing modes
mode="stdout" (default):
Parse k-Wave's own "Total execution time:
mode="wall":
Wall-clock around the internal _run() call (includes whatever k-Wave
does internally, excludes your pre/post Python work).
Initialize timed k-Wave solver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*args
|
Positional arguments forwarded to :class: |
()
|
|
mode
|
('stdout', 'wall')
|
Timing mode. |
"stdout"
|
**kwargs
|
Keyword arguments forwarded to :class: |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
forward(p0, domain, sensors, ts, *, record: str = 'p', **solver_kwargs) -> Tuple[np.ndarray, float]
Same as KWaveSolver.forward, but returns (result, seconds).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
p0
|
array - like
|
Initial pressure. |
required |
domain
|
Domain
|
Computational domain. |
required |
sensors
|
array - like
|
Sensor mask or positions. |
required |
ts
|
(array - like, shape(Nt))
|
Time grid. |
required |
record
|
str
|
k-Wave field to record. |
"p"
|
**solver_kwargs
|
Additional solver keyword arguments. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
result |
ndarray
|
Forward simulation result. |
seconds |
float
|
Execution time. |
time_reversal(data, domain, sensors, sources, ts, *, record: str = 'p_final', data_layout: str = 'auto', **solver_kwargs) -> Tuple[np.ndarray, float]
Same as KWaveSolver.time_reversal, but returns (result, seconds).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
array - like
|
Sensor measurements. |
required |
domain
|
Domain
|
Reconstruction domain. |
required |
sensors
|
array - like
|
Sensor mask. |
required |
sources
|
array - like
|
Source mask. |
required |
ts
|
(array - like, shape(Nt))
|
Time grid. |
required |
record
|
str
|
k-Wave field to return. |
"p_final"
|
data_layout
|
('auto', 'ns_nt', 'nt_ns')
|
Sensor-data layout interpretation. |
"auto"
|
**solver_kwargs
|
Additional solver keyword arguments. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
result |
ndarray
|
Time-reversal result. |
seconds |
float
|
Execution time. |
adjoint(data, domain, sensors, sources, ts, *, record: str = 'p_final', data_layout: str = 'auto', **solver_kwargs) -> Tuple[np.ndarray, float]
Same as KWaveSolver.adjoint, but returns (result, seconds).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
array - like
|
Sensor measurements. |
required |
domain
|
Domain
|
Reconstruction domain. |
required |
sensors
|
array - like
|
Sensor mask. |
required |
sources
|
array - like
|
Source mask. |
required |
ts
|
(array - like, shape(Nt))
|
Time grid. |
required |
record
|
str
|
k-Wave field to return. |
"p_final"
|
data_layout
|
('auto', 'ns_nt', 'nt_ns')
|
Sensor-data layout interpretation. |
"auto"
|
**solver_kwargs
|
Additional solver keyword arguments. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
result |
ndarray
|
Adjoint result. |
seconds |
float
|
Execution time. |