-
Notifications
You must be signed in to change notification settings - Fork 36
Implement checks for fulfilment of algorithm requirements in the OsipiBase class #96
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?
Changes from 7 commits
f509b5e
542a272
38a2e72
91ead9d
3cbd154
e550f80
4739089
953e872
d49d63f
04058d1
a2d8a22
1dd548e
e399f31
e20a8e2
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 |
---|---|---|
|
@@ -16,6 +16,10 @@ def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=Non | |
self.initial_guess = np.asarray(initial_guess) if initial_guess is not None else None | ||
self.use_bounds = True | ||
self.use_initial_guess = True | ||
|
||
# Validate the inputs | ||
self.osipi_validate_inputs() | ||
harshithasudhakar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# If the user inputs an algorithm to OsipiBase, it is intereprete as initiating | ||
# an algorithm object with that name. | ||
if algorithm: | ||
|
@@ -53,7 +57,8 @@ def osipi_fit(self, data, bvalues=None, **kwargs): | |
"""Fits the data with the bvalues | ||
Returns [S0, f, Dstar, D] | ||
""" | ||
|
||
self.osipi_validate_inputs() | ||
harshithasudhakar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# We should first check whether the attributes in the __init__ are not None | ||
# Then check if they are input here, if they are, these should overwrite the attributes | ||
use_bvalues = bvalues if bvalues is not None else self.bvalues | ||
|
@@ -123,6 +128,8 @@ def osipi_fit_full_volume(self, data, bvalues=None, **kwargs): | |
Returns: | ||
results (dict): Dict with key each containing an array which is a parametric map. | ||
""" | ||
|
||
self.osipi_validate_inputs() | ||
|
||
try: | ||
use_bvalues = bvalues if bvalues is not None else self.bvalues | ||
|
@@ -201,69 +208,63 @@ def osipi_print_requirements(self): | |
else: | ||
print(f"Initial guess required: {self.required_initial_guess} and is not optional") | ||
|
||
def osipi_validate_inputs(self): | ||
"""Validates the inputs of the algorithm.""" | ||
self.osipi_check_required_bvalues() | ||
self.osipi_check_required_thresholds() | ||
self.osipi_check_required_bounds() | ||
self.osipi_check_required_initial_guess() | ||
self.osipi_accepts_dimension(self.data.ndim) | ||
|
||
def osipi_accepted_dimensions(self): | ||
"""The array of accepted dimensions | ||
e.g. | ||
(1D, 2D, 3D, 4D, 5D, 6D) | ||
(True, True, False, False, False, False) | ||
""" | ||
|
||
#return (False,) * 6 | ||
return True | ||
return getattr(self, 'accepted_dimensions', (1, 3)) | ||
|
||
def osipi_accepts_dimension(self, dim): | ||
"""Query if the selection dimension is fittable""" | ||
|
||
#accepted = self.accepted_dimensions() | ||
#if dim < 0 or dim > len(accepted): | ||
#return False | ||
#return accepted[dim] | ||
min_dim, max_dim = self.osipi_accepted_dimensions() | ||
if not (min_dim <= dim <= max_dim): | ||
raise ValueError(f"Dimension {dim}D not supported. Requires {min_dim}-{max_dim}D spatial data") | ||
return True | ||
harshithasudhakar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def osipi_check_required_bvalues(self): | ||
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. b-values is another story. Here we cannot give a "default" |
||
"""Checks if the input bvalues fulfil the algorithm requirements""" | ||
|
||
#if self.bvalues.size < self.required_bvalues: | ||
#print("Conformance error: Number of b-values.") | ||
#return False | ||
#else: | ||
#return True | ||
if not hasattr(self, "required_bvalues"): | ||
raise AttributeError("required_bvalues not defined for this algorithm") | ||
if self.bvalues is None: | ||
raise ValueError("bvalues are not provided") | ||
if len(self.bvalues) < self.required_bvalues: | ||
raise ValueError(f"Atleast {self.required_bvalues} are required, but only {len(self.bvalues)} were provided") | ||
return True | ||
|
||
def osipi_check_required_thresholds(self): | ||
"""Checks if the number of input thresholds fulfil the algorithm requirements""" | ||
|
||
#if (len(self.thresholds) < self.required_thresholds[0]) or (len(self.thresholds) > self.required_thresholds[1]): | ||
#print("Conformance error: Number of thresholds.") | ||
#return False | ||
#else: | ||
#return True | ||
if not hasattr(self, "required_thresholds"): | ||
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. I am wondering whether for some attributes, like "required_thresholds", we should add "default" values when tests fail. Like, 200 would be an okay value for most body applications. Then we can do with a warning stating that the default value is used, instead. |
||
raise AttributeError("required_thresholds is not defined for this algorithm") | ||
if self.thresholds is None: | ||
raise ValueError("thresholds are not provided") | ||
if len(self.thresholds) < self.required_thresholds[0] and len(self.thresholds) > self.required_thresholds[1]: | ||
raise ValueError(f"Thresholds should be between {self.required_thresholds[0]} and {self.required_thresholds[1]} but {len(self.thresholds)} were provided") | ||
return True | ||
|
||
def osipi_check_required_bounds(self): | ||
"""Checks if input bounds fulfil the algorithm requirements""" | ||
#if self.required_bounds is True and self.bounds is None: | ||
#print("Conformance error: Bounds.") | ||
#return False | ||
#else: | ||
#return True | ||
if self.required_bounds is False and self.bounds is None: | ||
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. Same for bounds. I think if no bounds are given, but bounds will be used, then we should give some default bounds. |
||
raise ValueError("bounds are required but not provided") | ||
return True | ||
|
||
def osipi_check_required_initial_guess(self): | ||
"""Checks if input initial guess fulfil the algorithm requirements""" | ||
|
||
#if self.required_initial_guess is True and self.initial_guess is None: | ||
#print("Conformance error: Initial guess") | ||
#return False | ||
#else: | ||
#return True | ||
if self.required_initial_guess is False and self.initial_guess is None: | ||
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. same for initial guess :) |
||
raise ValueError("initial_guess are required but not provided") | ||
return True | ||
|
||
|
||
def osipi_check_required_bvalues(): | ||
"""Minimum number of b-values required""" | ||
pass | ||
|
||
def osipi_author(): | ||
"""Author identification""" | ||
return '' | ||
|
Uh oh!
There was an error while loading. Please reload this page.