@@ -29,10 +29,14 @@ class OsipiBase:
2929 Parameter bounds for constrained optimization. Should be a dict with keys
3030 like "S0", "f", "Dp", "D" and values as [lower, upper] lists or arrays.
3131 E.g. {"S0" : [0.7, 1.3], "f" : [0, 1], "Dp" : [0.005, 0.2], "D" : [0, 0.005]}.
32- initial_guess : dict, optional
33- Initial parameter estimates for the IVIM fit. Should be a dict with keys
34- like "S0", "f", "Dp", "D" and float values.
35- E.g. {"S0" : 1, "f" : 0.1, "Dp" : 0.01, "D" : 0.001}.
32+ initial_guess : dict or str, optional
33+ Initial parameter estimates for the IVIM fit. Can be:
34+ - A dict with keys like "S0", "f", "Dp", "D" and float values.
35+ E.g. {"S0" : 1, "f" : 0.1, "Dp" : 0.01, "D" : 0.001}.
36+ - A string naming a body part (e.g., "brain", "liver", "kidney").
37+ The string is looked up in the body-part defaults table and
38+ replaced with the corresponding dict. If bounds are not provided,
39+ body-part-specific bounds are also applied.
3640 algorithm : str, optional
3741 Name of an algorithm module in ``src/standardized`` to load dynamically.
3842 If supplied, the instance is immediately converted to that algorithm’s
@@ -43,6 +47,14 @@ class OsipiBase:
4347 "Dp":[0.005, 0.2], "D":[0, 0.005]}.
4448 To prevent this, set this bool to False. Default initial guess
4549 {"S0" : 1, "f": 0.1, "Dp": 0.01, "D": 0.001}.
50+ body_part : str, optional
51+ Name of the anatomical region being scanned (e.g., "brain", "liver",
52+ "kidney", "prostate", "pancreas", "head_and_neck", "breast",
53+ "placenta"). When provided, body-part-specific initial guesses,
54+ bounds, and thresholds are used as defaults instead of the generic
55+ ones. User-provided bounds/initial_guess always take priority.
56+ See :mod:`src.wrappers.ivim_body_part_defaults` for available
57+ body parts and their literature-sourced parameter values.
4658 **kwargs
4759 Additional keyword arguments forwarded to the selected algorithm’s
4860 initializer if ``algorithm`` is provided.
@@ -102,7 +114,14 @@ class OsipiBase:
102114 f_map = results["f"]
103115 """
104116
105- def __init__ (self , bvalues = None , thresholds = None , bounds = None , initial_guess = None , algorithm = None , force_default_settings = True , ** kwargs ):
117+ def __init__ (self , bvalues = None , thresholds = None , bounds = None , initial_guess = None , algorithm = None , force_default_settings = True , body_part = None , ** kwargs ):
118+ from src .wrappers .ivim_body_part_defaults import get_body_part_defaults
119+
120+ # If initial_guess is a string, treat it as a body part name
121+ if isinstance (initial_guess , str ):
122+ body_part = initial_guess
123+ initial_guess = None
124+
106125 # Define the attributes as numpy arrays only if they are not None
107126 self .bvalues = np .asarray (bvalues ) if bvalues is not None else None
108127 self .thresholds = np .asarray (thresholds ) if thresholds is not None else None
@@ -113,20 +132,34 @@ def __init__(self, bvalues=None, thresholds=None, bounds=None, initial_guess=Non
113132 self .deep_learning = False
114133 self .supervised = False
115134 self .stochastic = False
135+ self .body_part = body_part # Store for reference
116136
117137 if force_default_settings :
118- if self .bounds is None :
119- 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]' )
120- self .bounds = {"S0" : [0.7 , 1.3 ], "f" : [0 , 1.0 ], "Dp" : [0.005 , 0.2 ], "D" : [0 , 0.005 ]} # These are defined as [lower, upper]
121- self .forced_default_bounds = True
122-
123- if self .initial_guess is None :
124- print ('warning, no initial guesses were defined, so default initial guesses are used of [0.001, 0.001, 0.01, 1]' )
125- self .initial_guess = {"S0" : 1 , "f" : 0.1 , "Dp" : 0.01 , "D" : 0.001 }
126- self .forced_default_initial_guess = True
127-
128- if self .thresholds is None :
129- self .thresholds = np .array ([200 ])
138+ if body_part is not None :
139+ # Use body-part-specific defaults from the literature-sourced lookup table
140+ bp_defaults = get_body_part_defaults (body_part )
141+ if self .bounds is None :
142+ self .bounds = bp_defaults ["bounds" ]
143+ self .forced_default_bounds = True
144+ if self .initial_guess is None :
145+ self .initial_guess = bp_defaults ["initial_guess" ]
146+ self .forced_default_initial_guess = True
147+ if self .thresholds is None :
148+ self .thresholds = np .array (bp_defaults ["thresholds" ])
149+ else :
150+ # Generic defaults (original behavior)
151+ if self .bounds is None :
152+ 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]' )
153+ self .bounds = {"S0" : [0.7 , 1.3 ], "f" : [0 , 1.0 ], "Dp" : [0.005 , 0.2 ], "D" : [0 , 0.005 ]} # These are defined as [lower, upper]
154+ self .forced_default_bounds = True
155+
156+ if self .initial_guess is None :
157+ print ('warning, no initial guesses were defined, so default initial guesses are used of [0.001, 0.001, 0.01, 1]' )
158+ self .initial_guess = {"S0" : 1 , "f" : 0.1 , "Dp" : 0.01 , "D" : 0.001 }
159+ self .forced_default_initial_guess = True
160+
161+ if self .thresholds is None :
162+ self .thresholds = np .array ([200 ])
130163
131164 self .osipi_bounds = self .bounds # Variable that stores the original bounds before they are passed to the algorithm
132165 self .osipi_initial_guess = self .initial_guess # Variable that stores the original initial guesses before they are passed to the algorithm
0 commit comments