7
7
numpy
8
8
tqdm
9
9
scipy
10
- joblib
11
10
"""
12
11
13
12
# load relevant libraries
14
- from scipy .optimize import curve_fit , nnls
13
+ from scipy .optimize import curve_fit
15
14
import numpy as np
16
- from joblib import Parallel , delayed
17
15
import tqdm
18
16
19
17
20
18
21
19
22
20
def two_exp_noS0 (bvalues , Dpar , Fmv , Dmv ):
23
- """ tri -exponential IVIM function, and S0 set to 1"""
21
+ """ bi -exponential IVIM function, and S0 set to 1"""
24
22
return Fmv * np .exp (- bvalues * Dmv ) + (1 - Fmv ) * np .exp (- bvalues * Dpar )
25
23
26
24
def two_exp (bvalues , S0 , Dpar , Fmv , Dmv ):
27
- """ tri -exponential IVIM function"""
25
+ """ bi -exponential IVIM function"""
28
26
return S0 * (Fmv * np .exp (- bvalues * Dmv ) + (1 - Fmv ) * np .exp (- bvalues * Dpar ))
29
27
30
28
31
29
32
- def fit_least_squares_array (bvalues , dw_data , fitS0 = True , bounds = ([0.9 , 0.0001 , 0.0 , 0.0025 ], [1.1 , 0.0025 , 0.2 , 0.2 ]), cutoff = 200 ):
30
+ def fit_least_squares_array (bvalues , dw_data , fitS0 = False , bounds = ([0.9 , 0.0001 , 0.0 , 0.0025 ], [1.1 , 0.0025 , 0.5 , 0.2 ]), cutoff = 200 ):
33
31
"""
34
32
This is the LSQ implementation, in which we first estimate Dpar using a curve fit to b-values>=cutoff;
35
33
Second, we fit the other parameters using all b-values, while fixing Dpar from step 1. This fit
36
34
is done on an array.
37
35
:param bvalues: 1D Array with the b-values
38
36
:param dw_data: 2D Array with diffusion-weighted signal in different voxels at different b-values
39
- :param bounds: Array with fit bounds ([S0min, Dparmin, Fintmin, Dintmin, Fmvmin, Dmvmin],[S0max, Dparmax, Fintmax, Dintmax, Fmvmax, Dmvmax]). default: ([0.9, 0.0001, 0.0, 0.0015, 0.0, 0.004], [1.1, 0.0015, 0.4, 0.004, 0.2, 0.2])
37
+ :param bounds: Array with fit bounds ([S0min, Dparmin, Fmvmin, Dmvmin],[S0max, Dparmax, Fmvmax, Dmvmax]).
40
38
:param cutoff: cutoff b-value used in step 1
41
39
:return Dpar: 1D Array with Dpar in each voxel
42
40
:return Fmv: 1D Array with Fmv in each voxel
@@ -54,69 +52,56 @@ def fit_least_squares_array(bvalues, dw_data, fitS0=True, bounds=([0.9, 0.0001,
54
52
return [Dpar , Fmv , Dmv , S0 ]
55
53
56
54
57
- def fit_least_squares (bvalues , dw_data , IR = False , S0_output = False , fitS0 = True ,
58
- bounds = ([0.9 , 0.0001 , 0.0 , 0.0025 ], [1.1 , 0.0025 , 0.2 , 0.2 ]), cutoff = 200 ):
55
+ def fit_least_squares (bvalues , dw_data , S0_output = False , fitS0 = False ,
56
+ bounds = ([0.9 , 0.0001 , 0.0 , 0.0025 ], [1.1 , 0.003 , 1 , 0.2 ]), cutoff = 200 ):
59
57
"""
60
58
This is the LSQ implementation, in which we first estimate Dpar using a curve fit to b-values>=cutoff;
61
59
Second, we fit the other parameters using all b-values, while fixing Dpar from step 1. This fit
62
60
is done on an array. It fits a single curve
63
61
:param bvalues: 1D Array with the b-values
64
62
:param dw_data: 1D Array with diffusion-weighted signal in different voxels at different b-values
65
- :param IR: Boolean; True will fit the IVIM accounting for inversion recovery, False will fit IVIM without IR; default = True
66
- :param S0_output: Boolean determining whether to output (often a dummy) variable S0; default = False
67
- :param fix_S0: Boolean determining whether to fix S0 to 1; default = True
68
- :param bounds: Array with fit bounds ([S0min, Dparmin, Fintmin, Dintmin, Fmvmin, Dmvmin],[S0max, Dparmax, Fintmax, Dintmax, Fmvmax, Dmvmax]). Default: ([0, 0, 0, 0.005, 0, 0.06], [2.5, 0.005, 1, 0.06, 1, 0.5])
63
+ :param S0_output: Boolean determining whether to output (often a dummy) variable S0;
64
+ :param fitS0: Boolean determining whether to fix S0 to 1;
65
+ :param bounds: Array with fit bounds ([S0min, Dparmin, Fmvmin, Dmvmin],[S0max, Dparmax, Fmvmax, Dmvmax]).
69
66
:param cutoff: cutoff b-value used in step 1
70
67
:return S0: optional 1D Array with S0 in each voxel
71
68
:return Dpar: scalar with Dpar of the specific voxel
72
- :return Fint: scalar with Fint of the specific voxel
73
- :return Dint: scalar with Dint of the specific voxel
74
69
:return Fmv: scalar with Fmv of the specific voxel
75
70
:return Dmv: scalar with Dmv of the specific voxel
76
71
"""
77
72
78
73
#try:
79
- def monofit (bvalues , Dpar ):
80
- return np .exp (- bvalues * Dpar )
74
+ def monofit (bvalues , Dpar , Fmv ):
75
+ return ( 1 - Fmv ) * np .exp (- bvalues * Dpar )
81
76
82
77
high_b = bvalues [bvalues >= cutoff ]
83
78
high_dw_data = dw_data [bvalues >= cutoff ]
84
- boundspar = ([bounds [0 ][1 ]], [bounds [1 ][1 ]])
85
- params , _ = curve_fit (monofit , high_b , high_dw_data , p0 = [(bounds [1 ][1 ]- bounds [0 ][1 ])/ 2 ], bounds = boundspar )
86
- Dpar = params [0 ]
87
-
79
+ boundsmonoexp = ([bounds [0 ][1 ], bounds [0 ][2 ]], [bounds [1 ][1 ], bounds [1 ][2 ]])
80
+ params , _ = curve_fit (monofit , high_b , high_dw_data , p0 = [(bounds [1 ][1 ]- bounds [0 ][1 ])/ 2 ,(bounds [1 ][2 ]- bounds [0 ][2 ])/ 2 ], bounds = boundsmonoexp )
81
+ Dpar1 = params [0 ]
88
82
if not fitS0 :
89
- boundsupdated = ([Dpar1 , bounds [0 ][2 ] , bounds [0 ][3 ] ],
90
- [Dpar1 , bounds [1 ][2 ] , bounds [1 ][3 ] ])
91
- params , _ = curve_fit (two_exp_noS0 , bvalues , dw_data , p0 = [Dpar1 , (bounds [0 ][2 ]+ bounds [1 ][2 ])/ 2 , (bounds [0 ][3 ]+ bounds [1 ][3 ])/ 2 ], bounds = boundsupdated )
92
- Dpar1 , Fmv , Dmv = params [0 ], params [1 ], params [ 2 ]
83
+ boundsupdated = ([bounds [0 ][2 ] , bounds [0 ][3 ] ],
84
+ [bounds [1 ][2 ] , bounds [1 ][3 ] ])
85
+ params , _ = curve_fit (lambda b , Fmv , Dmv : two_exp_noS0 ( b , Dpar1 , Fmv , Dmv ), bvalues , dw_data , p0 = [(bounds [0 ][2 ]+ bounds [1 ][2 ])/ 2 , (bounds [0 ][3 ]+ bounds [1 ][3 ])/ 2 ], bounds = boundsupdated )
86
+ Fmv , Dmv = params [0 ], params [1 ]
93
87
#when the fraction of a compartment equals zero (or very very small), the corresponding diffusivity is non-existing (=NaN)
94
- if Fmv < 1e-4 :
95
- Dmv = float ("NaN" )
88
+ # if Fmv < 1e-4:
89
+ # Dmv = float("NaN")
96
90
97
91
else :
98
- #boundsupdated = ([bounds[0][0] , Dpar1 , bounds[0][2] , bounds[0][3] ],
99
- # [bounds[1][0] , Dpar1, bounds[1][2] , bounds[1][3] ])
100
- #params, _ = curve_fit(two_exp, bvalues, dw_data, p0=[1, Dpar1, (bounds[0][2]+bounds[1][2])/2, (bounds[0][3]+bounds[1][3])/2], bounds=boundsupdated)
101
92
boundsupdated = ([bounds [0 ][0 ] , bounds [0 ][2 ] , bounds [0 ][3 ] ],
102
93
[bounds [1 ][0 ] , bounds [1 ][2 ] , bounds [1 ][3 ] ])
103
- params , _ = curve_fit (lambda bvalues , S0 , Fmv , Dmv : two_exp (bvalues , S0 , Dpar , Fmv , Dmv ), bvalues , dw_data , p0 = [1 , (bounds [0 ][2 ]+ bounds [1 ][2 ])/ 2 , (bounds [0 ][3 ]+ bounds [1 ][3 ])/ 2 ], bounds = boundsupdated )
94
+ params , _ = curve_fit (lambda b , S0 , Fmv , Dmv : two_exp (b , S0 , Dpar1 , Fmv , Dmv ), bvalues , dw_data , p0 = [1 , (bounds [0 ][2 ]+ bounds [1 ][2 ])/ 2 , (bounds [0 ][3 ]+ bounds [1 ][3 ])/ 2 ], bounds = boundsupdated )
104
95
S0 = params [0 ]
105
96
Fmv , Dmv = params [1 ] , params [2 ]
106
97
#when the fraction of a compartment equals zero (or very very small), the corresponding diffusivity is non-existing (=NaN)
107
- if Fmv < 1e-4 :
108
- Dmv = float ("NaN" )
98
+ # if Fmv < 1e-4:
99
+ # Dmv = float("NaN")
109
100
110
101
if S0_output :
111
- return Dpar , Fmv , Dmv , S0
112
- else :
113
- return Dpar , Fmv , Dmv
114
- #except:
115
-
116
- if S0_output :
117
- return 0 , 0 , 0 , 0 , 0 , 0
102
+ return Dpar1 , Fmv , Dmv , S0
118
103
else :
119
- return 0 , 0 , 0 , 0 , 0
104
+ return Dpar1 , Fmv , Dmv
120
105
121
106
122
107
0 commit comments