-
Notifications
You must be signed in to change notification settings - Fork 36
Wrapper super ivim #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Wrapper super ivim #107
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
numpy<2 | ||
super-ivim-dc==0.4.0 | ||
nibabel | ||
scipy | ||
torchio | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
from src.wrappers.OsipiBase import OsipiBase | ||
from super_ivim_dc.source.Classsic_ivim_fit import IVIM_fit_sls | ||
import numpy as np | ||
|
||
class TCML_TechnionIIT_SLS(OsipiBase): | ||
""" | ||
TCML_TechnionIIT_lsqBOBYQA fitting algorithm by Moti Freiman and Noam Korngut, TechnionIIT | ||
""" | ||
|
||
# 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 = "Moti Freiman and Noam Korngut, TechnIIT" | ||
id_algorithm_type = "Bi-exponential fit, segmented fitting" | ||
id_return_parameters = "f, D*, D, S0" | ||
id_units = "seconds per milli metre squared or milliseconds per micro metre squared" | ||
|
||
# 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 | ||
accepted_dimensions = 1 # Not sure how to define this for the number of accepted dimensions. Perhaps like the thresholds, at least and at most? | ||
|
||
|
||
# Supported inputs in the standardized class | ||
supported_bounds = True | ||
supported_initial_guess = True | ||
supported_thresholds = True | ||
|
||
def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=None, fitS0=True): | ||
""" | ||
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(TCML_TechnionIIT_SLS, self).__init__(bvalues=bvalues, bounds=bounds, initial_guess=initial_guess) | ||
self.fit_least_squares = IVIM_fit_sls | ||
self.fitS0=fitS0 | ||
self.initialize(bounds, initial_guess, fitS0,thresholds) | ||
|
||
def initialize(self, bounds, initial_guess, fitS0,thresholds): | ||
if bounds is None: | ||
print('warning, no bounds were defined, so default bounds are used of ([0.0003, 0.001, 0.009, 0],[0.008, 0.5,0.04, 3])') | ||
self.bounds = ([0.0003, 0.001, 0.009, 0],[0.008, 0.5,0.04, 3]) | ||
else: | ||
bounds=bounds | ||
self.bounds = bounds | ||
if initial_guess is None: | ||
print('warning, no initial guesses were defined, so default bounds are used of [0.001, 0.1, 0.01, 1]') | ||
self.initial_guess = [0.001, 0.1, 0.01, 1] # D, Dp, f, S0 | ||
else: | ||
self.initial_guess = initial_guess | ||
self.use_initial_guess = True | ||
self.fitS0=fitS0 | ||
self.use_initial_guess = True | ||
self.use_bounds = True | ||
if thresholds is None: | ||
self.thresholds = 150 | ||
print('warning, no thresholds were defined, so default bounds are used of 150') | ||
else: | ||
self.thresholds = thresholds | ||
|
||
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_ | ||
""" | ||
|
||
bvalues=np.array(bvalues) | ||
bounds=np.array(self.bounds) | ||
bounds=[bounds[0][[0, 2, 1, 3]], bounds[1][[0, 2, 1, 3]]] | ||
initial_guess = np.array(self.initial_guess) | ||
initial_guess = initial_guess[[0, 2, 1, 3]] | ||
|
||
|
||
fit_results = self.fit_least_squares(1 ,np.array(signals)[:,np.newaxis],bvalues, bounds,initial_guess,self.thresholds) | ||
|
||
results = {} | ||
results["D"] = fit_results[0] | ||
results["f"] = fit_results[2] | ||
results["Dp"] = fit_results[1] | ||
|
||
return results |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
from src.wrappers.OsipiBase import OsipiBase | ||
from super_ivim_dc.source.Classsic_ivim_fit import fit_least_squers_BOBYQA | ||
import numpy as np | ||
|
||
class TCML_TechnionIIT_lsqBOBYQA(OsipiBase): | ||
""" | ||
TCML_TechnionIIT_lsqBOBYQA fitting algorithm by Moti Freiman and Noam Korngut, TechnionIIT | ||
""" | ||
|
||
# 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 = "Moti Freiman and Noam Korngut, TechnIIT" | ||
id_algorithm_type = "Bi-exponential fit, BOBYQO" | ||
id_return_parameters = "f, D*, D, S0" | ||
id_units = "seconds per milli metre squared or milliseconds per micro metre squared" | ||
|
||
# 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 | ||
accepted_dimensions = 1 # Not sure how to define this for the number of accepted dimensions. Perhaps like the thresholds, at least and at most? | ||
|
||
|
||
# Supported inputs in the standardized class | ||
supported_bounds = True | ||
supported_initial_guess = True | ||
supported_thresholds = False | ||
|
||
def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=None, fitS0=True): | ||
""" | ||
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(TCML_TechnionIIT_lsqBOBYQA, self).__init__(bvalues=bvalues, bounds=bounds, initial_guess=initial_guess) | ||
self.fit_least_squares = fit_least_squers_BOBYQA | ||
self.fitS0=fitS0 | ||
self.initialize(bounds, initial_guess, fitS0) | ||
|
||
def initialize(self, bounds, initial_guess, fitS0): | ||
if bounds is None: | ||
print('warning, no bounds were defined, so default bounds are used of [0, 0, 0.005, 0.7],[0.005, 1.0, 0.2, 1.3]') | ||
self.bounds = ([0.0003, 0.001, 0.009, 0],[0.01, 0.5,0.04, 3]) | ||
else: | ||
bounds=bounds | ||
self.bounds = bounds | ||
if initial_guess is None: | ||
print('warning, no initial guesses were defined, so default bounds are used of [0.001, 0.001, 0.01, 1]') | ||
self.initial_guess = [0.001, 0.1, 0.01, 1] # D, Dp, f, S0 | ||
else: | ||
self.initial_guess = initial_guess | ||
self.use_initial_guess = True | ||
self.fitS0=fitS0 | ||
self.use_initial_guess = True | ||
self.use_bounds = True | ||
|
||
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_ | ||
""" | ||
|
||
bvalues=np.array(bvalues) | ||
bounds=np.array(self.bounds) | ||
bounds=[bounds[0][[0, 2, 1, 3]], bounds[1][[0, 2, 1, 3]]] | ||
initial_guess = np.array(self.initial_guess) | ||
initial_guess = initial_guess[[0, 2, 1, 3]] | ||
|
||
fit_results = self.fit_least_squares(1 ,bvalues, np.array(signals)[:,np.newaxis], bounds, initial_guess) | ||
|
||
results = {} | ||
results["D"] = fit_results[0] | ||
results["f"] = fit_results[2] | ||
results["Dp"] = fit_results[1] | ||
|
||
return results |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from src.wrappers.OsipiBase import OsipiBase | ||
from super_ivim_dc.source.Classsic_ivim_fit import fit_least_squares_lm | ||
import numpy as np | ||
|
||
class TCML_TechnionIIT_lsqlm(OsipiBase): | ||
""" | ||
TCML_TechnionIIT_lsqlm fitting algorithm by Moti Freiman and Noam Korngut, TechnionIIT | ||
""" | ||
|
||
# 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 = "Moti Freiman and Noam Korngut, TechnIIT" | ||
id_algorithm_type = "Bi-exponential fit" | ||
id_return_parameters = "f, D*, D, S0" | ||
id_units = "seconds per milli metre squared or milliseconds per micro metre squared" | ||
|
||
# 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 = False # Bounds may not be required but are optional | ||
required_initial_guess = False | ||
required_initial_guess_optional = True | ||
accepted_dimensions = 1 # Not sure how to define this for the number of accepted dimensions. Perhaps like the thresholds, at least and at most? | ||
|
||
|
||
# Supported inputs in the standardized class | ||
supported_bounds = False | ||
supported_initial_guess = True | ||
supported_thresholds = False | ||
|
||
def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=None, fitS0=True): | ||
""" | ||
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(TCML_TechnionIIT_lsqlm, self).__init__(bvalues=bvalues, bounds=bounds, initial_guess=initial_guess) | ||
self.fit_least_squares = fit_least_squares_lm | ||
self.fitS0=fitS0 | ||
self.initialize(bounds, initial_guess, fitS0) | ||
|
||
def initialize(self, bounds, initial_guess, fitS0): | ||
if initial_guess is None: | ||
print('warning, no initial guesses were defined, so default bounds are used of [0.001, 0.1, 0.01, 1]') | ||
self.initial_guess = [0.001, 0.1, 0.01, 1] | ||
else: | ||
self.initial_guess = initial_guess | ||
self.use_initial_guess = True | ||
self.fitS0=fitS0 | ||
self.use_initial_guess = True | ||
self.use_bounds = False | ||
|
||
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_ | ||
""" | ||
|
||
bvalues=np.array(bvalues) | ||
initial_guess = np.array(self.initial_guess) | ||
initial_guess = initial_guess[[0, 2, 1, 3]] | ||
fit_results = self.fit_least_squares(1 ,bvalues, np.array(signals)[:,np.newaxis], initial_guess) | ||
|
||
results = {} | ||
results["D"] = fit_results[0] | ||
results["f"] = fit_results[2] | ||
results["Dp"] = fit_results[1] | ||
|
||
return self.D_and_Ds_swap(results) | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
from src.wrappers.OsipiBase import OsipiBase | ||
from super_ivim_dc.source.Classsic_ivim_fit import fit_least_squares_trf | ||
import numpy as np | ||
|
||
class TCML_TechnionIIT_lsqtrf(OsipiBase): | ||
""" | ||
TCML_TechnionIIT_lsqlm fitting algorithm by Moti Freiman and Noam Korngut, TechnionIIT | ||
""" | ||
|
||
# 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 = "Moti Freiman and Noam Korngut, TechnIIT" | ||
id_algorithm_type = "Bi-exponential fit, Trust Region Reflective algorithm" | ||
id_return_parameters = "f, D*, D, S0" | ||
id_units = "seconds per milli metre squared or milliseconds per micro metre squared" | ||
|
||
# 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 | ||
accepted_dimensions = 1 # Not sure how to define this for the number of accepted dimensions. Perhaps like the thresholds, at least and at most? | ||
|
||
|
||
# Supported inputs in the standardized class | ||
supported_bounds = True | ||
supported_initial_guess = True | ||
supported_thresholds = False | ||
|
||
def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=None, fitS0=True): | ||
""" | ||
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(TCML_TechnionIIT_lsqtrf, self).__init__(bvalues=bvalues, bounds=bounds, initial_guess=initial_guess) | ||
self.fit_least_squares = fit_least_squares_trf | ||
self.fitS0=fitS0 | ||
self.initialize(bounds, initial_guess, fitS0) | ||
|
||
def initialize(self, bounds, initial_guess, fitS0): | ||
if bounds is None: | ||
print('warning, no bounds were defined, so default bounds are used of ([0.0003, 0.001, 0.009, 0],[0.008, 0.5,0.04, 3])') | ||
self.bounds = ([0.0003, 0.001, 0.009, 0],[0.008, 0.5,0.04, 3]) | ||
else: | ||
bounds=bounds | ||
self.bounds = bounds | ||
if initial_guess is None: | ||
print('warning, no initial guesses were defined, so default bounds are used of [0.001, 0.1, 0.01, 1]') | ||
self.initial_guess = [0.001, 0.1, 0.01, 1] # D, Dp, f, S0 | ||
else: | ||
self.initial_guess = initial_guess | ||
self.use_initial_guess = True | ||
self.fitS0=fitS0 | ||
self.use_initial_guess = True | ||
self.use_bounds = True | ||
|
||
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_ | ||
""" | ||
|
||
bvalues=np.array(bvalues) | ||
bounds=np.array(self.bounds) | ||
bounds=[bounds[0][[0, 2, 1, 3]], bounds[1][[0, 2, 1, 3]]] | ||
initial_guess = np.array(self.initial_guess) | ||
initial_guess = initial_guess[[0, 2, 1, 3]] | ||
fit_results = self.fit_least_squares(1 ,bvalues, np.array(signals)[:,np.newaxis], bounds,initial_guess) | ||
|
||
results = {} | ||
results["D"] = fit_results[0] | ||
results["f"] = fit_results[2] | ||
results["Dp"] = fit_results[1] | ||
|
||
return results |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
{ | ||
"algorithms": [ | ||
"TCML_TechnionIIT_lsqlm", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason to omit the other 2? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the other two algorithms fail within the package itself. One refers to a variable that is not initiated. The other has the bounds not properly implemented. As the code is in a package, we cannot modify it. I've asked the authors to take a look. |
||
"TCML_TechnionIIT_lsqtrf", | ||
"ASD_MemorialSloanKettering_QAMPER_IVIM", | ||
"ETP_SRI_LinearFitting", | ||
"IAR_LU_biexp", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to just do it here and not generally in the wrapper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I think for bounded fits it is less of an issue. But it will not do any harm. But I will move it to the general wrapper indeed.