Skip to content

Commit f9161f2

Browse files
Matlab installation + adding Amita's code to wrapper
Unit test will fail. Mainly checking whether matlab is called
1 parent 0785232 commit f9161f2

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed

.github/workflows/unit_test.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ jobs:
3030
run: |
3131
python -m pip install --upgrade pip
3232
pip install -r requirements.txt
33+
- name: Check out repository
34+
uses: actions/checkout@v4
35+
- name: Set up MATLAB
36+
uses: matlab-actions/setup-matlab@v2
37+
- name: Run build
38+
uses: matlab-actions/run-build@v2
3339
- name: Test with pytest
3440
run: |
3541
pip install pytest pytest-cov

src/original/ASD_MemorialSloanKettering/MRI-QAMPER_IVIM/IVIM_standard_bcin.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
end
88

99
numVoxels = size(dwi_arr,2);
10+
print(numVoxels)
1011
numBvals = length(bval_arr);
1112

1213
f_lb = 0;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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

tests/IVIMmodels/unit_tests/algorithms.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"algorithms": [
3+
"ASD_MemorialSloanKettering_QAMPER_IVIM",
34
"ETP_SRI_LinearFitting",
45
"IAR_LU_biexp",
56
"IAR_LU_modified_mix",

0 commit comments

Comments
 (0)