1
+ from src .wrappers .OsipiBase import OsipiBase
2
+ import numpy as np
3
+ import matlab .engine
4
+
5
+ class ASD_MemorialSloanKettering_QAMPER_IVIM (OsipiBase ):
6
+ """
7
+ Bi-exponential fitting algorithm by Oliver Gurney-Champion, Amsterdam UMC
8
+ """
9
+
10
+ # I'm thinking that we define default attributes for each submission like this
11
+ # And in __init__, we can call the OsipiBase control functions to check whether
12
+ # the user inputs fulfil the requirements
13
+
14
+ # Some basic stuff that identifies the algorithm
15
+ id_author = "LoCastro, Dr. Ramesh Paudyal, Dr. Amita Shukla-Dave"
16
+ id_algorithm_type = "Bi-exponential fit"
17
+ id_return_parameters = "f, D*, D, S0"
18
+ id_units = "seconds per milli metre squared or milliseconds per micro metre squared"
19
+
20
+ # Algorithm requirements
21
+ required_bvalues = 4
22
+ required_thresholds = [0 ,
23
+ 0 ] # Interval from "at least" to "at most", in case submissions allow a custom number of thresholds
24
+ required_bounds = False
25
+ required_bounds_optional = True # Bounds may not be required but are optional
26
+ required_initial_guess = False
27
+ required_initial_guess_optional = True
28
+ accepted_dimensions = 1 # Not sure how to define this for the number of accepted dimensions. Perhaps like the thresholds, at least and at most?
29
+
30
+
31
+ # Supported inputs in the standardized class
32
+ supported_bounds = True
33
+ supported_initial_guess = True
34
+ supported_thresholds = False
35
+
36
+ def __init__ (self , bvalues = None , thresholds = None , bounds = None , initial_guess = None ):
37
+ """
38
+ Everything this algorithm requires should be implemented here.
39
+ Number of segmentation thresholds, bounds, etc.
40
+
41
+ Our OsipiBase object could contain functions that compare the inputs with
42
+ the requirements.
43
+ """
44
+ #super(OGC_AmsterdamUMC_biexp, self).__init__(bvalues, bounds, initial_guess, fitS0)
45
+ super (ASD_MemorialSloanKettering_QAMPER_IVIM , self ).__init__ (bvalues = bvalues , bounds = bounds , initial_guess = initial_guess )
46
+ self .initialize (bounds , initial_guess )
47
+
48
+ def algorithm (self ,dwi_arr , bval_arr , LB0 , UB0 , x0in ):
49
+ eng = matlab .engine .start_matlab ()
50
+ dwi_arr = matlab .double (dwi_arr .tolist ())
51
+ bval_arr = matlab .double (bval_arr .tolist ())
52
+ LB0 = matlab .double (LB0 .tolist ())
53
+ UB0 = matlab .double (UB0 .tolist ())
54
+ x0in = matlab .double (x0in .tolist ())
55
+ f_arr , D_arr , Dx_arr , s0_arr , fitted_dwi_arr , RSS , rms_val , chi , AIC , BIC , R_sq = eng .IVIM_standard_bcin (
56
+ dwi_arr , bval_arr , 0.0 , LB0 , UB0 , x0in , False , 0 , 0 )
57
+ eng .quit ()
58
+ return D_arr , f_arr , Dx_arr , s0_arr
59
+
60
+ def initialize (self , bounds , initial_guess ):
61
+ if bounds is None :
62
+ print ('warning, no bounds were defined, so algorithm-specific default bounds are used' )
63
+ self .bounds = ([1e-6 , 0 , 1e-6 , 0 ],[0.003 , 1.0 , 5e-2 , 5 ])
64
+ else :
65
+ self .bounds = bounds
66
+ if initial_guess is None :
67
+ print ('warning, no initial guesses were defined, so algorithm-specific default initial guess is used' )
68
+ self .initial_guess = [0.001 , 0.001 , 0.2 , 1 ]
69
+ else :
70
+ self .initial_guess = initial_guess
71
+ self .use_initial_guess = True
72
+ self .use_initial_guess = True
73
+ self .use_bounds = True
74
+
75
+ def ivim_fit (self , signals , bvalues , ** kwargs ):
76
+ """Perform the IVIM fit
77
+
78
+ Args:
79
+ signals (array-like)
80
+ bvalues (array-like, optional): b-values for the signals. If None, self.bvalues will be used. Default is None.
81
+
82
+ Returns:
83
+ _type_: _description_
84
+ """
85
+
86
+ bvalues = np .array (bvalues )
87
+ LB = np .array (self .bounds [0 ])
88
+ UB = np .array (self .bounds [1 ])
89
+
90
+ fit_results = self .algorithm (np .array (signals ), bvalues , LB , UB , np .array (self .initial_guess ))
91
+
92
+ results = {}
93
+ results ["D" ] = fit_results [0 ]
94
+ results ["f" ] = fit_results [1 ]
95
+ results ["Dp" ] = fit_results [2 ]
96
+
97
+ return results
0 commit comments