Skip to content

Commit fbf5952

Browse files
committed
Add ETP Linear testing and add testing configuration
1 parent 806517d commit fbf5952

File tree

3 files changed

+53
-41
lines changed

3 files changed

+53
-41
lines changed

src/original/ETP_SRI/LinearFitting.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def ivim_fit(self, bvalues, signal):
6666
gt_cutoff = bvalues >= self.linear_cutoff
6767
linear_signal = np.log(signal)
6868
D = self.linear_fit(bvalues[gt_cutoff], linear_signal[gt_cutoff])
69+
D[1] = max(D[1], 0) # constrain to positive values
6970

7071
if lt_cutoff.sum() > 0:
7172
signal_Dp = linear_signal[lt_cutoff] - gd.linear_signal(D[1], bvalues[lt_cutoff], np.log(D[0]))

tests/IVIMmodels/unit_tests/test_ivim_fit.py

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010

1111
#run using python -m pytest from the root folder
1212

13-
test_linear_data = [
14-
pytest.param(0, np.linspace(0, 1000, 11), id='0'),
15-
pytest.param(0.01, np.linspace(0, 1000, 11), id='0.1'),
16-
pytest.param(0.02, np.linspace(0, 1000, 11), id='0.2'),
17-
pytest.param(0.03, np.linspace(0, 1000, 11), id='0.3'),
18-
pytest.param(0.04, np.linspace(0, 1000, 11), id='0.4'),
19-
pytest.param(0.05, np.linspace(0, 1000, 11), id='0.5'),
20-
pytest.param(0.08, np.linspace(0, 1000, 11), id='0.8'),
21-
pytest.param(0.1, np.linspace(0, 1000, 11), id='1'),
22-
]
13+
# test_linear_data = [
14+
# pytest.param(0, np.linspace(0, 1000, 11), id='0'),
15+
# pytest.param(0.01, np.linspace(0, 1000, 11), id='0.1'),
16+
# pytest.param(0.02, np.linspace(0, 1000, 11), id='0.2'),
17+
# pytest.param(0.03, np.linspace(0, 1000, 11), id='0.3'),
18+
# pytest.param(0.04, np.linspace(0, 1000, 11), id='0.4'),
19+
# pytest.param(0.05, np.linspace(0, 1000, 11), id='0.5'),
20+
# pytest.param(0.08, np.linspace(0, 1000, 11), id='0.8'),
21+
# pytest.param(0.1, np.linspace(0, 1000, 11), id='1'),
22+
# ]
2323

2424
#@pytest.mark.parametrize("D, bvals", test_linear_data)
2525
#def test_linear_fit(D, bvals):
@@ -30,14 +30,14 @@
3030
#D_fit = fit.linear_fit(bvals, np.log(gd_signal))
3131
#npt.assert_allclose([1, D], D_fit)
3232

33-
test_ivim_data = [
34-
pytest.param(0, 0.01, 0.05, np.linspace(0, 1000, 11), id='0'),
35-
pytest.param(0.1, 0.01, 0.05, np.linspace(0, 1000, 11), id='0.1'),
36-
pytest.param(0.2, 0.01, 0.05, np.linspace(0, 1000, 11), id='0.2'),
37-
pytest.param(0.1, 0.05, 0.1, np.linspace(0, 1000, 11), id='0.3'),
38-
pytest.param(0.4, 0.001, 0.05, np.linspace(0, 1000, 11), id='0.4'),
39-
pytest.param(0.5, 0.001, 0.05, np.linspace(0, 1000, 11), id='0.5'),
40-
]
33+
# test_ivim_data = [
34+
# pytest.param(0, 0.01, 0.05, np.linspace(0, 1000, 11), id='0'),
35+
# pytest.param(0.1, 0.01, 0.05, np.linspace(0, 1000, 11), id='0.1'),
36+
# pytest.param(0.2, 0.01, 0.05, np.linspace(0, 1000, 11), id='0.2'),
37+
# pytest.param(0.1, 0.05, 0.1, np.linspace(0, 1000, 11), id='0.3'),
38+
# pytest.param(0.4, 0.001, 0.05, np.linspace(0, 1000, 11), id='0.4'),
39+
# pytest.param(0.5, 0.001, 0.05, np.linspace(0, 1000, 11), id='0.5'),
40+
# ]
4141

4242
#@pytest.mark.parametrize("f, D, Dp, bvals", test_ivim_data)
4343
#def test_ivim_fit(f, D, Dp, bvals):
@@ -58,36 +58,46 @@
5858
#npt.assert_allclose(Dp, Dp_fit, rtol=1e-2, atol=1e-3)
5959

