Example #1
0
    def combine(self):
        super().combine()

        statistic_maps = {}
        for name in self._sample_storage:
            samples_path = os.path.join(self._output_dir,
                                        name + '.samples.npy')
            samples = open_memmap(samples_path, mode='r')
            statistic_maps[name] = np.mean(samples, axis=1)
            statistic_maps[name + '.std'] = np.std(samples, axis=1)

        write_all_as_nifti(restore_volumes(statistic_maps, self._mask),
                           os.path.join(self._output_dir, 'univariate_normal'),
                           nifti_header=self._nifti_header,
                           gzip=self._write_volumes_gzipped)

        write_all_as_nifti({'UsedMask': self._mask},
                           self._output_dir,
                           nifti_header=self._nifti_header,
                           gzip=self._write_volumes_gzipped)

        if not self._keep_samples:
            for ind, name in enumerate(self._model.get_free_param_names()):
                os.remove(os.path.join(self._output_dir,
                                       name + '.samples.npy'))
        else:
            return load_samples(self._output_dir)
Example #2
0
File: npy.py Project: sudesnac/MDT
def samples_npy_to_nifti(samples_npy_fname,
                         used_mask,
                         nifti_header,
                         nifti_fname=None):
    """Convert a npy file containing sample results to a nifti file.

    Since the sample npy files are stored as a two dimensional matrix (with on the first axis the ROI index number
    and on the second the samples), we need to have the lookup table for the spatial information about the samples.

    Args:
        samples_npy_fname (str): the filename of the samples file to convert
        used_mask (ndarray or str): either an three dimensional matrix with the mask or a path to a nifti file.
        nifti_header (nibabel header): the header to use for writing the nifti file
        nifti_fname (str): the filename of the nifti file. If not given it defaults to the same directory as the
            samples file.
    """
    samples = np.load(samples_npy_fname, mmap_mode='r')

    if isinstance(used_mask, str):
        used_mask = load_nifti(used_mask).get_data()

    if np.count_nonzero(used_mask) != samples.shape[0]:
        raise ValueError(
            'The number of voxels in the mask ({}) does not correspond '
            'with the number of voxels in the samples file ({})'.format(
                np.count_nonzero(used_mask), samples.shape[0]))

    if nifti_fname is None:
        nifti_fname = os.path.join(
            os.path.dirname(samples_npy_fname),
            os.path.splitext(os.path.basename(samples_npy_fname))[0] +
            '.nii.gz')

    volume = restore_volumes(samples, used_mask)
    write_nifti(volume, nifti_fname, nifti_header)
Example #3
0
def create_signal_estimates(model, input_data, parameters):
    """Create the signals estimates for your estimated model parameters.

    This function is typically used to obtain signal estimates from optimization results.

    This function evaluates the model as it is in the model fitting and sample. That is, this method includes
    the gradient deviations (if set in the input data) and loads all static and fixed parameters maps.

    Args:
        model (str or model): the model or the name of the model to use for estimating the signals
        input_data (mdt.utils.MRIInputData): the input data object, we will set this to the model
        parameters (str or dict): either a directory file name or a dictionary containing optimization results
            Each element is assumed to be a 4d volume with the voxels we are using for the simulations.

    Returns:
        ndarray: the 4d array with the signal estimates per voxel
    """
    if isinstance(model, str):
        model = get_model(model)()

    model.set_input_data(input_data)
    build_model = model.build()

    if isinstance(parameters, str):
        parameters = get_all_nifti_data(parameters)

    parameters = create_roi(parameters, input_data.mask)
    parameters = model.param_dict_to_array(parameters)

    kernel_data = {
        'data':
        build_model.get_kernel_data(),
        'parameters':
        Array(parameters, ctype='mot_float_type'),
        'estimates':
        Zeros((parameters.shape[0], build_model.get_nmr_observations()),
              'mot_float_type')
    }

    _get_simulate_function(build_model).evaluate(kernel_data,
                                                 parameters.shape[0])
    results = kernel_data['estimates'].get_data()

    return restore_volumes(results, input_data.mask)
