Skip to content

Commit 5a04eb9

Browse files
authored
Merge branch 'master' into dependabot/pip/sphinx-toolbox-3.9.0
2 parents 8a6c252 + fe030f3 commit 5a04eb9

177 files changed

Lines changed: 4077 additions & 2522 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/codespell.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Spell Check
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
spellcheck:
11+
name: Spell Check
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v3
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v4
18+
with:
19+
python-version: '3.10'
20+
21+
- name: Install codespell
22+
run: pip install codespell
23+
24+
- name: Run codespell
25+
run: codespell --config .codespellrc

.github/workflows/run-examples.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Run K-Wave Examples
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 * * 1' # Every Monday at 00:00 UTC
6+
workflow_dispatch: # Manual trigger
7+
8+
jobs:
9+
discover-examples:
10+
runs-on: ubuntu-latest
11+
outputs:
12+
example_paths: ${{ steps.find-examples.outputs.examples }}
13+
steps:
14+
- uses: actions/checkout@v4
15+
- id: find-examples
16+
run: |
17+
# Find all Python files in examples subdirectories
18+
EXAMPLES=$(find examples -name "*.py" -not -path "*/\.*" | jq -R -s -c 'split("\n")[:-1]')
19+
echo "examples=$EXAMPLES" >> "$GITHUB_OUTPUT"
20+
21+
run-examples:
22+
needs: discover-examples
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 60 # 1 hour timeout per example
25+
strategy:
26+
fail-fast: false # Continue running other examples even if one fails
27+
matrix:
28+
example: ${{ fromJson(needs.discover-examples.outputs.example_paths) }}
29+
30+
steps:
31+
- name: Checkout repository
32+
uses: actions/checkout@v4
33+
34+
- name: Install system dependencies
35+
run: |
36+
sudo apt-get update
37+
sudo apt-get install -y ffmpeg
38+
39+
- name: Set up Python
40+
uses: actions/setup-python@v5
41+
with:
42+
python-version: '3.10' # Matches requires-python from pyproject.toml
43+
cache: 'pip'
44+
45+
- name: Install dependencies
46+
run: |
47+
python -m pip install --upgrade pip
48+
# Install the package with example dependencies
49+
pip install -e ".[example]"
50+
51+
- name: Run example
52+
env:
53+
KWAVE_FORCE_CPU: 1
54+
run: |
55+
echo "Running example: ${{ matrix.example }}"
56+
python "${{ matrix.example }}"

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ repos:
1717
args: [ --fix ]
1818
# Run the formatter.
1919
- id: ruff-format
20+
- repo: https://github.com/codespell-project/codespell
21+
rev: v2.2.6
22+
hooks:
23+
- id: codespell
24+
additional_dependencies:
25+
- tomli
26+
args: [--write-changes]
2027
# - repo: https://github.com/pre-commit/pre-commit-hooks
2128
# rev: v4.5.0 # Use the ref you want to point at
2229
# hooks:

docs/development/development_environment.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ Ensure pre-commit is configured by running the following command:
2424
Running Tests
2525
=======================
2626
Assuming matlab is installed locally, and `k-wave <https://github.com/ucl-bug/k-wave>` is installed in a parallel directory, testing can be performed using the make file located in the project root.
27+
2728
.. code-block:: bash
2829
2930
make test
3031
31-
This process will first generate refernce files in matlab and run the complete python test suite against them.
32+
This process will first generate reference files in matlab and run the complete python test suite against them.
3233

3334
To run the tests manually after reference generation, use the following command:
3435

@@ -43,7 +44,9 @@ To run the tests with coverage, use the following command:
4344
coverage run
4445
4546
To run all examples, to ensure they still run after changes use the following command:
47+
4648
.. code-block:: bash
49+
4750
make run-examples
4851
4952
or
@@ -87,7 +90,7 @@ These tests are located in the ``tests`` directory. The comparison between ``mat
8790
#. Open desired example in matlab, e.g. `example_pr_2D_TR_directional_sensors.m <https://github.com/ucl-bug/k-wave/blob/main/k-Wave/examples/example_pr_2D_TR_directional_sensors.m>`_
8891
#. Find the lines where the call to one of the `kSpaceFirstOrder-family` function is made. For example,
8992

90-
.. code-block:: python
93+
.. code-block:: matlab
9194
9295
input_args = {'PMLInside', false, 'PMLSize', PML_size, 'PlotPML', false, 'Smooth', false};
9396
sensor_data = kspaceFirstOrder2D(kgrid, medium, source, sensor, input_args{:});

