Skip to content
Merged
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
17 changes: 13 additions & 4 deletions src/standardized/IVIM_NEToptim.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,17 @@ def initialize(self, bounds, initial_guess, fitS0, traindata, SNR, n):
self.arg=Arg()
print('note that the bounds in the network are soft bounds and implemented by a sigmoid transform. In order for the network to be sensitive over the range, we extend the bounds ny 30%')
if bounds is not None:
self.arg.net_pars.cons_min = np.array([self.bounds["D"][0], self.bounds["f"][0], self.bounds["Dp"][0], self.bounds["S0"][0]])#bounds[0] # Dt, Fp, Ds, S0
self.arg.net_pars.cons_max = np.array([self.bounds["D"][1], self.bounds["f"][1], self.bounds["Dp"][1], self.bounds["S0"][1]])#bounds[1] # Dt, Fp, Ds, S0
self.bounds = bounds
else:
warnings.warn('No bounds indicated. default bounds are used of self.cons_min = [0, 0, 0.005, 0] and self.cons_max = [0.005, 0.8, 0.2, 2.0] # Dt, Fp, Ds, S0')
self.bounds = {"S0" : [0, 2], "f" : [0, 0.8], "Dp" : [0.005, 0.2], "D" : [0, 0.005]} # These are defined as [lower, upper]
warnings.warn('No bounds indicated. default bounds are used of self.cons_min = [0, 0, 0.005, 0] and self.cons_max = [0.005, 1, 0.2, 2.0] # Dt, Fp, Ds, S0')
self.bounds = {"S0" : [0, 2], "f" : [0, 1], "Dp" : [0.005, 0.2], "D" : [0, 0.005]} # These are defined as [lower, upper]
self.arg.net_pars.cons_min = np.array([self.bounds["D"][0], self.bounds["f"][0], self.bounds["Dp"][0], self.bounds["S0"][0]])#bounds[0] # Dt, Fp, Ds, S0
self.arg.net_pars.cons_max = np.array([self.bounds["D"][1], self.bounds["f"][1], self.bounds["Dp"][1], self.bounds["S0"][1]])#bounds[1] # Dt, Fp, Ds, S0

boundsrange = 0.3 * (np.array(self.arg.net_pars.cons_max)-np.array(self.arg.net_pars.cons_min)) # ensure that we are on the most lineair bit of the sigmoid function
self.arg.net_pars.cons_min = np.array(self.arg.net_pars.cons_min) - boundsrange
self.arg.net_pars.cons_max = np.array(self.arg.net_pars.cons_max) + boundsrange
self.bounds={"S0" : [self.arg.net_pars.cons_min[3], self.arg.net_pars.cons_max[3]], "f" : [self.arg.net_pars.cons_min[1], self.arg.net_pars.cons_max[1]], "Dp" : [self.arg.net_pars.cons_min[2], self.arg.net_pars.cons_max[2]], "D" : [self.arg.net_pars.cons_min[0], self.arg.net_pars.cons_max[0]]} # These are defined as [lower, upper]

self.use_bounds = {"f": True, "Dp": True, "D": True}
self.use_initial_guess = {"f": False, "Dp": False, "D": False}
Expand Down Expand Up @@ -119,6 +124,10 @@ def ivim_fit_full_volume(self, signals, bvalues, retrain_on_input_data=False, **
"""
if not np.array_equal(bvalues, self.bvalues):
raise ValueError("bvalue list at fitting must be identical as the one at initiation, otherwise it will not run")
minimum_bvalue = np.min(self.bvalues) # We normalize the signal to the minimum bvalue. Should be 0 or very close to 0.
b0_indices = np.where(self.bvalues == minimum_bvalue)[0]
normalization_factor = np.mean(signals[..., b0_indices],axis=-1)
signals = signals / np.repeat(normalization_factor[...,np.newaxis],np.shape(signals)[-1],-1)

signals, shape = self.reshape_to_voxelwise(signals)
if retrain_on_input_data:
Expand Down
5 changes: 4 additions & 1 deletion tests/IVIMmodels/unit_tests/algorithms.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
"OJ_GU_bayesMATLAB",
"TF_reference_IVIMfit"
],
"IVIM_NEToptim": {
"TCML_TechnionIIT_lsqBOBYQA": {
"xfail_names": {"pericardium": false}
},
"IVIM_NEToptim": {
"deep_learning": true,
"n":3000000
},
Expand Down
11 changes: 5 additions & 6 deletions tests/IVIMmodels/unit_tests/test_ivim_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,13 @@ def test_bounds(bound_input, eng):
if fit.use_bounds["f"] or fit.use_bounds["D"] or fit.use_bounds["Dp"]:
signal = signal_helper(data["data"])
fit_result = fit.osipi_fit(signal, bvals)
eps=1e-10 # without this margin it can cause floating point failures on mac systems
if fit.use_bounds["D"]:
assert bounds["D"][0] <= fit_result['D'] <= bounds["D"][1], f"Result {fit_result['D']} out of bounds for data: {name}"
assert bounds["D"][0]-eps <= fit_result['D'] <= bounds["D"][1]+eps, f"Result {fit_result['D']} out of bounds for data: {name}"
if fit.use_bounds["f"]:
assert bounds["f"][0] <= fit_result['f'] <= bounds["f"][1], f"Result {fit_result['f']} out of bounds for data: {name}"
assert bounds["f"][0]-eps <= fit_result['f'] <= bounds["f"][1]+eps, f"Result {fit_result['f']} out of bounds for data: {name}"
if fit.use_bounds["Dp"]:
assert bounds["Dp"][0] <= fit_result['Dp'] <= bounds["Dp"][1], f"Result {fit_result['Dp']} out of bounds for data: {name}"
assert bounds["Dp"][0]-eps <= fit_result['Dp'] <= bounds["Dp"][1]+eps, f"Result {fit_result['Dp']} out of bounds for data: {name}"
# S0 is not returned as argument...
#assert bounds[0][3] <= fit_result['S0'] <= bounds[1][3], f"Result {fit_result['S0']} out of bounds for data: {name}"
'''if fit.use_initial_guess:
Expand Down Expand Up @@ -254,12 +255,10 @@ def test_deep_learning_algorithms(deep_learning_algorithms, record_property):
kwargs = {**kwargs, 'eng': eng}

tolerances = tolerances_helper(tolerances, data)
fit = OsipiBase(bvalues=bvals, algorithm=algorithm, **kwargs)
fit = OsipiBase(bvalues=bvals, algorithm=algorithm, bounds={"S0" : [0, 2], "f" : [0, 1], "Dp" : [0.005, 0.2], "D" : [0, 0.005]}, **kwargs)

array_2d = np.array([dat["data"] for _, dat in data.items()])
start_time = time.time()
fit_result = fit.osipi_fit_full_volume(array_2d, bvals)
elapsed_time = time.time() - start_time

errors = [] # Collect all assertion errors

Expand Down