Example #4
0
def create_signal_estimates(model, input_data, parameters):
    """Create the signals estimates for your estimated model parameters.

    This function is typically used to obtain signal estimates from optimization results.

    This function evaluates the model as it is in the model fitting and sampling. That is, this method includes
    the gradient deviations (if set in the input data) and loads all static and fixed parameters maps.

    Args:
        model (str or model): the model or the name of the model to use for estimating the signals
        input_data (mdt.utils.MRIInputData): the input data object, we will set this to the model
        parameters (str or dict): either a directory file name or a dictionary containing optimization results
            Each element is assumed to be a 4d volume with the voxels we are using for the simulations.

    Returns:
        ndarray: the 4d array with the signal estimates per voxel
    """
    if isinstance(model, string_types):
        model = get_model(model)()

    model.set_input_data(input_data)

    if isinstance(parameters, string_types):
        parameters = get_all_nifti_data(parameters)

    parameters = create_roi(parameters, input_data.mask)
    parameters = model.param_dict_to_array(parameters)

    build_model = model.build()

    if parameters.shape[0] != build_model.get_nmr_problems():
        raise ValueError(
            'The number of voxels in the parameters does not match those in the model.'
        )

    calculator = CalculateModelEstimates()
    results = calculator.calculate(model.build(), parameters)

    return restore_volumes(results, input_data.mask)
