-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathIAR_LU_modified_mix.py
More file actions
108 lines (82 loc) · 4.23 KB
/
IAR_LU_modified_mix.py
File metadata and controls
108 lines (82 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import numpy as np
from dipy.core.gradients import gradient_table
from src.wrappers.OsipiBase import OsipiBase
from src.original.IAR_LundUniversity.ivim_fit_method_modified_mix import IvimModelVP
class IAR_LU_modified_mix(OsipiBase):
"""
Bi-exponential fitting algorithm by Ivan A. Rashid, Lund University
"""
# I'm thinking that we define default attributes for each submission like this
# And in __init__, we can call the OsipiBase control functions to check whether
# the user inputs fulfil the requirements
# Some basic stuff that identifies the algorithm
id_author = "Ivan A. Rashid, LU"
id_algorithm_type = "Bi-exponential fit"
id_return_parameters = "f, D*, D"
id_units = "seconds per milli metre squared or milliseconds per micro metre squared"
id_ref = "https://doi.org/10.1038/srep38927"
# Algorithm requirements
required_bvalues = 4
required_thresholds = [0,0] # Interval from "at least" to "at most", in case submissions allow a custom number of thresholds
required_bounds = False
required_bounds_optional = True # Bounds may not be required but are optional
required_initial_guess = False
required_initial_guess_optional = True
# Supported inputs in the standardized class
supported_bounds = True
supported_initial_guess = False
supported_thresholds = False
supported_dimensions = 1
supported_priors = False
def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=None, weighting=None, stats=False):
"""
Everything this algorithm requires should be implemented here.
Number of segmentation thresholds, bounds, etc.
Our OsipiBase object could contain functions that compare the inputs with
the requirements.
"""
super(IAR_LU_modified_mix, self).__init__(bvalues, thresholds, bounds, initial_guess)
self.use_bounds = {"f": False, "Dp": False, "D": False} # This algorithm performs intermediate steps that generates initial guesses outside very constrainted bounds
self.use_initial_guess = {"f": False, "Dp": False, "D": False} # This algorithm does not use initial guesses
# Additional options
self.stochastic = True
# Check the inputs
# Initialize the algorithm
if self.bvalues is not None:
bvec = np.zeros((self.bvalues.size, 3))
bvec[:,2] = 1
gtab = gradient_table(self.bvalues, bvec, b0_threshold=0)
bounds = [[self.bounds["f"][0], self.bounds["Dp"][0]*1000, self.bounds["D"][0]*1000],
[self.bounds["f"][1], self.bounds["Dp"][1]*1000, self.bounds["D"][1]*1000]]
self.IAR_algorithm = IvimModelVP(gtab, bounds=bounds, rescale_units=False, rescale_results_to_mm2_s=True)
else:
self.IAR_algorithm = None
def ivim_fit(self, signals, bvalues, **kwargs):
"""Perform the IVIM fit
Args:
signals (array-like)
bvalues (array-like, optional): b-values for the signals. If None, self.bvalues will be used. Default is None.
Returns:
_type_: _description_
"""
bounds = [[self.bounds["f"][0], self.bounds["Dp"][0]*1000, self.bounds["D"][0]*1000],
[self.bounds["f"][1], self.bounds["Dp"][1]*1000, self.bounds["D"][1]*1000]]
if self.IAR_algorithm is None:
if bvalues is None:
bvalues = self.bvalues
else:
bvalues = np.asarray(bvalues)
bvec = np.zeros((bvalues.size, 3))
bvec[:,2] = 1
gtab = gradient_table(bvalues, bvec, b0_threshold=0)
self.IAR_algorithm = IvimModelVP(gtab, bounds=bounds, rescale_results_to_mm2_s=True)
fit_results = self.IAR_algorithm.fit(signals)
#f = fit_results.model_params[1]
#Dstar = fit_results.model_params[2]
#D = fit_results.model_params[3]
results = {}
results["f"] = fit_results.model_params[1]
results["Dp"] = fit_results.model_params[2]
results["D"] = fit_results.model_params[3]
results = self.D_and_Ds_swap(results)
return results