docs/reconstruction/index.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Reconstruction
2+
=============
3+
4+
This module provides functionality for reconstructing acoustic fields from recorded sensor data.
5+
6+
.. toctree::
7+
:maxdepth: 2
8+
9+
time_reversal
10+
beamform
11+
converter
12+
shifted_transform
13+
tools
14+
15+
Migration Notes
16+
-------------
17+
18+
The time reversal reconstruction functionality has been moved to the :class:`TimeReversal` class.
19+
See :doc:`time_reversal` for migration guidelines and examples.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
Time Reversal Reconstruction
2+
========================
3+
4+
The :class:`TimeReversal` class provides functionality for time reversal reconstruction in photoacoustic imaging.
5+
It handles the reconstruction of initial pressure distributions from recorded sensor data.
6+
7+
.. tip::
8+
**Migration from Legacy Time Reversal**
9+
10+
Previous versions used ``sensor.time_reversal_boundary_data`` directly with ``kspaceFirstOrder2D/3D``.
11+
This approach is now deprecated. Instead, use the new :class:`TimeReversal` class:
12+
13+
.. code-block:: python
14+
15+
# Old approach (deprecated)
16+
sensor.time_reversal_boundary_data = sensor_data
17+
p0_recon = kspaceFirstOrder2D(kgrid, source, sensor, medium, simulation_options, execution_options)
18+
19+
# New approach
20+
sensor.recorded_pressure = sensor_data # Store recorded data
21+
tr = TimeReversal(kgrid, medium, sensor)
22+
p0_recon = tr(kspaceFirstOrder2D, simulation_options, execution_options)
23+
24+
Class Documentation
25+
-----------------
26+
27+
.. autoclass:: kwave.reconstruction.time_reversal.TimeReversal
28+
:members:
29+
:undoc-members:
30+
:show-inheritance:
31+
32+
Key Features
33+
-----------
34+
35+
- Automatic compensation for half-plane recording
36+
- Support for both 2D and 3D reconstructions
37+
- Input validation and error checking
38+
- Clean interface separating data recording from reconstruction
39+
40+
Example Usage
41+
------------
42+
43+
Here's a complete example showing forward simulation and time reversal reconstruction:
44+
45+
.. code-block:: python
46+
47+
import numpy as np
48+
from kwave import *
49+
50+
# Setup grid and medium
51+
kgrid = kWaveGrid([64, 64], [0.1e-3, 0.1e-3])
52+
medium = kWaveMedium(sound_speed=1500)
53+
kgrid.makeTime(medium.sound_speed)
54+
55+
# Create initial pressure
56+
source = kSource()
57+
source.p0 = np.zeros(kgrid.N)
58+
source.p0[32, 32] = 1
59+
60+
# Setup sensor
61+
sensor = kSensor()
62+
sensor.mask = np.zeros(kgrid.N)
63+
sensor.mask[0, :] = 1 # Line sensor
64+
65+
# Forward simulation
66+
sensor_data = kspaceFirstOrder2D(kgrid, source, sensor, medium,
67+
simulation_options, execution_options)
68+
sensor.recorded_pressure = sensor_data["p"].T
69+
70+
# Time reversal reconstruction
71+
tr = TimeReversal(kgrid, medium, sensor)
72+
p0_recon = tr(kspaceFirstOrder2D, simulation_options, execution_options)
73+
74+
Notes
75+
-----
76+
77+
- The compensation factor (default=2.0) accounts for energy loss when recording over a half-plane
78+
- The time array must be explicitly defined (not 'auto') for time reversal
79+
- The sensor mask must have at least one active point
80+
- The sensor mask shape must match the grid dimensions

