Skip to content

Commit 57b2aa1

Browse files
Merge pull request #113 from OSIPI/parallel
Parallel
2 parents 8c632cf + a75d9c0 commit 57b2aa1

25 files changed

+615
-126
lines changed

.github/workflows/unit_test.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ jobs:
3333
- name: Test with pytest
3434
run: |
3535
pip install pytest pytest-cov
36-
python -m pytest --doctest-modules --junitxml=junit/test-results.xml --cov=. --cov-report=xml --cov-report=html
36+
python -m pytest --doctest-modules --junitxml=junit/test-results.xml --cov=. --cov-report=xml --cov-report=html -r w
37+

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
__pycache__/
66
*.nii.gz
77
*.nii
8+
*.npy
89
*.dcm
910
*.npy
1011
*.mat

conftest.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import json
44
import csv
55
# import datetime
6-
6+
import numpy as np
7+
from phantoms.MR_XCAT_qMRI.sim_ivim_sig import phantom
78

89
def pytest_addoption(parser):
910
parser.addoption(
@@ -263,7 +264,8 @@ def algorithmlist(algorithms):
263264
for algorithm in algorithms["algorithms"]:
264265
algorithm_dict = algorithms.get(algorithm, {})
265266
requires_matlab = algorithm_dict.get("requires_matlab", False)
266-
yield algorithm, requires_matlab, algorithm_dict.get('deep_learning', False)
267+
if not algorithm_dict.get('deep_learning', False):
268+
yield algorithm, requires_matlab
267269

268270

269271
def bound_input(datafile, algorithms):
@@ -302,3 +304,16 @@ def deep_learning_algorithms(datafile, algorithms):
302304
requires_matlab = algorithm_dict.get("requires_matlab", False)
303305
tolerances = algorithm_dict.get("tolerances", {"atol":{"f": 2e-1, "D": 8e-4, "Dp": 8e-2},"rtol":{"f": 0.2, "D": 0.3, "Dp": 0.4}})
304306
yield algorithm, all_data, bvals, kwargs, requires_matlab, tolerances
307+
308+
309+
@pytest.fixture(scope="session")
310+
def threeddata(request):
311+
current_folder = pathlib.Path.cwd()
312+
datafile = request.config.getoption("dataFile")
313+
generic = current_folder / datafile
314+
with generic.open() as f:
315+
all_data = json.load(f)
316+
bvals = all_data.pop('config')
317+
bvals = np.array(bvals['bvalues'])
318+
sig, _, Dim, fim, Dpim, _=phantom(bvals, 1/1000, TR=3000, TE=40, motion=False, rician=False, interleaved=False, T1T2=True)
319+
return sig[::16,::8,::6,:], Dim[::16,::8,::6], fim[::16,::8,::6], Dpim[::16,::8,::6], bvals

phantoms/MR_XCAT_qMRI/sim_ivim_sig.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,33 @@
55
import argparse
66
import os
77
from utilities.data_simulation.Download_data import download_data
8+
import pathlib
89

910
##########
1011
# code written by Oliver J Gurney-Champion
1112
# code adapted from MAtlab code by Eric Schrauben: https://github.com/schrau24/XCAT-ERIC
1213
# This code generates a 4D IVIM phantom as nifti file
1314

1415
def phantom(bvalue, noise, TR=3000, TE=40, motion=False, rician=False, interleaved=False,T1T2=True):
16+
download_data()
1517
np.random.seed(42)
1618
if motion:
1719
states = range(1,21)
1820
else:
1921
states = [1]
2022
for state in states:
2123
# Load the .mat file
22-
mat_data = loadmat('../../download/Phantoms/XCAT_MAT_RESP/XCAT5D_RP_' + str(state) + '_CP_1.mat')
24+
project_root = pathlib.Path(__file__).resolve().parent.parent
25+
filename = f'XCAT5D_RP_{state}_CP_1.mat'
26+
mat_path = project_root / '..' /'download' / 'Phantoms' / 'XCAT_MAT_RESP' / filename
27+
mat_data = loadmat(mat_path)
2328

2429
# Access the variables in the loaded .mat file
2530
XCAT = mat_data['IMG']
2631
XCAT = XCAT[-1:0:-2,-1:0:-2,10:160:4]
2732

2833
D, f, Ds = contrast_curve_calc()
29-
S, Dim, fim, Dpim, legend = XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, D, f, Ds,T1T2=T1T2)
34+
S, Dim, fim, Dpim, legend = XCAT_to_MR_IVIM(XCAT, TR, TE, bvalue, D, f, Ds,T1T2=T1T2)
3035
if state == 1:
3136
Dim_out = Dim
3237
fim_out = fim
@@ -187,7 +192,7 @@ def contrast_curve_calc():
187192
return D, f, Ds
188193

189194

