Skip to content

Commit

Permalink
Removed automatic model selection entirely
Browse files Browse the repository at this point in the history
Was more trouble than it was worth implementing it!
  • Loading branch information
alexdaniel654 committed Nov 13, 2024
1 parent 4928e22 commit 3ace838
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 94 deletions.
67 changes: 15 additions & 52 deletions ukat/mapping/t1.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,13 @@ def __init__(self, pixel_array, ti, parameters=2, mask=None, tss=0,
would be along the TI axis and would be meaningless.
If `pixel_array` is single slice (dimensions [x, y, TI]),
then this should be set to None.
mag_corr : {True, False, 'auto'}, optional
mag_corr : bool, optional
Default False
If True, the data is assumed to have been magnitude corrected
using the complex component of the signal and thus negative
values represent inverted signal. If False, the data will be
fit to the modulus of the expected signal, negative values are
simply considered part of the noise in the data. If 'auto',
the data will be assumed to have been magnitude corrected if 5%
of the initial inversion time data is negative.
simply considered part of the noise in the data.
multithread : bool, optional
Default True
If True, the fitting will be performed in parallel using all
Expand All @@ -61,47 +59,15 @@ def __init__(self, pixel_array, ti, parameters=2, mask=None, tss=0,
self.tss = tss
self.tss_axis = tss_axis

if mag_corr == 'auto':
# Find a very rough estimate of the fully recovered signal
recovered_signal = np.percentile(pixel_array[..., -1], 95)

# If the fifth percentile of the first inversion time is
# less than the negative of 5% of the recovered signal
# then assume the data has been magnitude corrected
if (np.percentile(pixel_array[..., 0], 5)
< -recovered_signal * 0.05):
self.mag_corr = True
neg_percent = (np.sum(pixel_array[..., 0] < 0)
/ pixel_array[..., 0].size)
if neg_percent < 0.05:
warnings.warn('Fitting data to a magnitude corrected '
'inversion recovery curve however, less '
'than 5% of the data from the first '
'inversion is negative. If you have '
'performed magnitude correction ignore '
'this warning, otherwise the negative '
'values could be due to noise or '
'preprocessing steps such as EPI '
'distortion correction and registration.\n'
f'Percentage of first inversion data that '
f'is negative = {neg_percent:.2%}')
else:
self.mag_corr = False
if np.nanmin(pixel_array) < 0:
warnings.warn('Negative values found in data from the '
'first inversion but as the first '
'percentile is not negative, it is assumed '
'these are negative due to noise or '
'preprocessing steps such as EPI '
'distortion correction and registration. '
'As such the data will be fit to the '
'modulus of the recovery curve.\n'
f'Min value = '
f'{np.nanmin(pixel_array[..., 0])}\n'
'5th percentile = '
f'{np.percentile(pixel_array[..., 0], 5)}')
else:
self.mag_corr = mag_corr
if (mag_corr == False) & (np.nanmin(pixel_array) < 0):
warnings.warn('Negative values found in data, this could be due '
'to noise or preprocessing steps, however if you '
'have magnitude corrected your data, remember to '
'set mag_corr=True\n'
f'Min value = '
f'{np.nanmin(pixel_array[..., 0])}\n')

self.mag_corr = mag_corr

if self.parameters == 2:
if self.mag_corr:
Expand Down Expand Up @@ -207,15 +173,13 @@ def __init__(self, pixel_array, inversion_list, affine, tss=0, tss_axis=-2,
The number of parameters to fit the data to. A two parameter fit
will estimate S0 and T1 while a three parameter fit will also
estimate the inversion efficiency.
mag_corr : {True, False, 'auto'}, optional
mag_corr : bool, optional
Default False
If True, the data is assumed to have been magnitude corrected
using the complex component of the signal and thus negative
values represent inverted signal. If False, the data will be
fit to the modulus of the expected signal, negative values are
simply considered part of the noise in the data. If 'auto',
the data will be assumed to have been magnitude corrected if 5%
of the initial inversion time data is negative.
simply considered part of the noise in the data.
molli : bool, optional
Default False.
Apply MOLLI corrections to T1.
Expand All @@ -238,9 +202,8 @@ def __init__(self, pixel_array, inversion_list, affine, tss=0, tss_axis=-2,
f'be True, False or auto. You '
f'entered { multithread}.')
assert mag_corr in [True,
False,
'auto'], (f'mag_corr must be True, False or auto. '
f'You entered {mag_corr}.')
False], (f'mag_corr must be True or False. '
f'You entered {mag_corr}.')

self.pixel_array = pixel_array
self.shape = pixel_array.shape[:-1]
Expand Down
48 changes: 6 additions & 42 deletions ukat/mapping/tests/test_t1.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,54 +289,18 @@ def test_mag_corr_options(self):
npt.assert_almost_equal(mapper.r1_map().mean(), 1 / self.t1)
npt.assert_almost_equal(mapper.r2.mean(), 1)

# Test negative values warning when mag_corr is False
with pytest.warns(UserWarning):
signal_array[0, 0, 0, 0] = -1000
mapper = T1(signal_array, self.t, self.affine, mag_corr=False,
multithread=False)

# Test with mag_corr not recognised input
with pytest.raises(AssertionError):
mapper = T1(signal_array, self.t, self.affine,
mag_corr='yes please',
multithread=False)

def test_auto_mag_corr(self):
# Test warning for small number of negative values thus assuming no
# magnitude correction has been performed

# Make the absolute of the signal into a 4D array
signal_array = np.tile(np.abs(self.correct_signal_two_param),
(10, 10, 3, 1))
# Add a single negative value to the signal
signal_array[0, 0, 0, 0] = -1000

with pytest.warns(UserWarning):
mapper = T1(signal_array, self.t, self.affine,
mag_corr='auto', multithread=False)

# Test warning for enough negative values to assume magnitude
# correction has been performed but still not that many negative values

# Make the of the signal into a 4D array
signal_array = np.tile(np.abs(self.correct_signal_two_param),
(10, 10, 3, 1))
# Add a row of signals with negative values to the image
# 3.3% of first inversion is negative but 1st percentile is negative.
signal_array[:, 0, 0, :] = self.correct_signal_two_param

with pytest.warns(UserWarning):
mapper = T1(signal_array, self.t, self.affine,
mag_corr='auto', multithread=False)

# Test that giving abs data leads to mag_corr = False
signal_array = np.tile(np.abs(self.correct_signal_two_param),
(10, 10, 3, 1))
mapper = T1(signal_array, self.t, self.affine, mag_corr='auto',
multithread=False)
assert mapper.mag_corr is False

# Test that giving mag corrected data leads to mag_corr = True
signal_array = np.tile(self.correct_signal_two_param,
(10, 10, 3, 1))
mapper = T1(signal_array, self.t, self.affine, mag_corr='auto',
multithread=False)
assert mapper.mag_corr is True


def test_molli_2p_warning(self):
signal_array = np.tile(self.correct_signal_three_param, (10, 10, 3, 1))
Expand Down

0 comments on commit 3ace838

Please sign in to comment.