Skip to content

Commit e28dfe3

Browse files
committed
Refactor kWaveGrid properties and enhance at_focused_bowl_3D example
- Removed redundant properties for x_max, y_max, and z_max from kWaveGrid to streamline the class. - Updated the at_focused_bowl_3D example to define position vectors more clearly, improving readability and maintainability. - Introduced a new x_ref calculation for better accuracy in grid representation.
1 parent dbbde27 commit e28dfe3

3 files changed

Lines changed: 155 additions & 14 deletions

File tree

examples/at_focused_bowl_3D/at_focused_bowl_3D.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,9 @@
162162
# calculate the wavenumber
163163
knumber = 2.0 * np.pi * source_f0 / c0
164164

165-
# define axis
166-
x_max = kgrid.x_max
165+
# define the position vectors
166+
x_ref = np.arange(0.0, kgrid.x_size, kgrid.dx)
167+
x_max = (kgrid.Nx - 1) * kgrid.dx
167168
delta_x = x_max / 10000.0
168169
x_ref = np.arange(0.0, x_max + delta_x, delta_x)
169170

kwave/kgrid.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -784,15 +784,3 @@ def from_domain(cls, dimensions, frequency, sound_speed_min, sound_speed_max=Non
784784
grid = cls(N=N, spacing=grid_spacing)
785785

786786
return grid
787-
788-
@property
789-
def x_max(self):
790-
return self.x_vec[-1] - self.x_vec[0]
791-
792-
@property
793-
def y_max(self):
794-
return self.y_vec[-1] - self.y_vec[0]
795-
796-
@property
797-
def z_max(self):
798-
return self.z_vec[-1] - self.z_vec[0]

tests/test_kgrid.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import numpy as np
2+
import pytest
3+
4+
from kwave.kgrid import kWaveGrid
5+
6+
7+
def test_from_geometry():
8+
# Test 1D grid
9+
dimensions = [0.1] # 10cm domain
10+
min_element_width = 0.001 # 1mm minimum element
11+
grid = kWaveGrid.from_geometry(dimensions, min_element_width)
12+
assert grid.dim == 1
13+
assert grid.dx == 0.0001 # 0.1mm spacing (min_element_width/10)
14+
assert grid.Nx == 1000 # 10cm/0.1mm
15+
16+
# Test 2D grid
17+
dimensions = [0.1, 0.2] # 10cm x 20cm domain
18+
min_element_width = 0.001 # 1mm minimum element
19+
grid = kWaveGrid.from_geometry(dimensions, min_element_width)
20+
assert grid.dim == 2
21+
assert grid.dx == 0.0001 # 0.1mm spacing
22+
assert grid.dy == 0.0001 # 0.1mm spacing
23+
assert grid.Nx == 1000 # 10cm/0.1mm
24+
assert grid.Ny == 2000 # 20cm/0.1mm
25+
26+
# Test 3D grid
27+
dimensions = [0.1, 0.2, 0.3] # 10cm x 20cm x 30cm domain
28+
min_element_width = 0.001 # 1mm minimum element
29+
grid = kWaveGrid.from_geometry(dimensions, min_element_width)
30+
assert grid.dim == 3
31+
assert grid.dx == 0.0001 # 0.1mm spacing
32+
assert grid.dy == 0.0001 # 0.1mm spacing
33+
assert grid.dz == 0.0001 # 0.1mm spacing
34+
assert grid.Nx == 1000 # 10cm/0.1mm
35+
assert grid.Ny == 2000 # 20cm/0.1mm
36+
assert grid.Nz == 3000 # 30cm/0.1mm
37+
38+
# Test custom points_per_wavelength
39+
dimensions = [0.1] # 10cm domain
40+
min_element_width = 0.001 # 1mm minimum element
41+
points_per_wavelength = 20 # Double the default
42+
grid = kWaveGrid.from_geometry(dimensions, min_element_width, points_per_wavelength=points_per_wavelength)
43+
assert grid.dx == 0.00005 # 0.05mm spacing
44+
assert grid.Nx == 2000 # 10cm/0.05mm
45+
46+
# Test error cases
47+
with pytest.raises(ValueError):
48+
kWaveGrid.from_geometry([-0.1], 0.01) # Negative dimension
49+
with pytest.raises(ValueError):
50+
kWaveGrid.from_geometry([0.1], -0.01) # Negative element width
51+
52+
53+
def test_from_domain():
54+
# Test 1D grid based on at_circular_piston_3D example
55+
dimensions = [0.032] # 32mm domain
56+
frequency = 1e6 # 1MHz
57+
sound_speed = 1500 # 1500 m/s
58+
ppw = 3 # points per wavelength
59+
grid = kWaveGrid.from_domain(dimensions, frequency, sound_speed, points_per_wavelength=ppw)
60+
61+
wavelength = sound_speed / frequency # 1.5mm
62+
expected_spacing = wavelength / ppw # 0.5mm
63+
expected_points = int(np.ceil(dimensions[0] / expected_spacing))
64+
65+
assert grid.dim == 1
66+
assert np.isclose(grid.dx, expected_spacing)
67+
assert grid.Nx == expected_points
68+
69+
# Test 2D grid with different sound speeds
70+
dimensions = [0.032, 0.023] # 32mm x 23mm domain (from example)
71+
frequency = 1e6 # 1MHz
72+
sound_speed_min = 1500 # 1500 m/s
73+
sound_speed_max = 2000 # 2000 m/s
74+
grid = kWaveGrid.from_domain(dimensions, frequency, sound_speed_min, sound_speed_max, points_per_wavelength=ppw)
75+
76+
wavelength = sound_speed_min / frequency # 1.5mm
77+
expected_spacing = wavelength / ppw # 0.5mm
78+
expected_points_x = int(np.ceil(dimensions[0] / expected_spacing))
79+
expected_points_y = int(np.ceil(dimensions[1] / expected_spacing))
80+
81+
assert grid.dim == 2
82+
assert np.isclose(grid.dx, expected_spacing)
83+
assert np.isclose(grid.dy, expected_spacing)
84+
assert grid.Nx == expected_points_x
85+
assert grid.Ny == expected_points_y
86+
87+
# Test error cases
88+
with pytest.raises(ValueError):
89+
kWaveGrid.from_domain([-0.1], 1e6, 1500) # Negative dimension
90+
with pytest.raises(ValueError):
91+
kWaveGrid.from_domain([0.1], -1e6, 1500) # Negative frequency
92+
with pytest.raises(ValueError):
93+
kWaveGrid.from_domain([0.1], 1e6, -1500) # Negative sound speed
94+
95+
96+
def test_total_grid_points():
97+
# Test 1D grid
98+
grid = kWaveGrid([10], [0.1])
99+
assert grid.total_grid_points == 10
100+
101+
# Test 2D grid
102+
grid = kWaveGrid([10, 20], [0.1, 0.1])
103+
assert grid.total_grid_points == 200
104+
105+
# Test 3D grid
106+
grid = kWaveGrid([10, 20, 30], [0.1, 0.1, 0.1])
107+
assert grid.total_grid_points == 6000
108+
109+
110+
def test_kx_ky_kz_properties():
111+
# Test 1D grid
112+
grid = kWaveGrid([10], [0.1])
113+
assert np.array_equal(grid.kx, grid.k_vec.x)
114+
assert np.isnan(grid.ky)
115+
assert np.isnan(grid.kz)
116+
117+
# Test 2D grid
118+
grid = kWaveGrid([10, 20], [0.1, 0.1])
119+
expected_kx = np.tile(grid.k_vec.x, (1, 20))
120+
expected_ky = np.tile(grid.k_vec.y.T, (10, 1))
121+
assert np.array_equal(grid.kx, expected_kx)
122+
assert np.array_equal(grid.ky, expected_ky)
123+
assert np.isnan(grid.kz)
124+
125+
# Test 3D grid
126+
grid = kWaveGrid([10, 20, 30], [0.1, 0.1, 0.1])
127+
expected_kx = np.tile(grid.k_vec.x[:, :, None], (1, 20, 30))
128+
expected_ky = np.tile(grid.k_vec.y[None, :, :], (10, 1, 30))
129+
expected_kz = np.tile(grid.k_vec.z.T[None, :, :], (10, 20, 1))
130+
assert np.array_equal(grid.kx, expected_kx)
131+
assert np.array_equal(grid.ky, expected_ky)
132+
assert np.array_equal(grid.kz, expected_kz)
133+
134+
135+
def test_size_properties():
136+
# Test 1D grid
137+
grid = kWaveGrid([10], [0.1])
138+
assert grid.x_size == 1.0 # 10 * 0.1
139+
assert grid.y_size == 0.0 # Not applicable in 1D
140+
assert grid.z_size == 0.0 # Not applicable in 1D
141+
142+
# Test 2D grid
143+
grid = kWaveGrid([10, 20], [0.1, 0.1])
144+
assert grid.x_size == 1.0 # 10 * 0.1
145+
assert grid.y_size == 2.0 # 20 * 0.1
146+
assert grid.z_size == 0.0 # Not applicable in 2D
147+
148+
# Test 3D grid
149+
grid = kWaveGrid([10, 20, 30], [0.1, 0.1, 0.1])
150+
assert grid.x_size == 1.0 # 10 * 0.1
151+
assert grid.y_size == 2.0 # 20 * 0.1
152+
assert grid.z_size == 3.0 # 30 * 0.1

0 commit comments

Comments
 (0)