Skip to content

Commit 9e98d6e

Browse files
committed
make fixes necessary for strict-sort tests to pass even if image_defs are randomly sorted
1 parent 9a644b7 commit 9e98d6e

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

nibabel/parrec.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -734,15 +734,17 @@ def get_bvals_bvecs(self):
734734
n_slices, n_vols = self.get_data_shape()[-2:]
735735
bvals = self.image_defs['diffusion_b_factor'][reorder].reshape(
736736
(n_slices, n_vols), order='F')
737-
# All bvals within volume should be the same
738-
assert not np.any(np.diff(bvals, axis=0))
737+
if not self.strict_sort:
738+
# All bvals within volume should be the same
739+
assert not np.any(np.diff(bvals, axis=0))
739740
bvals = bvals[0]
740741
if 'diffusion' not in self.image_defs.dtype.names:
741742
return bvals, None
742743
bvecs = self.image_defs['diffusion'][reorder].reshape(
743744
(n_slices, n_vols, 3), order='F')
744-
# All 3 values of bvecs should be same within volume
745-
assert not np.any(np.diff(bvecs, axis=0))
745+
if not self.strict_sort:
746+
# All 3 values of bvecs should be same within volume
747+
assert not np.any(np.diff(bvecs, axis=0))
746748
bvecs = bvecs[0]
747749
# rotate bvecs to match stored image orientation
748750
permute_to_psl = ACQ_TO_PSL[self.get_slice_orientation()]
@@ -1046,19 +1048,21 @@ def _strict_sort_keys(self):
10461048
diffusion_keys = ()
10471049

10481050
# Define the desired sort order (last key is highest precedence)
1049-
keys = (slice_nos, vol_numbers(slice_nos), echos, phases) + \
1051+
keys = (slice_nos, echos, phases) + \
10501052
diffusion_keys + asl_keys + (dynamics, image_type)
10511053

10521054
initial_sort_order = np.lexsort(keys)
1055+
vol_nos = vol_numbers(slice_nos[initial_sort_order])
10531056
is_full = vol_is_full(slice_nos[initial_sort_order],
10541057
self.general_info['max_slices'])
10551058

10561059
# have to "unsort" is_full and volumes to match the other sort keys
10571060
unsort_indices = np.argsort(initial_sort_order)
10581061
is_full = is_full[unsort_indices]
1062+
vol_nos = np.asarray(vol_nos)[unsort_indices]
10591063

10601064
# final set of sort keys
1061-
return keys + (np.logical_not(is_full), )
1065+
return (keys[0], vol_nos) + keys[1:] + (np.logical_not(is_full), )
10621066