examples/at_array_as_sensor/at_array_as_sensor.ipynb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
"metadata": {},
1717
"outputs": [],
1818
"source": [
19-
"import matplotlib.pyplot as plt\n",
2019
"import matplotlib as mpl\n",
20+
"import matplotlib.pyplot as plt\n",
2121
"import numpy as np\n",
2222
"\n",
2323
"from kwave.data import Vector\n",
@@ -28,10 +28,10 @@
2828
"from kwave.kspaceFirstOrder2D import kspaceFirstOrder2D\n",
2929
"from kwave.options.simulation_execution_options import SimulationExecutionOptions\n",
3030
"from kwave.options.simulation_options import SimulationOptions\n",
31+
"from kwave.utils.colormap import get_color_map\n",
3132
"from kwave.utils.conversion import cart2grid\n",
3233
"from kwave.utils.kwave_array import kWaveArray\n",
3334
"from kwave.utils.mapgen import make_cart_circle, make_disc\n",
34-
"from kwave.utils.colormap import get_color_map\n",
3535
"from kwave.utils.signals import reorder_binary_sensor_data"
3636
]
3737
},
@@ -119,7 +119,7 @@
119119
"combined_sensor_data = karray.combine_sensor_data(kgrid, sensor_data)\n",
120120
"\n",
121121
"\n",
122-
"# create pml mask (re-use default size of 20 grid points from simulation_options)\n",
122+
"# create pml mask (reuse default size of 20 grid points from simulation_options)\n",
123123
"pml_size = simulation_options.pml_x_size # 20 [grid_points]\n",
124124
"pml_mask = np.zeros((N.x, N.y), dtype=bool)\n",
125125
"pml_mask[:pml_size, :] = 1\n",
@@ -142,7 +142,7 @@
142142
"outputs": [],
143143
"source": [
144144
"%matplotlib inline\n",
145-
"# create pml mask (re-use default size of 20 grid points from simulation_options)\n",
145+
"# create pml mask (reuse default size of 20 grid points from simulation_options)\n",
146146
"pml_size = simulation_options.pml_x_size # 20 [grid_points]\n",
147147
"pml_mask = np.zeros((N.x, N.y), dtype=bool)\n",
148148
"pml_mask[:pml_size, :] = 1\n",

examples/at_array_as_sensor/at_array_as_sensor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import matplotlib.pyplot as plt
21
import matplotlib as mpl
2+
import matplotlib.pyplot as plt
33
import numpy as np
44

55
from kwave.data import Vector
@@ -10,9 +10,9 @@
1010
from kwave.kspaceFirstOrder2D import kspaceFirstOrder2D
1111
from kwave.options.simulation_execution_options import SimulationExecutionOptions
1212
from kwave.options.simulation_options import SimulationOptions
13+
from kwave.utils.colormap import get_color_map
1314
from kwave.utils.conversion import cart2grid
1415
from kwave.utils.kwave_array import kWaveArray
15-
from kwave.utils.colormap import get_color_map
1616
from kwave.utils.mapgen import make_cart_circle, make_disc
1717
from kwave.utils.signals import reorder_binary_sensor_data
1818

@@ -76,7 +76,7 @@ def main():
7676
# VISUALIZATION
7777
# =========================================================================
7878

79-
# create pml mask (re-use default size of 20 grid points from simulation_options)
79+
# create pml mask (reuse default size of 20 grid points from simulation_options)
8080
pml_size = simulation_options.pml_x_size # 20 [grid_points]
8181
pml_mask = np.zeros((N.x, N.y), dtype=bool)
8282
pml_mask[:pml_size, :] = 1

examples/at_array_as_source/at_array_as_source.ipynb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
"from kwave.kspaceFirstOrder2D import kspace_first_order_2d_gpu\n",
3030
"from kwave.options.simulation_execution_options import SimulationExecutionOptions\n",
3131
"from kwave.options.simulation_options import SimulationOptions\n",
32-
"from kwave.utils.kwave_array import kWaveArray\n",
3332
"from kwave.utils.colormap import get_color_map\n",
33+
"from kwave.utils.kwave_array import kWaveArray\n",
3434
"from kwave.utils.signals import tone_burst\n"
3535
]
3636
},
@@ -169,6 +169,7 @@
169169
"outputs": [],
170170
"source": [
171171
"from matplotlib import rc\n",
172+
"\n",
172173
"rc('animation', html='jshtml', embed_limit=10**3)\n",
173174
"%matplotlib notebook\n",
174175
"\n",

examples/at_array_as_source/at_array_as_source.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
from kwave.kspaceFirstOrder2D import kspace_first_order_2d_gpu
1212
from kwave.options.simulation_execution_options import SimulationExecutionOptions
1313
from kwave.options.simulation_options import SimulationOptions
14-
from kwave.utils.kwave_array import kWaveArray
1514
from kwave.utils.colormap import get_color_map
15+
from kwave.utils.kwave_array import kWaveArray
1616
from kwave.utils.signals import tone_burst
1717

1818

0 commit comments

Comments
 (0)