Skip to content

Standardized pv mumc triexp #97

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/original/PV_MUMC/triexp_fitting_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ def monofit(bvalues, Dpar, Fp):
Dpar1 = params[0]
if IR:
if not fitS0:
bounds = ([bounds[0][1] , bounds[0][2] , bounds[0][3] , bounds[0][4] , bounds[0][5] ],
newbounds = ([bounds[0][1] , bounds[0][2] , bounds[0][3] , bounds[0][4] , bounds[0][5] ],
[Dpar1 , bounds[1][2] , bounds[1][3] , bounds[1][4] , bounds[1][5] ])
params, _ = curve_fit(tri_expN_noS0_IR, bvalues, dw_data, p0=[Dpar1, 0.0, (bounds[0][3]+bounds[1][3])/2, 0.05, (bounds[0][5]+bounds[1][5])/2], bounds=bounds)
params, _ = curve_fit(tri_expN_noS0_IR, bvalues, dw_data, p0=[Dpar1, 0.0, (bounds[0][3]+bounds[1][3])/2, 0.05, (bounds[0][5]+bounds[1][5])/2], bounds=newbounds)
Dpar, Fint, Dint, Fmv, Dmv = params[0], params[1], params[2], params[3], params[4]
#when the fraction of a compartment equals zero (or very very small), the corresponding diffusivity is non-existing (=NaN)

Expand All @@ -104,9 +104,9 @@ def monofit(bvalues, Dpar, Fp):

else:
if not fitS0:
bounds = ([bounds[0][1] , bounds[0][2] , bounds[0][3] , bounds[0][4] , bounds[0][5] ],
newbounds = ([bounds[0][1] , bounds[0][2] , bounds[0][3] , bounds[0][4] , bounds[0][5] ],
[Dpar1 , bounds[1][2] , bounds[1][3] , bounds[1][4] , bounds[1][5] ])
params, _ = curve_fit(tri_expN_noS0, bvalues, dw_data, p0=[Dpar1, 0.0, (bounds[0][3]+bounds[1][3])/2, 0.05, (bounds[0][5]+bounds[1][5])/2], bounds=bounds)
params, _ = curve_fit(tri_expN_noS0, bvalues, dw_data, p0=[Dpar1, 0.0, (bounds[0][3]+bounds[1][3])/2, 0.05, (bounds[0][5]+bounds[1][5])/2], bounds=newbounds)
Dpar, Fint, Dint, Fmv, Dmv = params[0], params[1], params[2], params[3], params[4]
#when the fraction of a compartment equals zero (or very very small), the corresponding diffusivity is non-existing (=NaN)

Expand Down
53 changes: 53 additions & 0 deletions src/standardized wip/PV_MUMC_triexp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import numpy as np
from src.wrappers.OsipiBase import OsipiBase
from src.original.PV_MUMC.triexp_fitting_algorithms import fit_least_squares_tri_exp, fit_NNLS


class PV_MUMC_triexp(OsipiBase):
"""
Tri-exponential least squares fitting algorithm by Paulien Voorter, Maastricht University
"""

# Some basic stuff that identifies the algorithm
id_author = "Paulien Voorter MUMC"
id_algorithm_type = "Tri-exponential fit"
id_return_parameters = "Dpar, Fint, Dint, Fmv, Dmv"
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?

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(PV_MUMC_triexp, self).__init__(bvalues, None, bounds, None)
self.PV_algorithm = fit_least_squares_tri_exp


def ivim_fit(self, signals, bvalues=None):
"""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_
"""


fit_results = self.PV_algorithm(bvalues, signals)
Dpar, Fint, Dint, Fmv, Dmv = fit_results

return Dpar, Fint, Dint, Fmv, Dmv
58 changes: 58 additions & 0 deletions src/standardized/PV_MUMC_triexp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import numpy as np
from src.wrappers.OsipiBase import OsipiBase
from src.original.PV_MUMC.triexp_fitting_algorithms import fit_least_squares_tri_exp, fit_NNLS


class PV_MUMC_triexp(OsipiBase):
"""
Tri-exponential least squares fitting algorithm by Paulien Voorter, Maastricht University
"""

# Some basic stuff that identifies the algorithm
id_author = "Paulien Voorter MUMC"
id_algorithm_type = "Tri-exponential fit"
id_return_parameters = "Dpar, Fint, Dint, Fmv, Dmv"
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
result_keys = ["Dpar", "Fint", "Dint", "Fmv", "Dmv"]
accepted_dimensions = 1 # Not sure how to define this for the number of accepted dimensions. Perhaps like the thresholds, at least and at most?

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(PV_MUMC_triexp, self).__init__(bvalues, None, bounds, None)
self.PV_algorithm = fit_least_squares_tri_exp


def ivim_fit(self, signals, bvalues=None):
"""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_
"""

fit_results = self.PV_algorithm(bvalues, signals)
results = {}
results["Dpar"] = fit_results[0]
results["Fint"] = fit_results[1]
results["Dint"] = fit_results[2]
results["Fmv"] = fit_results[3]
results["Dmv"] = fit_results[4]

return results
19 changes: 19 additions & 0 deletions tests/IVIMmodels/unit_tests/algorithms.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"OGC_AmsterdamUMC_biexp_segmented",
"OGC_AmsterdamUMC_biexp",
"PV_MUMC_biexp",
"PV_MUMC_triexp",
"PvH_KB_NKI_IVIMfit",
"OJ_GU_seg"
],
Expand Down Expand Up @@ -163,5 +164,23 @@
"Dp": 1e-1
}
}
},
"PV_MUMC_triexp": {
"tolerances": {
"rtol": {
"Dpar": 5,
"Fint": 5,
"Dint": 25,
"Fmv": 25,
"Dmv": 25
},
"atol": {
"Dpar": 1e-2,
"Fint": 1e-2,
"Dint": 1e-1,
"Fmv": 1e-1,
"Dmv": 1e-1
}
}
}
}
Loading