6060
def data_ivim_fit_saved():
61-
# Find the algorithm file in the folder structure
62-
path = pathlib.Path(__file__).resolve().parents[3] # Move up to the root folder
63-
path_standardized_algortihms = path / "src" / "standardized" # Move to the folder containing the algorithms
64-
algorithms = os.listdir(path_standardized_algortihms) # Get the contents of the folder
65-
66-
# Remove the .py extensions from the algorithm names
67-
algorithms = [algorithm for algorithm in algorithms if algorithm[0:2].isupper()]
68-
algorithms = [algorithm.split(".")[0] for algorithm in algorithms]
69-
70-
61+
# Find the algorithms from algorithms.json
7162
file = pathlib.Path(__file__)
63+
algorithm_path = file.with_name('algorithms.json')
64+
with algorithm_path.open() as f:
65+
algorithm_information = json.load(f)
66+
67+
# Load generic test data generated from the included phantom: phantoms/MR_XCAT_qMRI
7268
generic = file.with_name('generic.json')
7369
with generic.open() as f:
7470
all_data = json.load(f)
75-
bvals = all_data.pop('config')
76-
bvals = bvals['bvalues']
77-
for name, data in all_data.items():
78-
for algorithm in algorithms:
79-
yield name, bvals, data, algorithm
71+
72+
algorithms = algorithm_information["algorithms"]
73+
bvals = all_data.pop('config')
74+
bvals = bvals['bvalues']
75+
for name, data in all_data.items():
76+
for algorithm in algorithms:
77+
algorithm_dict = algorithm_information.get(algorithm, {})
78+
xfail = name in algorithm_dict.get("xfail_names", [])
79+
kwargs = algorithm_dict.get("options", {})
80+
tolerances = algorithm_dict.get("tolerances", None)
81+
yield name, bvals, data, algorithm, xfail, kwargs, tolerances
8082

8183

82-
@pytest.mark.parametrize("name, bvals, data, algorithm", data_ivim_fit_saved())
83-
def test_ivim_fit_saved(name, bvals, data, algorithm):
84-
fit = OsipiBase(algorithm=algorithm, thresholds=[500])
84+
@pytest.mark.parametrize("name, bvals, data, algorithm, xfail, kwargs, tolerances", data_ivim_fit_saved())
85+
def test_ivim_fit_saved(name, bvals, data, algorithm, xfail, kwargs, tolerances, request):
86+
if xfail:
87+
mark = pytest.mark.xfail(reason="xfail", strict=True)
88+
request.node.add_marker(mark)
89+
fit = OsipiBase(algorithm=algorithm, **kwargs)
8590
signal = np.asarray(data['data'])
86-
has_negatives = np.any(signal<0)
8791
signal = np.abs(signal)
88-
ratio = 1 / signal[0]
8992
signal /= signal[0]
90-
tolerance = 1e-2 + 25 * data['noise'] * ratio # totally empirical
93+
# has_negatives = np.any(signal<0)
94+
if tolerances is None:
95+
# signal = np.abs(signal)
96+
# ratio = 1 / signal[0]
97+
# signal /= signal[0]
98+
# tolerance = 1e-2 + 25 * data['noise'] * ratio # totally empirical
99+
# tolerance = 1
100+
tolerances = {"f": 5, "D": 5, "Dp": 25}
91101
#if has_negatives: # this fitting doesn't do well with negatives
92102
# tolerance += 1
93103
#if data['f'] == 1.0:
@@ -98,5 +108,6 @@ def test_ivim_fit_saved(name, bvals, data, algorithm):
98108
#npt.assert_allclose([data['f'], data['D']], [f_fit, D_fit], atol=tolerance)
99109
#npt.assert_allclose(data['Dp'], Dp_fit, atol=1e-1) # go easy on the perfusion as it's a linear fake
100110
[f_fit, Dp_fit, D_fit] = fit.ivim_fit(signal, bvals)
101-
npt.assert_allclose([data['f'], data['D']], [f_fit, D_fit], atol=tolerance)
102-
npt.assert_allclose(data['Dp'], Dp_fit, atol=1e-1) # go easy on the perfusion as it's a linear fake
111+
npt.assert_allclose(data['f'], f_fit, rtol=tolerances["f"])
112+
npt.assert_allclose(data['D'], D_fit, rtol=tolerances["D"])
113+
npt.assert_allclose(data['Dp'], Dp_fit, rtol=tolerances["Dp"]) # go easy on the perfusion as it's a linear fake

0 commit comments

Comments
 (0)