190-
def XCAT_to_MR_DCE(XCAT, TR, TE, bvalue, D, f, Ds, b0=3, ivim_cont = True, T1T2=True):
195+
def XCAT_to_MR_IVIM(XCAT, TR, TE, bvalue, D, f, Ds, b0=3, ivim_cont = True, T1T2=True):
191196
###########################################################################################
192197
# This script converts XCAT tissue values to MR contrast based on the SSFP signal equation.
193198
# Christopher W. Roy 2018-12-04 # [email protected]
@@ -436,7 +441,6 @@ def parse_bvalues_file(file_path):
436441
motion = args.motion
437442
interleaved = args.interleaved
438443
T1T2 = args.T1T2
439-
download_data()
440444
for key, bvalue in bvalues.items():
441445
bvalue = np.array(bvalue)
442446
sig, XCAT, Dim, fim, Dpim, legend = phantom(bvalue, noise, motion=motion, interleaved=interleaved,T1T2=T1T2)

pytest.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ markers =
33
slow: marks tests as slow (deselect with '-m "not slow"')
44
addopts =
55
-m 'not slow'
6-
testpaths = tests
6+
testpaths = tests
7+
filterwarnings =
8+
ignore::Warning
9+
always::tests.IVIMmodels.unit_tests.test_ivim_fit.PerformanceWarning

src/original/ETP_SRI/LinearFitting.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
import numpy.polynomial.polynomial as poly
3+
import warnings
34

45
from utilities.data_simulation.GenerateData import GenerateData
56

@@ -82,11 +83,17 @@ def ivim_fit(self, bvalues, signal):
8283
# print(Dp_prime)
8384

8485
if np.any(np.asarray(Dp_prime) < 0) or not np.all(np.isfinite(Dp_prime)):
85-
print('Perfusion fit failed')
86+
warnings.warn('Perfusion fit failed',
87+
category=UserWarning,
88+
stacklevel=2 # Ensures correct file/line info in the warning
89+
)
8690
Dp_prime = [0, 0]
8791
f = signal[0] - D[0]
8892
else:
89-
print("This doesn't seem to be an IVIM set of b-values")
93+
warnings.warn('This doesn\'t seem to be an IVIM set of b-values',
94+
category=UserWarning,
95+
stacklevel=2 # Ensures correct file/line info in the warning
96+
)
9097
f = 1
9198
Dp_prime = [0, 0]
9299
D = D[1]

src/original/PvH_KB_NKI/DWI_functions_standalone.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"""
1111

1212
import numpy as np
13+
import warnings
14+
1315

1416
def generate_ADC_standalone(DWIdata, bvalues, bmin: int = 150, bmax: int = 1000, specificBvals: list = []):
1517
"""
@@ -116,9 +118,11 @@ def generate_IVIMmaps_standalone(DWIdata, bvalues, bminADC=150, bmaxADC=1000, bm
116118
raise Exception('b=0 was not acquired')
117119

118120
if len(bvalues) > 2:
119-
print('More than two b-values were detected for D* calculation. ' +
120-
'Note that only the first two will be used for D*.')
121-
121+
warnings.warn(
122+
'More than two b-values were detected for D* calculation. ' + 'Note that only the first two will be used for D*.',
123+
category=UserWarning,
124+
stacklevel=2 # Ensures correct file/line info in the warning
125+
)
122126
except Exception as e:
123127
print("Could not calculate D* due to an error: " + str(e))
124128
return

src/original/TF_reference/segmented_IVIMfit.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def segmented_IVIM_fit(bvalues, dw_data, b_cutoff = 200, bounds=([0.0001, 0.0, 0
2424
"""
2525
bvalues_D = bvalues[bvalues >= b_cutoff]
2626
dw_data_D = dw_data[bvalues >= b_cutoff]
27+
dw_data_D = np.clip(dw_data_D, 1e-6, None) # ensure we do not get 0 or negative values that cause nans/infs
2728
log_data_D = np.log(dw_data_D)
2829

2930
D, b0_intercept = d_fit_iterative_wls(bvalues_D, log_data_D)

src/standardized/ETP_SRI_LinearFitting.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import numpy as np
22
from src.wrappers.OsipiBase import OsipiBase
33
from src.original.ETP_SRI.LinearFitting import LinearFit
4+
import warnings
5+
warnings.simplefilter('once', UserWarning)
46

57

68
class ETP_SRI_LinearFitting(OsipiBase):

src/standardized/IAR_LU_biexp.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,9 @@ def ivim_fit_full_volume(self, signals, bvalues, **kwargs):
114114
gtab = gradient_table(bvalues, bvec, b0_threshold=0)
115115

116116
self.IAR_algorithm = IvimModelBiExp(gtab, bounds=self.bounds, initial_guess=self.initial_guess)
117-
118-
fit_results = self.IAR_algorithm.fit(signals)
117+
b0_index = np.where(bvalues == 0)[0][0]
118+
mask = signals[...,b0_index]>0
119+
fit_results = self.IAR_algorithm.fit(signals, mask=mask)
119120

120121
results = {}
121122
results["f"] = fit_results.model_params[..., 1]

0 commit comments

Comments
 (0)