Commit 9a8d16f7 authored by William Clarke's avatar William Clarke
Browse files

Merge branch 'rf/dyn_mrs_reslist' into 'master'

RF: Move dynamic results resList output to optional method of dynRes results object. Add more...

See merge request !37
parents 39ed3cf0 9f18d0d7
Pipeline #11910 passed with stages
in 13 minutes and 50 seconds
......@@ -70,6 +70,16 @@ def test_nifti_mrs_generator():
0, 0)
break
for gen_data, slice_idx in obj.iterate_over_dims(dim='DIM_COIL'):
assert gen_data.shape == (1, 1, 1, 4096, 32)
assert slice_idx == (slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
0)
break
for gen_data, slice_idx in obj.iterate_over_dims(dim='DIM_DYN'):
assert gen_data.shape == (1, 1, 1, 4096, 64)
assert slice_idx == (slice(None, None, None),
......@@ -90,6 +100,32 @@ def test_nifti_mrs_generator():
assert slice_idx == (0, 0, 0, slice(None, None, None), 0)
break
obj2 = gen_new_nifti_mrs(
np.zeros((1, 1, 1, 100, 2, 10), dtype=complex),
0.0005,
120.0,
dim_tags=['DIM_EDIT', 'DIM_DYN', None])
for gen_data, slice_idx in obj2.iterate_over_dims(dim='DIM_DYN'):
assert gen_data.shape == (1, 1, 1, 100, 10)
assert slice_idx == (slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
0,
slice(None, None, None))
break
for gen_data, slice_idx in obj2.iterate_over_dims(dim='DIM_EDIT'):
assert gen_data.shape == (1, 1, 1, 100, 2)
assert slice_idx == (slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
slice(None, None, None),
0)
break
def test_nifti_mrs_spatial_generator():
obj = NIFTI_MRS(data['unprocessed'])
......
......@@ -50,12 +50,10 @@ def test_dynRes(fixed_ratio_mrs):
baseline_order=0,
metab_groups=[0, 0],
rescale=False)
res = dyn_obj.fit()
res_obj = dyn_obj.fit()[0]
resinit = dyn_obj.initialise()
res_obj = res['result']
import plotly
fig = res_obj.plot_spectra(init=True, fit_to_init=True)
assert isinstance(fig, plotly.graph_objs._figure.Figure)
......@@ -102,9 +100,8 @@ def test_dynRes_newton(fixed_ratio_mrs):
baseline_order=0,
metab_groups=[0, 0],
rescale=False)
res = dyn_obj.fit()
res_obj = dyn_obj.fit()[0]
res_obj = res['result']
assert isinstance(res_obj.cov_dyn, pd.DataFrame)
assert res_obj.cov_dyn.shape == (10, 10)
......@@ -122,6 +119,9 @@ def test_dynRes_newton(fixed_ratio_mrs):
assert isinstance(res_obj.mapped_params, pd.DataFrame)
assert res_obj.mapped_params.shape == (2, 8)
assert isinstance(res_obj.reslist, list)
assert len(res_obj.reslist) == 2
def test_dynRes_mcmc(fixed_ratio_mrs):
"""Test mcmc optimiser specific components"""
......@@ -136,9 +136,8 @@ def test_dynRes_mcmc(fixed_ratio_mrs):
metab_groups=[0, 0],
rescale=False)
res = dyn_obj.fit(method='MH', mh_jumps=20)
res_obj = dyn_obj.fit(method='MH', mh_jumps=20)[0]
res_obj = res['result']
assert isinstance(res_obj.cov_dyn, pd.DataFrame)
assert res_obj.cov_dyn.shape == (10, 10)
......@@ -169,7 +168,7 @@ def test_load_save(fixed_ratio_mrs, tmp_path):
metab_groups=[0, 0],
rescale=False)
res = dyn_obj.fit()['result']
res = dyn_obj.fit()[0]
res.save(tmp_path / 'res_save_test')
res_loaded = dyn.load_dyn_result(tmp_path / 'res_save_test', dyn_obj)
......
......@@ -150,9 +150,9 @@ def test_dynMRS_fit(fixed_ratio_mrs):
baseline_order=0,
metab_groups=[0, 0],
rescale=False)
res = dyn_obj.fit()
res, _ = dyn_obj.fit()
concs = res['result'].data_frame.filter(like='conc').to_numpy()
concs = res.data_frame.filter(like='conc').to_numpy()
assert np.allclose(concs, [1, 1, 1, 1], atol=0.1)
......@@ -167,9 +167,10 @@ def test_dynMRS_fit_mcmc(fixed_ratio_mrs):
baseline_order=0,
metab_groups=[0, 0],
rescale=False)
res = dyn_obj.fit(method='MH', mh_jumps=50)
init = dyn_obj.initialise(indiv_init=None)
res, _ = dyn_obj.fit(method='MH', mh_jumps=50, init=init)
concs = res['result'].data_frame.filter(like='conc').mean(axis=0).to_numpy()
concs = res.data_frame.filter(like='conc').mean(axis=0).to_numpy()
assert np.allclose(concs, [1, 1, 1, 1], atol=0.1)
......
......@@ -528,6 +528,15 @@ class dynRes_mcmc(dynRes):
"""
super().__init__(samples, dyn, init)
@property
def reslist(self):
"""Generate a list of (independent) results objects.
:return: List of FitRes objects.
:rtype: list
"""
return self._dyn.form_FitRes(self.dataframe.to_numpy(), 'MH')
@property
def cov_dyn(self):
"""Returns the covariance matrix of free parameters
......@@ -611,6 +620,15 @@ class dynRes_newton(dynRes):
std[name] = np.array(s).T
self._std = std
@property
def reslist(self):
"""Generate a list of (independent) results objects.
:return: List of FitRes objects.
:rtype: list
"""
return self._dyn.form_FitRes(self.x, 'Newton')
@property
def cov_dyn(self):
"""Returns the covariance matrix of free parameters
......
......@@ -228,7 +228,7 @@ class dynMRS(object):
:type init: dict, optional
:param verbose: Verbosity flag, defaults to False
:type verbose: bool, optional
:return: Tuple containing dedicated results object, list of fitRes objects, optimisation output (Newton only)
:return: Tuple containing dedicated results object, and optimisation output (Newton only)
:rtype: tuple
"""
if verbose:
......@@ -258,25 +258,18 @@ class dynMRS(object):
# Results
if verbose:
print('Collect results')
# 1. Create dedicated dynamic fit results
# Create dedicated dynamic fit results
if method.lower() == 'newton':
results = dyn_results.dynRes_newton(sol.x, self, init)
elif method.lower() == 'mh':
results = dyn_results.dynRes_mcmc(x, self, init)
else:
raise (Exception(f'Unrecognised method {method}'))
# 2. Create a list of fitRes objects for each timepoint for fsl_mrs like capabilities
res_list = self._form_FitRes(
x,
self._fit_args['model'],
method,
self._fit_args['ppmlim'],
self._fit_args['baseline_order'])
if verbose:
print(f"...completed in {time.time()-end_fit_time} seconds.")
return {'result': results, 'resList': res_list, 'optimisation_sol': sol}
return results, sol
def fit_mean_spectrum(self):
"""Return the parameters from the fit of the mean spectra stored in mrs_list."""
......@@ -288,12 +281,12 @@ class dynMRS(object):
mean_mrs.FID = mean_fid
return fitting.fit_FSLModel(mean_mrs, method='Newton', **self._fit_args).params
def initialise(self, indiv_init=None, verbose=False):
def initialise(self, indiv_init='mean', verbose=False):
"""Initialise the dynamic fitting using seperate fits of each spectrum.
:param indiv_init: Optional initilisation of individual fits.
Can be a numpy array of mapped parameters, 'mean' (fits the mean spectrum), or None (independent).
Defaults to None
Defaults to 'mean'.
:param verbose: Print information during fitting, defaults to False
:type verbose: bool, optional
:return: Dict containing free parameters and individual FitRes objects
......@@ -460,7 +453,7 @@ class dynMRS(object):
fwd[time_index, :] = self.forward[time_index](p)
return fwd.flatten()
def _form_FitRes(self, x, model, method, ppmlim, baseline_order):
def form_FitRes(self, x, method):
"""Create list of FitRes object"""
_, _, _, base_poly, metab_groups, _, _, _ = self._get_constants(
self.mrs_list[0],
......@@ -486,13 +479,13 @@ class dynMRS(object):
dynresList = []
for t in range(self.vm.ntimes):
mrs = self.mrs_list[t]
results = FitRes(model,
results = FitRes(self._fit_args['model'],
method,
mrs.names,
metab_groups,
baseline_order,
self._fit_args['baseline_order'],
base_poly,
ppmlim)
self._fit_args['ppmlim'])
results.loadResults(mrs, mapped[t])
dynresList.append(results)
return dynresList
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment