From 3ace838d19f49c5dd79f0f00ee686a4422d7b777 Mon Sep 17 00:00:00 2001 From: Alex Daniel Date: Wed, 13 Nov 2024 16:53:32 +0000 Subject: [PATCH] Removed automatic model selection entirely Was more trouble than it was worth implementing it! --- ukat/mapping/t1.py | 67 ++++++++--------------------------- ukat/mapping/tests/test_t1.py | 48 ++++--------------------- 2 files changed, 21 insertions(+), 94 deletions(-) diff --git a/ukat/mapping/t1.py b/ukat/mapping/t1.py index 017d064..f3f1aab 100644 --- a/ukat/mapping/t1.py +++ b/ukat/mapping/t1.py @@ -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 @@ -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: @@ -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. @@ -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] diff --git a/ukat/mapping/tests/test_t1.py b/ukat/mapping/tests/test_t1.py index 45933dc..8daf72a 100644 --- a/ukat/mapping/tests/test_t1.py +++ b/ukat/mapping/tests/test_t1.py @@ -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))