Example #5
0
    def get_init_data(model_name):
        inits = {}
        free_parameters = get_model(model_name)().get_free_param_names()

        if 'S0.s0' in free_parameters and input_data.has_input_data('b'):
            if input_data.get_input_data(
                    'b').shape[0] == input_data.nmr_voxels:
                masked_observations = ma.masked_array(
                    input_data.observations,
                    input_data.get_input_data('b') < 250e6)
                inits['S0.s0'] = restore_volumes(
                    np.mean(masked_observations, axis=1), input_data.mask)
            else:
                unweighted_locations = np.where(
                    input_data.get_input_data('b') < 250e6)[0]
                inits['S0.s0'] = np.mean(
                    input_data.signal4d[..., unweighted_locations], axis=-1)

        if model_name.startswith('BallStick_r2'):
            inits.update(
                get_subset(free_parameters, get_model_fit('BallStick_r1')))
            inits['w_stick1.w'] = np.minimum(inits['w_stick0.w'], 0.05)
        elif model_name.startswith('BallStick_r3'):
            inits.update(
                get_subset(free_parameters, get_model_fit('BallStick_r2')))
            inits['w_stick2.w'] = np.minimum(inits['w_stick1.w'], 0.05)
        elif model_name.startswith('Tensor'):
            fit_results = get_model_fit('BallStick_r1')
            inits.update(get_subset(free_parameters, fit_results))
            inits['Tensor.theta'] = fit_results['Stick0.theta']
            inits['Tensor.phi'] = fit_results['Stick0.phi']
        elif model_name.startswith('NODDI'):
            fit_results = get_model_fit('BallStick_r1')
            inits.update(get_subset(free_parameters, fit_results))
            inits['w_ic.w'] = fit_results['w_stick0.w'] / 2.0
            inits['w_ec.w'] = fit_results['w_stick0.w'] / 2.0
            inits['w_csf.w'] = fit_results['w_ball.w']
            inits['NODDI_IC.theta'] = fit_results['Stick0.theta']
            inits['NODDI_IC.phi'] = fit_results['Stick0.phi']
        elif model_name.startswith('BinghamNODDI_r1'):
            noddi_results = get_model_fit('NODDI')
            inits.update(get_subset(free_parameters, noddi_results))
            inits['w_in0.w'] = noddi_results['w_ic.w']
            inits['w_en0.w'] = noddi_results['w_ec.w']
            inits['w_csf.w'] = noddi_results['w_csf.w']
            inits['BinghamNODDI_IN0.theta'] = noddi_results['NODDI_IC.theta']
            inits['BinghamNODDI_IN0.phi'] = noddi_results['NODDI_IC.phi']
            inits['BinghamNODDI_IN0.k1'] = noddi_results['NODDI_IC.kappa']
        elif model_name.startswith('BinghamNODDI_r2'):
            bs2_results = get_model_fit('BallStick_r2')
            inits.update(get_subset(free_parameters, bs2_results))
            inits.update(
                get_subset(free_parameters, get_model_fit('BinghamNODDI_r1')))
            inits['BinghamNODDI_IN1.theta'] = bs2_results['Stick1.theta']
            inits['BinghamNODDI_IN1.phi'] = bs2_results['Stick1.phi']
        elif model_name.startswith('Kurtosis'):
            fit_results = get_model_fit('Tensor')
            inits.update(get_subset(free_parameters, fit_results))
            inits.update({
                'KurtosisTensor.' + key: fit_results['Tensor.' + key]
                for key in ['theta', 'phi', 'psi', 'd', 'dperp0', 'dperp1']
            })
        elif model_name.startswith('CHARMED_r'):
            nmr_dir = model_name[len('CHARMED_r'):len('CHARMED_r') + 1]
            fit_results = get_model_fit('BallStick_r' + nmr_dir)
            inits.update(get_subset(free_parameters, fit_results))
            inits['Tensor.theta'] = fit_results['Stick0.theta']
            inits['Tensor.phi'] = fit_results['Stick0.phi']
            for dir_ind in range(int(nmr_dir)):
                inits['w_res{}.w'.format(dir_ind)] = fit_results[
                    'w_stick{}.w'.format(dir_ind)]
                inits['CHARMEDRestricted{}.theta'.format(
                    dir_ind)] = fit_results['Stick{}.theta'.format(dir_ind)]
                inits['CHARMEDRestricted{}.phi'.format(dir_ind)] = fit_results[
                    'Stick{}.phi'.format(dir_ind)]
        elif model_name.startswith('BallRacket_r'):
            nmr_dir = model_name[len('BallRacket_r'):len('BallRacket_r') + 1]
            fit_results = get_model_fit('BallStick_r' + nmr_dir)
            inits.update(get_subset(free_parameters, fit_results))
            for dir_ind in range(int(nmr_dir)):
                inits['w_res{}.w'.format(dir_ind)] = fit_results[
                    'w_stick{}.w'.format(dir_ind)]
                inits['Racket{}.theta'.format(dir_ind)] = fit_results[
                    'Stick{}.theta'.format(dir_ind)]
                inits['Racket{}.phi'.format(dir_ind)] = fit_results[
                    'Stick{}.phi'.format(dir_ind)]
        elif model_name.startswith('AxCaliber'):
            fit_results = get_model_fit('BallStick_r1')
            inits.update(get_subset(free_parameters, fit_results))
            inits['GDRCylinders.theta'] = fit_results['Stick0.theta']
            inits['GDRCylinders.phi'] = fit_results['Stick0.phi']
        elif model_name.startswith('ActiveAx'):
            fit_results = get_model_fit('BallStick_r1')
            inits.update(get_subset(free_parameters, fit_results))
            inits['w_ic.w'] = fit_results['w_stick0.w'] / 2.0
            inits['w_ec.w'] = fit_results['w_stick0.w'] / 2.0
            inits['w_csf.w'] = fit_results['w_ball.w']
            inits['CylinderGPD.theta'] = fit_results['Stick0.theta']
            inits['CylinderGPD.phi'] = fit_results['Stick0.phi']
        elif model_name.startswith('QMT_ReducedRamani'):
            inits['S0.s0'] = np.mean(input_data.signal4d, axis=-1)

        return inits
