Commit ef535830 authored by William Clarke's avatar William Clarke
Browse files

Removed dyn results pickle dependence. Added dynMRS save and load.

parent 21eccc87
......@@ -166,7 +166,7 @@ def test_load_save(fixed_ratio_mrs, tmp_path):
assert_frame_equal(res._data, res_loaded._data)
assert_frame_equal(res._init_x, res_loaded._init_x)
res.save(tmp_path / 'res_save_test2', pickle_dyn=True)
res.save(tmp_path / 'res_save_test2', save_dyn_obj=True)
res_loaded2 = dyn.load_dyn_result(tmp_path / 'res_save_test2')
assert_frame_equal(res._data, res_loaded2._data)
......
......@@ -200,3 +200,34 @@ def test_dynMRS_mean_fit_init(fixed_ratio_mrs):
init1 = dyn_obj.initialise(indiv_init=meanres.params)
init2 = dyn_obj.initialise(indiv_init='mean')
assert np.allclose(np.hstack(np.hstack(init1['x'])), np.hstack(np.hstack(init2['x'])))
def test_save_load(tmp_path, fixed_ratio_mrs):
mrs_list = fixed_ratio_mrs
dyn_obj = dyn.dynMRS(
mrs_list,
[0, 1],
'fsl_mrs/tests/testdata/dynamic/simple_linear_model.py',
model='lorentzian',
baseline_order=0,
metab_groups=[0, 0],
rescale=False)
dyn_obj.save(tmp_path / 'test_save')
dyn_obj_load = dyn.dynMRS.load(tmp_path / 'test_save', mrs_list=mrs_list)
assert dyn_obj.metabolite_names == dyn_obj_load.metabolite_names
assert dyn_obj.free_names == dyn_obj_load.free_names
assert dyn_obj.mapped_names == dyn_obj_load.mapped_names
assert dyn_obj.vm.fcns.keys() == dyn_obj_load.vm.fcns.keys()
assert np.allclose(dyn_obj.time_var, dyn_obj_load.time_var)
dyn_obj.save(tmp_path / 'test_save2', save_mrs_list=True)
dyn_obj_load2 = dyn.dynMRS.load(tmp_path / 'test_save2')
assert dyn_obj.metabolite_names == dyn_obj_load2.metabolite_names
assert dyn_obj.free_names == dyn_obj_load2.free_names
assert dyn_obj.mapped_names == dyn_obj_load2.mapped_names
assert dyn_obj.vm.fcns.keys() == dyn_obj_load2.vm.fcns.keys()
assert np.allclose(dyn_obj.time_var, dyn_obj_load2.time_var)
This source diff could not be displayed because it is stored in LFS. You can view the blob instead.
......@@ -6,7 +6,6 @@
# Copyright (C) 2021 University of Oxford
import copy
import warnings
import dill as pickle
import pandas as pd
import numpy as np
......@@ -30,7 +29,8 @@ def load_dyn_result(load_dir, dyn_obj=None):
:param load_dir: Directory to load. Creaed using dynMRS.save method
:type load_dir: str or pathlib.Path
:param dyn_obj: Associated dynMRS object or if None will attempt to load a dyn.pkl file, defaults to None
:param dyn_obj: Associated dynMRS object or if None will attempt to load a
nested dynmrs_obj directory, defaults to None
:type dyn_obj: fsl_mrs.utils.dynamic.dynMRS, optional
:return: Dynamic results object
:rtype: dynRes_newton or dynRes_mcmc
......@@ -48,9 +48,9 @@ def load_dyn_result(load_dir, dyn_obj=None):
if dyn_obj:
return cls(sample_df, dyn_obj, init_df)
elif (load_dir / 'dyn.pkl').is_file():
with open(load_dir / 'dyn.pkl', 'rb') as pickle_file:
dyn_obj = pickle.load(pickle_file)
elif (load_dir / 'dynmrs_obj').is_dir():
from .dynmrs import dynMRS
dyn_obj = dynMRS.load(load_dir / 'dynmrs_obj')
return cls(sample_df, dyn_obj, init_df)
else:
raise ResultLoadError('Dynamic object required. Pass directly or ensure dyn.pkl is availible')
......@@ -110,7 +110,7 @@ class dynRes:
else:
self._init_x = pd.DataFrame(self.flatten_mapped(init['x']), columns=self._dyn.mapped_names)
def save(self, save_dir, pickle_dyn=False):
def save(self, save_dir, save_dyn_obj=False):
"""Save the results to a directory
Saves the two dataframes to csv format. If pickle_dyn=True then the ._dyn object
......@@ -118,8 +118,8 @@ class dynRes:
:param save_dir: Location to save to, created if neccesary.
:type save_dir: str or pathlib.Path
:param pickle_dyn: Save _dyn dynMRS object to pickle file, defaults to False
:type pickle_dyn: bool, optional
:param save_dyn_obj: Save _dyn dynMRS object nested directory, defaults to False
:type save_dyn_obj: bool, optional
"""
if not isinstance(save_dir, Path):
save_dir = Path(save_dir)
......@@ -129,10 +129,9 @@ class dynRes:
self._data.to_csv(save_dir / 'dyn_results.csv')
self._init_x.to_csv(save_dir / 'init_results.csv')
# If selected save the dynamic object a pickle file
if pickle_dyn:
with open(save_dir / 'dyn.pkl', 'wb') as fp:
pickle.dump(self._dyn, fp)
# If selected save the dynamic object to a nested directory
if save_dyn_obj:
self._dyn.save(save_dir / 'dynmrs_obj', save_mrs_list=True)
@property
def data_frame(self):
......
......@@ -6,11 +6,15 @@
# Copyright (C) 2019 University of Oxford
# SHBASECOPYRIGHT
import time
import re
from shutil import copyfile
import numpy as np
from scipy.optimize import minimize
import time
import re
from pathlib import Path
import pickle
import json
from fsl_mrs.utils import models, fitting
from . import variable_mapping as varmap
......@@ -22,6 +26,10 @@ from fsl_mrs.utils.misc import rescale_FID
conc_index_re = re.compile(r'^(conc_.*?_)(\d+)$')
class dynMRSLoadError(Exception):
pass
class dynMRS(object):
"""Dynamic MRS class"""
......@@ -55,7 +63,7 @@ class dynMRS(object):
:type rescale: bool, optional
"""
self.time_var = time_var
self.time_var = np.asarray(time_var)
self.mrs_list = mrs_list
if rescale:
self._process_mrs_list()
......@@ -80,6 +88,71 @@ class dynMRS(object):
time_variable=self.time_var,
config_file=config_file)
# For save function
self._config_file = Path(config_file)
self._kwargs = {
'model': model,
'ppmlim': ppmlim,
'baseline_order': baseline_order,
'metab_groups': metab_groups,
'rescale': rescale}
def save(self, save_dir, save_mrs_list=False):
if not isinstance(save_dir, Path):
save_dir = Path(save_dir)
save_dir.mkdir(exist_ok=True, parents=True)
# Save out the components needed to reconstruct this object
# 1 - mrs_list as a pickle file
if save_mrs_list:
with open(save_dir / 'mrs_list.pkl', 'wb') as fp:
pickle.dump(self.mrs_list, fp)
# 2 - Save time_var and kw_args in json file
with open(save_dir / 'args.json', 'w') as fp:
json_dict = {
'time_var': self.time_var.tolist(),
'config_file': self._config_file.name,
'kwargs': self._kwargs}
json.dump(json_dict, fp)
# 3 - Save a copy of the config file
copyfile(self._config_file, save_dir / self._config_file.name)
@classmethod
def load(cls, load_dir, mrs_list=None):
if not isinstance(load_dir, Path):
load_dir = Path(load_dir)
# 1) mrs_list
if mrs_list:
mrs_list_from_pkl = False
elif mrs_list is None\
and (load_dir / 'mrs_list.pkl').is_file():
with open(load_dir / 'mrs_list.pkl', 'rb') as pickle_file:
mrs_list = pickle.load(pickle_file)
mrs_list_from_pkl = True
else:
raise dynMRSLoadError(f'mrs_list must be supplied as argument no mrs_list.pkl found in {str(load_dir)}.')
# 2) Other arguments
with open(load_dir / 'args.json', 'r') as json_file:
args = json.load(json_file)
time_var = args['time_var']
config_file = args['config_file']
if not (load_dir / config_file).is_file():
raise dynMRSLoadError(f'config_file {str(load_dir / config_file)} not found!')
kwargs = args['kwargs']
if mrs_list_from_pkl and kwargs['rescale']:
# Don't rescale twice!
kwargs['rescale'] = False
return cls(mrs_list, time_var, load_dir / config_file, **kwargs)
def _process_mrs_list(self):
"""Apply single scaling to the mrs_list
"""
......
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