-
Notifications
You must be signed in to change notification settings - Fork 43
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 all commits
f509b5e
542a272
38a2e72
91ead9d
3cbd154
e550f80
4739089
953e872
d49d63f
04058d1
a2d8a22
1dd548e
e399f31
e20a8e2
f05032b
7e58f2f
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 |
|---|---|---|
|
|
@@ -98,6 +98,8 @@ def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=Non | |
| self.thresholds = np.asarray(thresholds) if thresholds is not None else None | ||
| self.bounds = np.asarray(bounds) if bounds is not None else None | ||
| self.initial_guess = np.asarray(initial_guess) if initial_guess is not None else None | ||
| self.required_bounds_optional = getattr(self, "required_bounds_optional", True) | ||
| self.required_initial_guess_optional = getattr(self, "required_initial_guess_optional", True) | ||
| self.use_bounds = True | ||
| self.use_initial_guess = True | ||
| self.deep_learning = False | ||
|
|
@@ -180,7 +182,9 @@ def osipi_fit(self, data, bvalues=None, njobs=1, **kwargs): | |
| >>> f_map = results['f'] | ||
| >>> D_map = results['D'] | ||
| """ | ||
|
|
||
| self.data = np.asarray(data) | ||
| self.osipi_validate_inputs() | ||
|
|
||
| # 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 | ||
|
|
@@ -321,6 +325,9 @@ def osipi_fit_full_volume(self, data, bvalues=None, **kwargs): | |
| if results is False: | ||
| print("Full-volume fitting not supported.") | ||
| """ | ||
|
|
||
| self.data = np.asarray(data) | ||
| self.osipi_validate_inputs() | ||
|
|
||
| try: | ||
| use_bvalues = bvalues if bvalues is not None else self.bvalues | ||
|
|
@@ -400,68 +407,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_accepts_dimension(self.data.ndim) | ||
| self.osipi_check_required_bvalues() | ||
| self.osipi_check_required_thresholds() | ||
| self.osipi_check_required_bounds() | ||
| self.osipi_check_required_initial_guess() | ||
|
|
||
| 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] | ||
| return True | ||
| """Check if the spatial dimensions (excluding b-values) are supported.""" | ||
| spatial_dim = dim - 1 # Exclude last axis (b-values) | ||
| min_dim, max_dim = self.osipi_accepted_dimensions() | ||
| if not (min_dim <= spatial_dim <= max_dim): | ||
| raise ValueError( | ||
| f"Spatial dimensions {spatial_dim}D not supported. " | ||
| f"Requires {min_dim}-{max_dim}D." | ||
| ) | ||
|
|
||
| def osipi_check_required_bvalues(self): | ||
|
Collaborator
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 | ||
| 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") | ||
|
|
||
| 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 | ||
| return True | ||
|
|
||
| if not hasattr(self, "required_thresholds"): | ||
|
Collaborator
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. |
||
| return | ||
| if self.thresholds is None: | ||
| raise ValueError("thresholds are required but not provided") | ||
| min_t, max_t = self.required_thresholds | ||
| num_thresholds = len(self.thresholds) if hasattr(self.thresholds, '__len__') else 1 | ||
| if num_thresholds < min_t or num_thresholds > max_t: | ||
| raise ValueError(f"Number of thresholds should be between {min_t} and {max_t} but {num_thresholds} were provided") | ||
|
|
||
| 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 | ||
| return True | ||
| if self.required_bounds_optional is False and self.bounds is None: | ||
| raise ValueError("bounds are required but not provided") | ||
|
|
||
| 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 | ||
| return True | ||
|
|
||
|
|
||
| def osipi_check_required_bvalues(self): | ||
| """Minimum number of b-values required""" | ||
| pass | ||
| if self.required_initial_guess_optional is False and self.initial_guess is None: | ||
| raise ValueError("initial guess are required but not provided") | ||
|
|
||
| def osipi_author(self): | ||
| """Author identification""" | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.