Unified API (v0.6.0)

Starting with v0.6.0, kspaceFirstOrder() is the preferred way to run simulations. It replaces the legacy kspaceFirstOrder2D, kspaceFirstOrder3D, and their GPU variants with a single function that auto-detects dimensionality from the grid.

Quick Start

from kwave.kgrid import kWaveGrid
from kwave.kmedium import kWaveMedium
from kwave.ksource import kSource
from kwave.ksensor import kSensor
from kwave.kspaceFirstOrder import kspaceFirstOrder
import numpy as np

# Setup (works for 1D, 2D, or 3D — just change grid dimensions)
kgrid = kWaveGrid([128, 128], [0.1e-3, 0.1e-3])
kgrid.makeTime(1500)

medium = kWaveMedium(sound_speed=1500, density=1000)

source = kSource()
source.p0 = np.zeros((128, 128))
source.p0[64, 64] = 1.0

sensor = kSensor(mask=np.ones((128, 128), dtype=bool))

# Run with the NumPy/CuPy solver in Python
result = kspaceFirstOrder(kgrid, medium, source, sensor)

print(result["p"].shape)       # (16384, Nt) — time series at each sensor
print(result["p_final"].shape) # (128, 128)  — final pressure field

Backend and Device

Two independent choices control how the simulation runs:

  • backend selects the simulation engine:

    • "python" (default) — pure Python solver using NumPy or CuPy. No external dependencies beyond NumPy.

    • "cpp" — serializes to HDF5 and invokes the pre-compiled C++ binary. Requires FFTW (brew install fftw on macOS).

  • device selects the hardware:

    • "cpu" (default) — NumPy for backend="python", OMP binary for backend="cpp".

    • "gpu" — CuPy for backend="python" (requires CuPy + CUDA), CUDA binary for backend="cpp".

# NumPy on CPU (default)
result = kspaceFirstOrder(kgrid, medium, source, sensor)

# CuPy on GPU (requires CuPy + CUDA)
result = kspaceFirstOrder(kgrid, medium, source, sensor, device="gpu")

# C++ binary on CPU (requires FFTW)
result = kspaceFirstOrder(kgrid, medium, source, sensor, backend="cpp")

# C++ CUDA binary on GPU
result = kspaceFirstOrder(kgrid, medium, source, sensor, backend="cpp", device="gpu")

PML Options

The perfectly-matched layer (PML) absorbs outgoing waves at the domain boundary. Three controls:

# Fixed size (default: 20 grid points on all sides)
result = kspaceFirstOrder(kgrid, medium, source, sensor, pml_size=20)

# Per-dimension sizes
result = kspaceFirstOrder(kgrid, medium, source, sensor, pml_size=(10, 15))

# Auto-optimal size (computed from grid via FFT analysis)
result = kspaceFirstOrder(kgrid, medium, source, sensor, pml_size="auto")

# PML inside the user domain (saves memory, but PML overlaps your grid)
result = kspaceFirstOrder(kgrid, medium, source, sensor, pml_inside=True)

By default (pml_inside=False), the grid is automatically expanded so the PML sits outside your domain. Full-grid output fields (_final, _max, etc.) are cropped back to the original size.

Save-Only Mode (Cluster Submission)

Generate HDF5 input files for the C++ binary without running it:

result = kspaceFirstOrder(
    kgrid, medium, source, sensor,
    backend="cpp",
    save_only=True,
    data_path="/path/to/output",
)
print(result["input_file"])   # path to HDF5 input
print(result["output_file"])  # path where C++ will write results

Full Parameter Reference

kspaceFirstOrder(kgrid, medium, source, sensor=None, *, pml_size=20, pml_alpha=2.0, pml_inside=False, use_sg=True, use_kspace=True, smooth_p0=True, backend='python', device='cpu', save_only=False, data_path=None, quiet=False, debug=False, num_threads=None, device_num=None)[source]

