Skip to content

Commit b1dcee0

Browse files
authored
Merge branch 'master' into release/v0.4.0
2 parents 3e11cea + 4874253 commit b1dcee0

19 files changed

+2376
-40
lines changed

examples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ Every example has a short readme.md file which briefly describes the purpose of
2727
- [Focused bowl transducer (axisymmetric)](at_focused_bowl_AS/) ([original example](http://www.k-wave.org/documentation/example_at_piston_and_bowl_transducers.php#heading6), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_focused_bowl_AS/at_focused_bowl_AS.ipynb))
2828

2929
- [Focused annular array](at_focused_annular_array_3D/) ([original example](http://www.k-wave.org/documentation/example_at_piston_and_bowl_transducers.php#heading7), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/at_focused_annular_array_3D/at_focused_annular_array_3D.ipynb))
30+
- [2D FFT Reconstruction For A Line Sensor](pr_2D_FFT_line_sensor/) ([original example](http://www.k-wave.org/documentation/example_pr_2D_fft_line_sensor.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/pr_2D_FFT_line_sensor/pr_2D_FFT_line_sensor.ipynb))
31+
- [3D FFT Reconstruction For A Planar Sensor](pr_3D_FFT_planar_sensor/) ([original example](http://www.k-wave.org/documentation/example_pr_3D_fft_planar_sensor.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/pr_3D_FFT_planar_sensor/pr_3D_FFT_planar_sensor.ipynb))
32+
- [2D Time Reversal Reconstruction For A Line Sensor](pr_2D_TR_line_sensor/) ([original example](http://www.k-wave.org/documentation/example_pr_2D_tr_line_sensor.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/pr_2D_TR_line_sensor/pr_2D_TR_line_sensor.ipynb))
33+
- [3D Time Reversal Reconstruction For A Planar Sensor](pr_3D_TR_planar_sensor/) ([original example](http://www.k-wave.org/documentation/example_pr_3D_tr_planar_sensor.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/pr_3D_TR_planar_sensor/pr_3D_TR_planar_sensor.ipynb))
34+
3035

3136
- [Focussed Detector In 2D Example](sd_focussed_detector_2D/) ([original example](http://www.k-wave.org/documentation/example_sd_focussed_detector_2D.php), [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/sd_focussed_detector_2D/sd_focussed_detector_2D.ipynb))
3237

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# 2D FFT Reconstruction For A Line Sensor Example
2+
3+
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/pr_2D_FFT_line_sensor/pr_2D_FFT_line_sensor.ipynb)
4+
5+
This example demonstrates the use of k-Wave for the reconstruction of a two-dimensional photoacoustic wave-field recorded over a linear array of sensor elements. The sensor data is simulated using [kspaceFirstOrder2D](https://k-wave-python.readthedocs.io/en/latest/kwave.kspaceFirstOrder2D.html) and reconstructed using kspaceLineRecon. It builds on the Homogeneous Propagation Medium and Heterogeneous Propagation Medium examples.
6+
7+
To read more, visit the [original example page](http://www.k-wave.org/documentation/example_pr_2D_fft_line_sensor.php) or its [implementation](https://github.com/ucl-bug/k-wave/blob/main/k-Wave/examples/example_pr_2D_FFT_line_sensor.m).
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"id": "initial_id",
6+
"metadata": {
7+
"collapsed": true
8+
},
9+
"source": [
10+
"%%capture\n",
11+
"!pip install k-wave-python "
12+
],
13+
"outputs": [],
14+
"execution_count": null
15+
},
16+
{
17+
"metadata": {},
18+
"cell_type": "code",
19+
"source": [
20+
"import matplotlib.pyplot as plt\n",
21+
"from mpl_toolkits.axes_grid1 import make_axes_locatable\n",
22+
"import numpy as np\n",
23+
"from scipy.interpolate import RegularGridInterpolator\n",
24+
"\n",
25+
"from kwave.data import Vector\n",
26+
"from kwave.kgrid import kWaveGrid\n",
27+
"from kwave.kmedium import kWaveMedium\n",
28+
"from kwave.ksensor import kSensor\n",
29+
"from kwave.ksource import kSource\n",
30+
"from kwave.kspaceFirstOrder2D import kspaceFirstOrder2D\n",
31+
"from kwave.kspaceLineRecon import kspaceLineRecon\n",
32+
"from kwave.options.simulation_execution_options import SimulationExecutionOptions\n",
33+
"from kwave.options.simulation_options import SimulationOptions\n",
34+
"from kwave.utils.colormap import get_color_map\n",
35+
"from kwave.utils.mapgen import make_disc\n",
36+
"from kwave.utils.filters import smooth"
37+
],
38+
"id": "48677f5b96e1511e",
39+
"outputs": [],
40+
"execution_count": null
41+
},
42+
{
43+
"metadata": {},
44+
"cell_type": "markdown",
45+
"source": [
46+
"## 2D FFT Reconstruction For A Line Sensor Example\n",
47+
"\n",
48+
"This example demonstrates the use of k-Wave for the reconstruction of a\n",
49+
"two-dimensional photoacoustic wave-field recorded over a linear array of\n",
50+
"sensor elements The sensor data is simulated using kspaceFirstOrder2D\n",
51+
"and reconstructed using kspaceLineRecon. It builds on the Homogeneous\n",
52+
"Propagation Medium and Heterogeneous Propagation Medium examples. "
53+
],
54+
"id": "262efa49a13b9574"
55+
},
56+
{
57+
"metadata": {},
58+
"cell_type": "markdown",
59+
"source": "### SIMULATION",
60+
"id": "310bcfe8541609c2"
61+
},
62+
{
63+
"metadata": {},
64+
"cell_type": "code",
65+
"source": [
66+
"# create the computational grid\n",
67+
"PML_size = 20 # size of the PML in grid points\n",
68+
"N = Vector([128, 256]) - 2 * PML_size # number of grid points\n",
69+
"d = Vector([0.1e-3, 0.1e-3]) # grid point spacing [m]\n",
70+
"kgrid = kWaveGrid(N, d)"
71+
],
72+
"id": "6d7c5328ae5dd3ee",
73+
"outputs": [],
74+
"execution_count": null
75+
},
76+
{
77+
"metadata": {},
78+
"cell_type": "code",
79+
"source": [
80+
"# define the properties of the propagation medium\n",
81+
"medium = kWaveMedium(sound_speed=1500) # [m/s]"
82+
],
83+
"id": "bd5eece140453f0f",
84+
"outputs": [],
85+
"execution_count": null
86+
},
87+
{
88+
"metadata": {},
89+
"cell_type": "code",
90+
"source": [
91+
"# create initial pressure distribution using makeDisc\n",
92+
"disc_magnitude = 5 # [Pa]\n",
93+
"disc_pos = Vector([60, 140])\n",
94+
"disc_radius = 5\n",
95+
"disc_2 = disc_magnitude * make_disc(N, disc_pos, disc_radius)\n",
96+
"\n",
97+
"disc_pos = Vector([30, 110])\n",
98+
"disc_radius = 8\n",
99+
"disc_1 = disc_magnitude * make_disc(N, disc_pos, disc_radius)\n",
100+
"\n",
101+
"# smooth the initial pressure distribution and restore the magnitude\n",
102+
"p0 = disc_1 + disc_2\n",
103+
"p0 = smooth(p0, restore_max=True)\n",
104+
"\n",
105+
"source = kSource()\n",
106+
"source.p0 = p0"
107+
],
108+
"id": "2ce3b8059a9ec319",
109+
"outputs": [],
110+
"execution_count": null
111+
},
112+
{
113+
"metadata": {},
114+
"cell_type": "code",
115+
"source": [
116+
"# define a binary line sensor\n",
117+
"sensor = kSensor()\n",
118+
"sensor.mask = np.zeros(N)\n",
119+
"sensor.mask[0] = 1"
120+
],
121+
"id": "cf6961e373c6f8e8",
122+
"outputs": [],
123+
"execution_count": null
124+
},
125+
{
126+
"metadata": {},
127+
"cell_type": "code",
128+
"source": [
129+
"%%capture\n",
130+
"\n",
131+
"# create the time array\n",
132+
"kgrid.makeTime(medium.sound_speed)"
133+
],
134+
"id": "5a278b1e9b253295",
135+
"outputs": [],
136+
"execution_count": null
137+
},
138+
{
139+
"metadata": {},
140+
"cell_type": "code",
141+
"source": [
142+
"# set the input arguments: force the PML to be outside the computational grid\n",
143+
"simulation_options = SimulationOptions(\n",
144+
" save_to_disk=True,\n",
145+
" pml_inside=False,\n",
146+
" pml_size=PML_size,\n",
147+
" smooth_p0=False,\n",
148+
")\n",
149+
"execution_options = SimulationExecutionOptions(is_gpu_simulation=True)"
150+
],
151+
"id": "a3802e3e482dc77",
152+
"outputs": [],
153+
"execution_count": null
154+
},
155+
{
156+
"metadata": {},
157+
"cell_type": "code",
158+
"source": [
159+
"# run the simulation\n",
160+
"sensor_data = kspaceFirstOrder2D(kgrid, source, sensor, medium, simulation_options, execution_options)\n",
161+
"sensor_data = sensor_data['p'].T\n",
162+
"\n",
163+
"# reconstruct the initial pressure\n",
164+
"p_xy = kspaceLineRecon(sensor_data.T, dy=d[1], dt=kgrid.dt.item(), c=medium.sound_speed.item(),\n",
165+
" pos_cond=True, interp='linear')\n",
166+
"\n",
167+
"# define a second k-space grid using the dimensions of p_xy\n",
168+
"N_recon = Vector(p_xy.shape)\n",
169+
"d_recon = Vector([kgrid.dt.item() * medium.sound_speed.item(), kgrid.dy])\n",
170+
"kgrid_recon = kWaveGrid(N_recon, d_recon)\n",
171+
"\n",
172+
"# resample p_xy to be the same size as source.p0\n",
173+
"interp_func = RegularGridInterpolator(\n",
174+
" (kgrid_recon.x_vec[:, 0] - kgrid_recon.x_vec.min(), kgrid_recon.y_vec[:, 0]),\n",
175+
" p_xy, method='linear'\n",
176+
")\n",
177+
"query_points = np.stack((kgrid.x - kgrid.x.min(), kgrid.y), axis=-1)\n",
178+
"p_xy_rs = interp_func(query_points)"
179+
],
180+
"id": "154c372469cd6063",
181+
"outputs": [],
182+
"execution_count": null
183+
},
184+
{
185+
"metadata": {},
186+
"cell_type": "markdown",
187+
"source": "### VISUALIZATION\n",
188+
"id": "b07f65d05feaf902"
189+
},
190+
{
191+
"metadata": {},
192+
"cell_type": "code",
193+
"source": "cmap = get_color_map()",
194+
"id": "30edd081e39aa21b",
195+
"outputs": [],
196+
"execution_count": null
197+
},
198+
{
199+
"metadata": {},
200+
"cell_type": "code",
201+
"source": [
202+
"# plot the initial pressure and sensor distribution\n",
203+
"fig, ax = plt.subplots(1, 1)\n",
204+
"im = ax.imshow(p0 + sensor.mask[PML_size:-PML_size, PML_size:-PML_size] * disc_magnitude,\n",
205+
" extent=[kgrid.y_vec.min() * 1e3, kgrid.y_vec.max() * 1e3, kgrid.x_vec.max() * 1e3, kgrid.x_vec.min() * 1e3],\n",
206+
" vmin=-disc_magnitude, vmax=disc_magnitude, cmap=cmap)\n",
207+
"divider = make_axes_locatable(ax)\n",
208+
"cax = divider.append_axes(\"right\", size=\"3%\", pad=\"2%\")\n",
209+
"ax.set_ylabel('x-position [mm]')\n",
210+
"ax.set_xlabel('y-position [mm]')\n",
211+
"fig.colorbar(im, cax=cax)\n",
212+
"plt.show()"
213+
],
214+
"id": "d02e73401dee274c",
215+
"outputs": [],
216+
"execution_count": null
217+
},
218+
{
219+
"metadata": {},
220+
"cell_type": "code",
221+
"source": [
222+
"fig, ax = plt.subplots(1, 1)\n",
223+
"im = ax.imshow(sensor_data, vmin=-1, vmax=1, cmap=cmap, aspect='auto')\n",
224+
"divider = make_axes_locatable(ax)\n",
225+
"cax = divider.append_axes(\"right\", size=\"3%\", pad=\"2%\")\n",
226+
"ax.set_ylabel('Sensor Position')\n",
227+
"ax.set_xlabel('Time Step')\n",
228+
"fig.colorbar(im, cax=cax)\n",
229+
"plt.show()"
230+
],
231+
"id": "fc203d6e2a22dec6",
232+
"outputs": [],
233+
"execution_count": null
234+
},
235+
{
236+
"metadata": {},
237+
"cell_type": "code",
238+
"source": [
239+
"# plot the reconstructed initial pressure\n",
240+
"fig, ax = plt.subplots(1, 1)\n",
241+
"im = ax.imshow(p_xy_rs,\n",
242+
" extent=[kgrid.y_vec.min() * 1e3, kgrid.y_vec.max() * 1e3, kgrid.x_vec.max() * 1e3, kgrid.x_vec.min() * 1e3],\n",
243+
" vmin=-disc_magnitude, vmax=disc_magnitude, cmap=cmap)\n",
244+
"divider = make_axes_locatable(ax)\n",
245+
"cax = divider.append_axes(\"right\", size=\"3%\", pad=\"2%\")\n",
246+
"ax.set_ylabel('x-position [mm]')\n",
247+
"ax.set_xlabel('y-position [mm]')\n",
248+
"fig.colorbar(im, cax=cax)\n",
249+
"plt.show()"
250+
],
251+
"id": "2da3a2a311fd1683",
252+
"outputs": [],
253+
"execution_count": null
254+
},
255+
{
256+
"metadata": {},
257+
"cell_type": "code",
258+
"source": [
259+
"# plot a profile for comparison\n",
260+
"plt.plot(kgrid.y_vec[:, 0] * 1e3, p0[disc_pos[0], :], 'k-', label='Initial Pressure')\n",
261+
"plt.plot(kgrid.y_vec[:, 0] * 1e3, p_xy_rs[disc_pos[0], :], 'r--', label='Reconstructed Pressure')\n",
262+
"plt.xlabel('y-position [mm]')\n",
263+
"plt.ylabel('Pressure')\n",
264+
"plt.legend()\n",
265+
"plt.axis('tight')\n",
266+
"plt.ylim([0, 5.1])\n",
267+
"plt.show()"
268+
],
269+
"id": "f7ae5b0a2f5e147e",
270+
"outputs": [],
271+
"execution_count": null
272+
}
273+
],
274+
"metadata": {
275+
"kernelspec": {
276+
"display_name": "Python 3",
277+
"language": "python",
278+
"name": "python3"
279+
},
280+
"language_info": {
281+
"codemirror_mode": {
282+
"name": "ipython",
283+
"version": 2
284+
},
285+
"file_extension": ".py",
286+
"mimetype": "text/x-python",
287+
"name": "python",
288+
"nbconvert_exporter": "python",
289+
"pygments_lexer": "ipython2",
290+
"version": "2.7.6"
291+
}
292+
},
293+
"nbformat": 4,
294+
"nbformat_minor": 5
295+
}

0 commit comments

Comments
 (0)