Example #6
0
 def signal4d(self):
     # return self._signal4d
     return restore_volumes(self._observation_list, self.mask)
Example #7
0
def compute_fim(model, input_data, optimization_results, output_folder=None, cl_device_ind=None, cl_load_balancer=None,
                initialization_data=None):
    """Compute the Fisher Information Matrix (FIM).

    This is typically done as post-processing step during the model fitting process, but can also be performed
    separately after optimization.

    Since the FIM depends on which parameters were optimized, results will change if different parameters are fixed.
    That is, this function will compute the FIM for every estimable parameter (free-non-fixed parameters). If you want
    to have the exact same FIM results as when you computed the FIM as optimization post-processing it is important
    to have exactly the same maps fixed.

    Contrary to the post-processing of the optimization maps, all FIM results are written to a single sub-folder in the
    provided output folder.

    Args:
        model (str or :class:`~mdt.models.base.EstimableModel`):
            The name of a composite model or an implementation of a composite model.
        input_data (:class:`~mdt.lib.input_data.MRIInputData`): the input data object containing all
            the info needed for the model fitting.
        optimization_results (dict or str): the optimization results, either a dictionary with results or the
            path to a folder.
        output_folder (string): Optionally, the path to the folder where to place the output
        cl_device_ind (List[Union[mot.lib.cl_environments.CLEnvironment, int]]
                             or mot.lib.cl_environments.CLEnvironment or int): the CL devices to use.
            Either provide MOT CLEnvironment's or indices from into the list from the function mdt.get_cl_devices().
        cl_load_balancer (mot.lib.load_balancers.LoadBalancer or Tuple[float]): the load balancer to use. Can also
            be an array of fractions (summing to 1) with one fraction per device. For example, for two devices one
            can specify ``cl_load_balancer = [0.3, 0.7]`` to let one device to more work than another.
        initialization_data (dict): provides (extra) initialization data to
            use during model fitting. This dictionary can contain the following elements:

            * ``inits``: dictionary with per parameter an initialization point
            * ``fixes``: dictionary with per parameter a fixed point, this will remove that parameter from the fitting
            * ``lower_bounds``: dictionary with per parameter a lower bound
            * ``upper_bounds``: dictionary with per parameter a upper bound
            * ``unfix``: a list of parameters to unfix

            For example::

                initialization_data = {
                    'fixes': {'Stick0.theta: np.array(...), ...},
                    'inits': {...}
                }

    Returns:
        dict: all the computed FIM maps in a flattened dictionary.
    """
    initialization_data = initialization_data or {}

    if isinstance(optimization_results, str):
        optimization_results = get_all_nifti_data(optimization_results)

    if not check_user_components():
        init_user_settings(pass_if_exists=True)

    cl_runtime_info = CLRuntimeInfo(cl_environments=cl_device_ind,
                                    double_precision=True,
                                    load_balancer=cl_load_balancer)

    if isinstance(model, str):
        model_name = model
        model_instance = get_model(model)()
    else:
        model_name = model.name
        model_instance = model

    model_instance.set_input_data(input_data)

    initialization_data = SimpleInitializationData(**initialization_data)
    initialization_data.apply_to_model(model_instance, input_data)

    with mot.configuration.config_context(CLRuntimeAction(cl_runtime_info)):
        opt_points = create_roi(optimization_results, input_data.mask)
        opt_array = combine_dict_to_array(opt_points, model_instance.get_free_param_names())

        covars = model_instance.compute_covariance_matrix(opt_array)
        covariance_names = model_instance.get_covariance_output_names()

        return_results = {}
        for ind, name in enumerate(covariance_names):
            if name.endswith('.std'):
                return_results[name] = np.nan_to_num(np.sqrt(covars[..., ind]))
            else:
                return_results[name] = covars[..., ind]

        return_results = restore_volumes(return_results, input_data.mask)
        write_volume_maps(return_results, os.path.join(output_folder, model_name, 'FIM'))

        return return_results