Skip to content

Commit 40e6519

Browse files
jhlegarretaoesteban
andcommitted
ENH: Add a shell data property to DWI data class
Add a shell data property to `DWI` data class that returns a list of pairs consisting of the estimated b-value and the associated DWI data. Co-authored-by: Oscar Esteban <code@oscaresteban.es>
1 parent 9a143e4 commit 40e6519

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

src/nifreeze/data/dmri.py

+38
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,44 @@ def to_nifti(self, filename: Path | str, insert_b0: bool = False) -> None:
242242
np.savetxt(bvecs_file, self.gradients[:3, ...].T, fmt="%.6f")
243243
np.savetxt(bvals_file, self.gradients[:3, ...], fmt="%.6f")
244244

245+
def shells(
246+
self,
247+
num_bins: int = DEFAULT_NUM_BINS,
248+
multishell_nonempty_bin_count_thr: int = DEFAULT_MULTISHELL_BIN_COUNT_THR,
249+
bval_cap: int = DEFAULT_HIGHB_THRESHOLD,
250+
) -> list:
251+
"""Get the shell data according to the b-value groups.
252+
253+
Bin the shell data according to the b-value groups found by `~find_shelling_scheme`.
254+
255+
Parameters
256+
----------
257+
num_bins : :obj:`int`, optional
258+
Number of bins.
259+
multishell_nonempty_bin_count_thr : :obj:`int`, optional
260+
Bin count to consider a multi-shell scheme.
261+
bval_cap : :obj:`int`, optional
262+
Maximum b-value to be considered in a multi-shell scheme.
263+
264+
Returns
265+
-------
266+
:obj:`list`
267+
Tuples of binned b-values and corresponding shell data.
268+
"""
269+
270+
_, bval_groups, bval_estimated = find_shelling_scheme(
271+
self.gradients[-1, ...],
272+
num_bins=num_bins,
273+
multishell_nonempty_bin_count_thr=multishell_nonempty_bin_count_thr,
274+
bval_cap=bval_cap,
275+
)
276+
indices = [
277+
np.hstack(np.where(np.isin(self.gradients[-1, ...], bvals))) for bvals in bval_groups
278+
]
279+
return [
280+
(bval_estimated[idx], *self[indices]) for idx, indices in enumerate(indices)
281+
]
282+
245283

246284
def load(
247285
filename: Path | str,

test/test_data_dmri.py

+36
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,42 @@ def test_equality_operator(tmp_path):
182182
assert round_trip_dwi_obj == dwi_obj
183183

184184

185+
def test_shells(datadir):
186+
dwi_h5 = load(datadir / "dwi.h5")
187+
num_bins = 3
188+
189+
_, expected_bval_groups, expected_bval_est = find_shelling_scheme(
190+
dwi_h5.gradients[-1, ...], num_bins=num_bins
191+
)
192+
193+
indices = [
194+
np.hstack(np.where(np.isin(dwi_h5.gradients[-1, ...], bvals)))
195+
for bvals in expected_bval_groups
196+
]
197+
expected_dwi_data = [dwi_h5.dataobj[..., idx] for idx in indices]
198+
expected_motion_affines = [dwi_h5.motion_affines[idx] if dwi_h5.motion_affines else None for idx in indices]
199+
expected_gradients = [dwi_h5.gradients[..., idx] for idx in indices]
200+
201+
shell_data = dwi_h5.shells(num_bins=num_bins)
202+
obtained_bval_est, obtained_dwi_data, obtained_motion_affines, obtained_gradients = zip(*shell_data, strict=True)
203+
204+
assert len(shell_data) == num_bins
205+
assert list(obtained_bval_est) == expected_bval_est
206+
assert all(
207+
np.allclose(arr1, arr2)
208+
for arr1, arr2 in zip(list(obtained_dwi_data), expected_dwi_data, strict=True)
209+
)
210+
assert all(
211+
(arr1 is None and arr2 is None) or
212+
(arr1 is not None and arr2 is not None and np.allclose(arr1, arr2))
213+
for arr1, arr2 in zip(list(obtained_motion_affines), expected_motion_affines, strict=True)
214+
)
215+
assert all(
216+
np.allclose(arr1, arr2)
217+
for arr1, arr2 in zip(list(obtained_gradients), expected_gradients, strict=True)
218+
)
219+
220+
185221
@pytest.mark.parametrize(
186222
("bvals", "exp_scheme", "exp_bval_groups", "exp_bval_estimated"),
187223
[

0 commit comments

Comments
 (0)