Run a k-Wave simulation.

Unified entry point replacing the legacy kspaceFirstOrder2D / 3D functions. Works with 1-D, 2-D, and 3-D grids.

Parameters:
  • kgrid (kWaveGrid) – Simulation grid (defines dimensionality, spacing, and time steps).

  • medium (kWaveMedium) – Acoustic medium properties (sound speed, density, absorption, nonlinearity).

  • source (kSource) – Pressure and/or velocity source terms.

  • sensor (kSensor | NotATransducer | None) – Sensor mask defining where the field is recorded. None records the entire grid.

  • pml_size (int | tuple | str)

  • pml_alpha (float | tuple)

  • pml_inside (bool)

  • use_sg (bool)

  • use_kspace (bool)

  • smooth_p0 (bool)

  • backend (str)

  • device (str)

  • save_only (bool)

  • data_path (str | None)

  • quiet (bool)

  • debug (bool)

  • num_threads (int | None)

  • device_num (int | None)

Keyword Arguments:
  • pml_size – Perfectly-matched-layer thickness in grid points. A scalar applies to all dimensions; a tuple sets each dimension independently. "auto" selects an optimal size via FFT-based analysis. Default 20.

  • pml_alpha – PML absorption coefficient (Nepers per grid point). Scalar or per-dimension tuple. Default 2.0.

  • pml_inside – When False (default), the grid is automatically expanded by 2 * pml_size so the PML sits outside the user domain; full-grid output fields (_final, _max, etc.) are cropped back to the original size. When True, the PML occupies the outermost grid points of the user-supplied grid, which saves memory but means PML absorption will modify field values near the domain boundary.

  • use_sg – Use a staggered grid for velocity fields. Default True.

  • use_kspace – Apply the k-space correction to the time-stepping scheme. Default True.

  • smooth_p0 – Smooth the initial pressure distribution to suppress staircasing artifacts. Default True.

  • backend – Simulation engine. "python" runs a pure-Python / NumPy / CuPy solver; "cpp" serializes to HDF5 and invokes the compiled C++ binary. Default "python".

  • device"cpu" or "gpu". For backend="python" this selects NumPy (cpu) vs CuPy (gpu). For backend="cpp" it selects the OMP vs CUDA binary. Default "cpu".

  • save_only – When True (backend="cpp" only), write the HDF5 input file and return without running the binary. Useful for cluster submission. Default False.

  • data_path – Directory for HDF5 input/output files (backend="cpp" only). If None a temporary directory is created and cleaned up automatically after the run. Set explicitly to inspect or reuse the HDF5 files. Default None.

  • quiet – Suppress progress output. Default False.

  • debug – Print detailed diagnostic output. Default False.

  • num_threads – Thread count for the C++ OMP binary. None uses all available cores. Default None.

  • device_num – GPU device index for CUDA execution. Default None.

Returns:

Recorded sensor data keyed by field name (e.g. "p", "p_final", "ux", "uy").

All time-series are (n_sensor, Nt) with sensor points in C-flattened order. Use reshape_to_grid() to recover spatial structure for full-grid masks.

Return type:

dict

Migrating from Legacy API

The kwave.compat module provides options_to_kwargs() to convert old SimulationOptions / SimulationExecutionOptions to keyword arguments:

from kwave.compat import options_to_kwargs
from kwave.options.simulation_options import SimulationOptions
from kwave.options.simulation_execution_options import SimulationExecutionOptions

sim_opts = SimulationOptions(smooth_p0=False, pml_inside=True)
exec_opts = SimulationExecutionOptions(is_gpu_simulation=False)

kwargs = options_to_kwargs(simulation_options=sim_opts, execution_options=exec_opts)
result = kspaceFirstOrder(kgrid, medium, source, sensor, **kwargs)

The legacy kspaceFirstOrder2D and kspaceFirstOrder3D functions continue to work but emit FutureWarning.