Skip to content

Commit 4522ca0

Browse files
author
Brandon Kirkland
committed
Fix critical row bug, lint violations, and style consistency
SimulationCorrected: fix undefined 'row' variable in arrival time extraction loop (would crash at runtime). Add voxel_to_row lookup before accessing sensor_data. Remove redundant to_dict override (base class handles it). Replace importlib.find_spec for k-wave availability check. Fix .values -> .to_numpy() for xarray compat. Style: convert all docstrings to Sphinx :param:/:returns: format matching the existing codebase. Add noqa comments for deliberate lazy imports. Fix import sort order in threshold_mri.py skull refinement block. kwave_if: remove unused kWaveGrid and kWaveMedium imports from run_point_source_simulation.
1 parent 4974521 commit 4522ca0

3 files changed

Lines changed: 29 additions & 42 deletions

File tree

src/openlifu/bf/delay_methods/simulation_corrected.py

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ def calc_delays(self, arr: Transducer, target: Point, params: xa.Dataset, transf
7777
if the simulation fails for any reason.
7878
7979
Args:
80-
arr: The transducer array.
81-
target: The focal target point.
82-
params: Simulation grid dataset with sound_speed, density, attenuation fields.
83-
transform: Optional 4x4 affine transform for element positions.
84-
85-
Returns:
86-
delays: 1D numpy array of per-element delays in seconds.
80+
:param arr: The transducer array.
81+
:param target: The focal target point.
82+
:param params: Simulation grid dataset with sound_speed, density, attenuation fields.
83+
:param transform: Optional 4x4 affine transform for element positions.
84+
:returns: 1D numpy array of per-element delays in seconds.
8785
"""
8886
try:
89-
from openlifu.sim.kwave_if import run_point_source_simulation
87+
import importlib # noqa: PLC0415
88+
if importlib.util.find_spec("kwave") is None:
89+
raise ImportError("k-wave not installed")
9090
except ImportError:
9191
logger.warning("k-wave not available. Falling back to Direct delay method.")
9292
return self._fallback_delays(arr, target, params, transform)
@@ -117,9 +117,9 @@ def _run_reciprocal_simulation(
117117
Returns:
118118
arrival_times: 1D array of arrival times (seconds) per element.
119119
"""
120-
from scipy.signal import hilbert
120+
from scipy.signal import hilbert # noqa: PLC0415
121121

122-
from openlifu.sim.kwave_if import run_point_source_simulation
122+
from openlifu.sim.kwave_if import run_point_source_simulation # noqa: PLC0415
123123

124124
# Get the reference sound speed from params if available
125125
if 'sound_speed' in params and 'ref_value' in params['sound_speed'].attrs:
@@ -151,7 +151,7 @@ def _run_reciprocal_simulation(
151151
target_pos_grid = target.get_position(units=coord_units)
152152

153153
# Build the sensor mask: find nearest grid indices for each element
154-
coord_arrays = [params.coords[dim].values for dim in coord_dims]
154+
coord_arrays = [params.coords[dim].to_numpy() for dim in coord_dims]
155155
grid_shape = tuple(len(c) for c in coord_arrays)
156156

157157
sensor_indices = []
@@ -241,6 +241,7 @@ def fortran_linear_index(idx, shape):
241241
arrival_times[el_i] = dist / self.c0
242242
continue
243243

244+
row = voxel_to_row[sensor_idx]
244245
time_series = sensor_data[row, :]
245246
# Compute the analytic signal envelope via the Hilbert transform
246247
analytic = hilbert(time_series)
@@ -253,25 +254,15 @@ def fortran_linear_index(idx, shape):
253254

254255
def _fallback_delays(self, arr: Transducer, target: Point, params: xa.Dataset, transform: np.ndarray | None = None) -> np.ndarray:
255256
"""Compute delays using the Direct (geometric) method as a fallback."""
256-
from openlifu.bf.delay_methods.direct import Direct
257+
from openlifu.bf.delay_methods.direct import Direct # noqa: PLC0415
257258
direct = Direct(c0=self.c0)
258259
return direct.calc_delays(arr, target, params, transform)
259260

260-
def to_dict(self):
261-
d = {
262-
'class': self.__class__.__name__,
263-
'c0': self.c0,
264-
'cfl': self.cfl,
265-
'n_cycles': self.n_cycles,
266-
'gpu': self.gpu,
267-
}
268-
return d
269-
270261
def to_table(self) -> pd.DataFrame:
271-
"""Get a table of the delay method parameters.
262+
"""
263+
Get a table of the delay method parameters
272264
273-
Returns:
274-
Pandas DataFrame of the delay method parameters.
265+
:returns: Pandas DataFrame of the delay method parameters
275266
"""
276267
records = [
277268
{"Name": "Type", "Value": "SimulationCorrected", "Unit": ""},

src/openlifu/seg/seg_methods/threshold_mri.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,9 @@ def _segment(self, volume: xa.DataArray) -> xa.DataArray:
402402
shell_mask = foreground & ~brain_mask
403403
shell_intensities = data[shell_mask]
404404
if shell_intensities.size > 100:
405+
from scipy.ndimage import binary_closing # noqa: PLC0415
406+
from scipy.ndimage import label as ndlabel # noqa: PLC0415
405407
from skimage.filters import threshold_otsu # noqa: PLC0415
406-
from scipy.ndimage import binary_closing, label as ndlabel # noqa: PLC0415
407408

408409
# Only refine if the shell has meaningful intensity variation.
409410
# On uniform/synthetic data (CV < 0.1), Otsu cannot distinguish

src/openlifu/sim/kwave_if.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,18 @@ def run_point_source_simulation(
9494
approach: a single point source is placed at the target and pressure time
9595
series are recorded at transducer element positions.
9696
97-
Args:
98-
params: Simulation grid dataset with sound_speed, density, attenuation.
99-
source_mask: 3D binary array with 1 at the source (target) voxel.
100-
sensor_mask: 3D binary array with 1s at sensor (element) voxels.
101-
freq: Source frequency in Hz.
102-
n_cycles: Number of cycles in the source pulse.
103-
sound_speed_ref: Reference speed of sound (m/s) for time stepping.
104-
cfl: Courant-Friedrichs-Lewy number for time stepping.
105-
gpu: Whether to use GPU acceleration.
106-
ref_values_only: If True, use reference (homogeneous) medium values.
107-
108-
Returns:
109-
sensor_data: 2D array (n_sensor_points, n_timesteps) of recorded pressure.
110-
dt: The simulation time step in seconds.
97+
:param params: Simulation grid dataset with sound_speed, density, attenuation.
98+
:param source_mask: 3D binary array with 1 at the source (target) voxel.
99+
:param sensor_mask: 3D binary array with 1s at sensor (element) voxels.
100+
:param freq: Source frequency in Hz.
101+
:param n_cycles: Number of cycles in the source pulse.
102+
:param sound_speed_ref: Reference speed of sound (m/s) for time stepping.
103+
:param cfl: Courant-Friedrichs-Lewy number for time stepping.
104+
:param gpu: Whether to use GPU acceleration.
105+
:param ref_values_only: If True, use reference (homogeneous) medium values.
106+
:returns: Tuple of (sensor_data, dt) where sensor_data is a 2D array
107+
(n_sensor_points, n_timesteps) and dt is the time step in seconds.
111108
"""
112-
from kwave.kgrid import kWaveGrid
113-
from kwave.kmedium import kWaveMedium
114109
from kwave.ksensor import kSensor
115110
from kwave.ksource import kSource
116111
from kwave.kspaceFirstOrder3D import kspaceFirstOrder3D

0 commit comments

Comments
 (0)