10631067
def get_sorted_slice_indices(self):
10641068
"""Return indices to sort (and maybe discard) slices in REC file.

nibabel/tests/test_parrec.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,16 @@ def test_get_sorted_slice_indices():
268268
def test_sorting_dual_echo_T1():
269269
# For this .PAR file, instead of getting 1 echo per volume, they get
270270
# mixed up unless strict_sort=True
271-
dti_par = pjoin(DATA_PATH, 'T1_dual_echo.PAR')
272-
with open(dti_par, 'rt') as fobj:
273-
dti_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
274-
sorted_indices = dti_hdr.get_sorted_slice_indices()
275-
sorted_echos = dti_hdr.image_defs['echo number'][sorted_indices]
276-
n_half = len(dti_hdr.image_defs) // 2
271+
t1_par = pjoin(DATA_PATH, 'T1_dual_echo.PAR')
272+
with open(t1_par, 'rt') as fobj:
273+
t1_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
274+
275+
# should get the correct order even if we randomly shuffle the order
276+
np.random.shuffle(t1_hdr.image_defs)
277+
278+
sorted_indices = t1_hdr.get_sorted_slice_indices()
279+
sorted_echos = t1_hdr.image_defs['echo number'][sorted_indices]
280+
n_half = len(t1_hdr.image_defs) // 2
277281
# first half (volume 1) should all correspond to echo 1
278282
assert_equal(np.all(sorted_echos[:n_half] == 1), True)
279283
# second half (volume 2) should all correspond to echo 2
@@ -290,15 +294,19 @@ def test_sorting_multiple_echos_and_contrasts():
290294
# Type 1, Echo 1, Slices 1-30
291295
# ...
292296
# Type 3, Echo 3, Slices 1-30
293-
dti_par = pjoin(DATA_PATH, 'T1_3echo_mag_real_imag_phase.PAR')
294-
with open(dti_par, 'rt') as fobj:
295-
dti_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
296-
sorted_indices = dti_hdr.get_sorted_slice_indices()
297-
sorted_slices = dti_hdr.image_defs['slice number'][sorted_indices]
298-
sorted_echos = dti_hdr.image_defs['echo number'][sorted_indices]
299-
sorted_types = dti_hdr.image_defs['image_type_mr'][sorted_indices]
297+
t1_par = pjoin(DATA_PATH, 'T1_3echo_mag_real_imag_phase.PAR')
298+
with open(t1_par, 'rt') as fobj:
299+
t1_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
300300

301-
ntotal = len(dti_hdr.image_defs)
301+
# should get the correct order even if we randomly shuffle the order
302+
np.random.shuffle(t1_hdr.image_defs)
303+
304+
sorted_indices = t1_hdr.get_sorted_slice_indices()
305+
sorted_slices = t1_hdr.image_defs['slice number'][sorted_indices]
306+
sorted_echos = t1_hdr.image_defs['echo number'][sorted_indices]
307+
sorted_types = t1_hdr.image_defs['image_type_mr'][sorted_indices]
308+
309+
ntotal = len(t1_hdr.image_defs)
302310
nslices = sorted_slices.max()
303311
nechos = sorted_echos.max()
304312
for slice_offset in range(ntotal//nslices):
@@ -321,15 +329,19 @@ def test_sorting_multiple_echos_and_contrasts():
321329
def test_sorting_multiecho_ASL():
322330
# For this .PAR file has 3 keys corresponding to volumes:
323331
# 'echo number', 'label type', 'dynamic scan number'
324-
dti_par = pjoin(DATA_PATH, 'ASL_3D_Multiecho.PAR')
325-
with open(dti_par, 'rt') as fobj:
326-
dti_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
327-
sorted_indices = dti_hdr.get_sorted_slice_indices()
328-
sorted_slices = dti_hdr.image_defs['slice number'][sorted_indices]
329-
sorted_echos = dti_hdr.image_defs['echo number'][sorted_indices]
330-
sorted_dynamics = dti_hdr.image_defs['dynamic scan number'][sorted_indices]
331-
sorted_labels = dti_hdr.image_defs['label type'][sorted_indices]
332-
ntotal = len(dti_hdr.image_defs)
332+
asl_par = pjoin(DATA_PATH, 'ASL_3D_Multiecho.PAR')
333+
with open(asl_par, 'rt') as fobj:
334+
asl_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
335+
336+
# should get the correct order even if we randomly shuffle the order
337+
np.random.shuffle(asl_hdr.image_defs)
338+
339+
sorted_indices = asl_hdr.get_sorted_slice_indices()
340+
sorted_slices = asl_hdr.image_defs['slice number'][sorted_indices]
341+
sorted_echos = asl_hdr.image_defs['echo number'][sorted_indices]
342+
sorted_dynamics = asl_hdr.image_defs['dynamic scan number'][sorted_indices]
343+
sorted_labels = asl_hdr.image_defs['label type'][sorted_indices]
344+
ntotal = len(asl_hdr.image_defs)
333345
nslices = sorted_slices.max()
334346
nechos = sorted_echos.max()
335347
nlabels = sorted_labels.max()
@@ -439,6 +451,10 @@ def test_diffusion_parameters_strict_sort():
439451
dti_par = pjoin(DATA_PATH, 'DTI.PAR')
440452
with open(dti_par, 'rt') as fobj:
441453
dti_hdr = PARRECHeader.from_fileobj(fobj, strict_sort=True)
454+
455+
# should get the correct order even if we randomly shuffle the order
456+
np.random.shuffle(dti_hdr.image_defs)
457+
442458
assert_equal(dti_hdr.get_data_shape(), (80, 80, 10, 8))
443459
assert_equal(dti_hdr.general_info['diffusion'], 1)
444460
bvals, bvecs = dti_hdr.get_bvals_bvecs()

0 commit comments

Comments
 (0)