@@ -124,29 +124,30 @@ def fit_segmented(bvalues, dw_data, bounds=([0, 0, 0.005],[0.005, 0.7, 0.2]), cu
124124 :return Dp: Fitted Dp
125125 :return S0: Fitted S0
126126 """
127- p0 = [p0 [0 ] * 1000 , p0 [1 ] * 10 , p0 [2 ] * 10 , p0 [3 ]]
128127 try :
129128 # determine high b-values and data for D
129+ dw_data = dw_data / np .mean (dw_data [bvalues == 0 ])
130130 high_b = bvalues [bvalues >= cutoff ]
131131 high_dw_data = dw_data [bvalues >= cutoff ]
132132 # correct the bounds. Note that S0 bounds determine the max and min of f
133- bounds1 = ([bounds [0 ][0 ] * 1000. , 0.7 - bounds [1 ][1 ]], [bounds [1 ][0 ] * 1000. , 1.3 - bounds [0 ][
134- 1 ]]) # By bounding S0 like this, we effectively insert the boundaries of f
135- # fit for S0' and D
136- params , _ = curve_fit (lambda b , Dt , int : int * np .exp (- b * Dt / 1000 ), high_b , high_dw_data ,
137- p0 = (p0 [0 ], p0 [3 ]- p0 [1 ]/ 10 ),
133+ bounds1 = ([bounds [0 ][0 ], 0 ], [bounds [1 ][0 ], 10000000000 ])
134+ params , _ = curve_fit (lambda b , Dt , int : int * np .exp (- b * Dt ), high_b , high_dw_data ,
135+ p0 = (p0 [0 ], p0 [3 ]- p0 [1 ]),
138136 bounds = bounds1 )
139- Dt , Fp = params [0 ] / 1000 , 1 - params [1 ]
137+ Dt , Fp = 0 + params [0 ], 1 - params [1 ]
138+ if Fp < bounds [0 ][1 ] : Fp = bounds [0 ][1 ]
139+ if Fp > bounds [1 ][1 ] : Fp = bounds [1 ][1 ]
140+
140141 # remove the diffusion part to only keep the pseudo-diffusion
141142 dw_data_remaining = dw_data - (1 - Fp ) * np .exp (- bvalues * Dt )
142- bounds2 = (bounds [0 ][2 ]* 10 , bounds [1 ][2 ]* 10 )
143+ bounds2 = (bounds [0 ][2 ], bounds [1 ][2 ])
143144 # fit for D*
144145 params , _ = curve_fit (lambda b , Dp : Fp * np .exp (- b * Dp ), bvalues , dw_data_remaining , p0 = (p0 [2 ]), bounds = bounds2 )
145- Dp = params [0 ]
146- return Dt , Fp , Dp
146+ Dp = 0 + params [0 ]
147+ return Dt , np . float64 ( Fp ) , Dp
147148 except :
148149 # if fit fails, return zeros
149- # print('segnetned fit failed')
150+ # print('segmented fit failed')
150151 return 0. , 0. , 0.
151152
152153
@@ -235,17 +236,17 @@ def fit_least_squares(bvalues, dw_data, S0_output=False, fitS0=True,
235236 try :
236237 if not fitS0 :
237238 # bounds are rescaled such that each parameter changes at roughly the same rate to help fitting.
238- bounds = ([bounds [0 ][0 ] * 1000 , bounds [0 ][1 ] * 10 , bounds [0 ][2 ] * 10 ],
239+ bounds2 = ([bounds [0 ][0 ] * 1000 , bounds [0 ][1 ] * 10 , bounds [0 ][2 ] * 10 ],
239240 [bounds [1 ][0 ] * 1000 , bounds [1 ][1 ] * 10 , bounds [1 ][2 ] * 10 ])
240241 p0 = [p0 [0 ]* 1000 ,p0 [1 ]* 10 ,p0 [2 ]* 10 ]
241- params , _ = curve_fit (ivimN_noS0 , bvalues , dw_data , p0 = p0 , bounds = bounds )
242+ params , _ = curve_fit (ivimN_noS0 , bvalues , dw_data , p0 = p0 , bounds = bounds2 )
242243 S0 = 1
243244 else :
244245 # bounds are rescaled such that each parameter changes at roughly the same rate to help fitting.
245- bounds = ([bounds [0 ][0 ] * 1000 , bounds [0 ][1 ] * 10 , bounds [0 ][2 ] * 10 , bounds [0 ][3 ]],
246+ bounds2 = ([bounds [0 ][0 ] * 1000 , bounds [0 ][1 ] * 10 , bounds [0 ][2 ] * 10 , bounds [0 ][3 ]],
246247 [bounds [1 ][0 ] * 1000 , bounds [1 ][1 ] * 10 , bounds [1 ][2 ] * 10 , bounds [1 ][3 ]])
247248 p0 = [p0 [0 ]* 1000 ,p0 [1 ]* 10 ,p0 [2 ]* 10 ,p0 [3 ]]
248- params , _ = curve_fit (ivimN , bvalues , dw_data , p0 = p0 , bounds = bounds )
249+ params , _ = curve_fit (ivimN , bvalues , dw_data , p0 = p0 , bounds = bounds2 )
249250 S0 = params [3 ]
250251 # correct for the rescaling of parameters
251252 Dt , Fp , Dp = params [0 ] / 1000 , params [1 ] / 10 , params [2 ] / 10
@@ -261,7 +262,7 @@ def fit_least_squares(bvalues, dw_data, S0_output=False, fitS0=True,
261262 Dt , Fp , Dp = fit_segmented (bvalues , dw_data , bounds = bounds )
262263 return Dt , Fp , Dp , 1
263264 else :
264- return fit_segmented (bvalues , dw_data )
265+ return fit_segmented (bvalues , dw_data , bounds = bounds )
265266
266267
267268def fit_least_squares_array_tri_exp (bvalues , dw_data , S0_output = True , fitS0 = True , njobs = 4 ,
@@ -561,19 +562,19 @@ def neg_log_prior(p):
561562 Dt , Fp , Dp = p [0 ], p [1 ], p [2 ]
562563 # make D*<D very unlikely
563564 if (Dp < Dt ):
564- return 1e3
565+ return 1e10
565566 else :
566567 # determine and return the prior for D, f and D* (and S0)
567568 if len (p ) == 4 :
568- if Dt_range [0 ] < Dt < Dt_range [1 ] and Fp_range [0 ] < Fp < Fp_range [1 ] and Dp_range [0 ] < Dp < Dp_range [1 ]: # and S0_range[0] < S0 < S0_range[1]: << not sure whether this helps. Technically it should be here
569+ if Dt_range [0 ] < Dt < Dt_range [1 ] and Fp_range [0 ] < Fp < Fp_range [1 ] and Dp_range [0 ] < Dp < Dp_range [1 ] and S0_range [0 ] < S0 < S0_range [1 ]: # << not sure whether this helps. Technically it should be here
569570 return 0
570571 else :
571- return 1e3
572+ return 1e10
572573 else :
573574 if Dt_range [0 ] < Dt < Dt_range [1 ] and Fp_range [0 ] < Fp < Fp_range [1 ] and Dp_range [0 ] < Dp < Dp_range [1 ]:
574575 return 0
575576 else :
576- return 1e3
577+ return 1e10
577578
578579 return neg_log_prior
579580
@@ -638,7 +639,7 @@ def parfun(i):
638639 return Dt_pred , Fp_pred , Dp_pred , S0_pred
639640
640641
641- def fit_bayesian (bvalues , dw_data , neg_log_prior , x0 = [0.001 , 0.2 , 0.05 , 1 ], fitS0 = True ):
642+ def fit_bayesian (bvalues , dw_data , neg_log_prior , x0 = [0.001 , 0.2 , 0.05 , 1 ], fitS0 = True , bounds = ([ 0 , 0 , 0 , 0 ],[ 0.005 , 1.5 , 2 , 2.5 ]) ):
642643 '''
643644 This is an implementation of the Bayesian IVIM fit. It returns the Maximum a posterior probability.
644645 The fit is taken from Barbieri et al. which was initially introduced in http://arxiv.org/10.1002/mrm.25765 and
@@ -655,7 +656,7 @@ def fit_bayesian(bvalues, dw_data, neg_log_prior, x0=[0.001, 0.2, 0.05, 1], fitS
655656 '''
656657 try :
657658 # define fit bounds
658- bounds = [(0 , 0.005 ), (0 , 1.5 ), (0 , 2 ), (0 , 2.5 )]
659+ bounds = [(bounds [ 0 ][ 0 ], bounds [ 1 ][ 0 ] ), (bounds [ 0 ][ 1 ], bounds [ 1 ][ 1 ] ), (bounds [ 0 ][ 2 ], bounds [ 1 ][ 2 ] ), (bounds [ 0 ][ 3 ], bounds [ 1 ][ 3 ] )]
659660 # Find the Maximum a posterior probability (MAP) by minimising the negative log of the posterior
660661 if fitS0 :
661662 params = minimize (neg_log_posterior , x0 = x0 , args = (bvalues , dw_data , neg_log_prior ), bounds = bounds )
0 commit comments