def test_BaseModel(): BM = BaseModel(data_path + 'small_dwi.nii.gz', data_path + 'dwi.bvecs', data_path + 'dwi.bvals') npt.assert_equal(BM.r_squared, np.ones(BM.signal.shape[:3])) npt.assert_equal(BM.R_squared, np.ones(BM.signal.shape[:3])) npt.assert_equal(BM.coeff_of_determination, np.ones(BM.signal.shape[:3])) npt.assert_equal(BM.RMSE, np.zeros(BM.signal.shape[:3])) # Test without numexpr: XXX Doesn't seem to do that for now has_numexpr = ozm.has_numexpr if has_numexpr: ozm.has_numexpr = False BM_wo_numexpr = BaseModel(data_path + 'small_dwi.nii.gz', data_path + 'dwi.bvecs', data_path + 'dwi.bvals') npt.assert_equal(BM.r_squared, np.ones(BM.signal.shape[:3])) npt.assert_equal(BM.R_squared, np.ones(BM.signal.shape[:3])) npt.assert_equal(BM.coeff_of_determination, np.ones(BM.signal.shape[:3])) npt.assert_equal(BM.RMSE, np.zeros(BM.signal.shape[:3])) # Set it back: ozm.has_numexpr = True
def __init__(self, data, bvecs, bvals, sh_order=8, quad_points=132, verts_level=5, alpha=None, rho=None, params_file=None, affine=None, mask=None, scaling_factor=SCALE_FACTOR): # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, params_file=params_file) self.sh_order = sh_order self.quad_points = quad_points # This will soon be replaced by an import from dipy: import kernel_model from dipy.core.subdivide_octahedron import create_unit_hemisphere self.kernel_model = kernel_model self.verts_level = verts_level # Set the sparseness params. # First, for the default values: aa = 0.0001 # L1 weight bb = 0.00001 # L2 weight if alpha is None: alpha = aa + bb if rho is None: rho = aa / (aa + bb) self.alpha = alpha self.rho = rho
def __init__(self, data, bvecs, bvals, sh_order=8, quad_points=132, verts_level=5, alpha=None, rho=None, params_file=None, affine=None, mask=None, scaling_factor=SCALE_FACTOR): # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, params_file=params_file) self.sh_order = sh_order self.quad_points = quad_points # This will soon be replaced by an import from dipy: import kernel_model from dipy.core.subdivide_octahedron import create_unit_hemisphere self.kernel_model = kernel_model self.verts_level = verts_level # Set the sparseness params. # First, for the default values: aa = 0.0001 # L1 weight bb = 0.00001 # L2 weight if alpha is None: alpha = aa + bb if rho is None: rho = aa/(aa + bb) self.alpha = alpha self.rho = rho
def __init__(self, data, bvecs, bvals, params_file=None, affine=None, mask=None, scaling_factor=SCALE_FACTOR): # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, params_file=params_file)
def __init__(self, data, FG, bvecs=None, bvals=None, affine=None, mask=None, scaling_factor=None, params_file=None, sub_sample=None): """ Parameters ---------- data : a volume with data (can be diffusion data, but doesn't have to be) FG : a osmosis.fibers.FiberGroup object, or the name of a pdb file containing the fibers to be read in using ozf.fg_from_pdb """ # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, params_file=params_file, sub_sample=sub_sample) if affine is not None: # The FG is transformed through the provided affine if need be: self.FG = FG.xform(affine.getI(), inplace=False) else: self.FG = FG
def __init__(self, data, bvecs, bvals, params_file=None, axial_diffusivity=AD, radial_diffusivity=RD, affine=None, mask=None, scaling_factor=SCALE_FACTOR, sub_sample=None, over_sample=None, mode='relative_signal', iso_diffusivity=None, verbose=True): """ Initialize a CanonicalTensorModel class instance. Parameters ---------- params_file: str, optional full path to the name of the file in which to save the model parameters, once a model is fit. over_sample: optional, int. Sometimes you might want to probe the sphere at a higher resolution than that provided by the measurement. You can do that using two possible sources of information. The first is the camino points, which ship together with osmosis and are used for the boot-strapping (see osmosis.boot). These are used for integers smaller than 150, for 246 and for 755. The other sources of information are the symmetric spheres provided as part of dipy. These are used if 362 or 642 are provided. Note that these might be problematic, because they contain polar opposite points, so use with caution. mode: string, optional This can take one of several values, determining the form of the regressors and the form of the signal to fit to. 'relative_signal': The fit is to $\frac{S}{S_0}$ and the regressors are the relative signal predicted for a canonical tensor and the relative signal predicted for a isotropic diffusivity compartment: .. math:: \frac{S}{S_0} = \beta_1 e^{-bD} + \beta_2 e^{-b\vec{b}Q\vec{b}^t} 'signal_attenuation': The fit is to $1-\frac{S}{S_0}$ and the regressors are the signal attenuation for the canonical tensor and the signal attenuation due to isotropic diffusion: .. math:: 1-\frac{S}{S_0} = \beta_1 (1-e^{-bD}) + \beta_2 (1-e^{-b\vec{b} Q \vec{b}^t}) 'normalize': in this case, we fit to $\frac{S}{S_0}$, but our regressor set is normalized to maximum of 1 in each columns. This affects the values of the weights, and also the goodness-of-fit (because of the relative scaling of the regressors in the OLS). The equation in this case is: .. math:: \frac{S}{S_0} = \beta_1 + \beta_2 \frac{e^{-b\vec{b} Q \vec{b}^t}}{max(e^{-b\vec{b} Q \vec{b}^t})} 'log': in this case, we fit to $log(\frac{S}{S_0})$ and our regressors are the exponents: .. math:: log(\frac{S}{S_0}) = \beta_1 -bD + \beta_1 -b\vec{b}Q\vec{b}^t iso_diffusivity: optional, float What the diffusivity of the isotropic component should be set to. This is irrelevant for the 'normalize' mode. Defaults to be equal to the axial_diffusivity """ # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, sub_sample=sub_sample, params_file=params_file, verbose=verbose) self.ad = axial_diffusivity self.rd = radial_diffusivity if iso_diffusivity is None: iso_diffusivity = axial_diffusivity self.iso_diffusivity = iso_diffusivity if over_sample is not None: # Symmetric spheres from dipy: if over_sample in[362, 642]: # We want to get these vertices: verts = dpd.get_sphere('symmetric%s'%over_sample).vertices # Their convention is transposed relative to ours: self.rot_vecs = verts.T elif (isinstance(over_sample, int) and (over_sample<=150 or over_sample in [246,755])): self.rot_vecs = ozu.get_camino_pts(over_sample) elif over_sample== 'quad132': pp = os.path.split(oz.__file__)[0]+'/data/SparseKernelModel/' self.rot_vecs = np.loadtxt(pp + 'qsph1-16-132DP.dat')[:,:-1].T else: e_s = "You asked to sample the sphere in %s"%over_sample e_s += " different directions. Can only do that for n<=150" e_s += " or n in [246, 362, 642, 755]" raise ValueError(e_s) else: self.rot_vecs = self.bvecs[:,self.b_idx] if mode not in ['relative_signal', 'signal_attenuation', 'normalize', 'log']: raise ValueError("Not a recognized mode of CanonicalTensorModel") self.mode = mode self.iso_diffusivity = iso_diffusivity
def __init__( self, data, bvecs, bvals, model_coeffs, params_file=None, axial_diffusivity=None, radial_diffusivity=None, response_file=None, affine=None, mask=None, scaling_factor=SCALE_FACTOR, sub_sample=None, verbose=True, ): """ Initialize a SphericalHarmonicsModel class instance. Parameters ---------- DWI: osmosis.dwi.DWI class instance. model_coefficients: ndarray Coefficients for a SH model, organized according to the conventions used by mrtrix (see sph_harm_set for details). """ # Initialize the super-class: BaseModel.__init__( self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, sub_sample=sub_sample, params_file=params_file, verbose=verbose, ) # If it's a string, assume it's a full path to a nifti file: if isinstance(model_coeffs, str): self.model_coeffs = ni.load(model_coeffs).get_data() else: # Otherwise, it had better be an array: self.model_coeffs = model_coeffs self.L = self._calculate_L(self.model_coeffs.shape[-1]) self.n_params = self.model_coeffs.shape[-1] self.ad = axial_diffusivity self.rd = radial_diffusivity if axial_diffusivity is None and radial_diffusivity is None and response_file is None: self.ad = AD self.rd = RD elif axial_diffusivity is not None and radial_diffusivity is not None and response_file is not None: e_s = "Need to provide information to generate canonical tensor" e_s += " *or* path to response file for response function. " e_s += "Not both!" raise ValueError(e_s) self.response_file = response_file
def __init__(self, data, bvecs, bvals, params_file=None, axial_diffusivity=AD, radial_diffusivity=RD, affine=None, mask=None, scaling_factor=SCALE_FACTOR, sub_sample=None, over_sample=None, mode='relative_signal', iso_diffusivity=None, verbose=True): """ Initialize a CanonicalTensorModel class instance. Parameters ---------- params_file: str, optional full path to the name of the file in which to save the model parameters, once a model is fit. over_sample: optional, int. Sometimes you might want to probe the sphere at a higher resolution than that provided by the measurement. You can do that using two possible sources of information. The first is the camino points, which ship together with osmosis and are used for the boot-strapping (see osmosis.boot). These are used for integers smaller than 150, for 246 and for 755. The other sources of information are the symmetric spheres provided as part of dipy. These are used if 362 or 642 are provided. Note that these might be problematic, because they contain polar opposite points, so use with caution. mode: string, optional This can take one of several values, determining the form of the regressors and the form of the signal to fit to. 'relative_signal': The fit is to $\frac{S}{S_0}$ and the regressors are the relative signal predicted for a canonical tensor and the relative signal predicted for a isotropic diffusivity compartment: .. math:: \frac{S}{S_0} = \beta_1 e^{-bD} + \beta_2 e^{-b\vec{b}Q\vec{b}^t} 'signal_attenuation': The fit is to $1-\frac{S}{S_0}$ and the regressors are the signal attenuation for the canonical tensor and the signal attenuation due to isotropic diffusion: .. math:: 1-\frac{S}{S_0} = \beta_1 (1-e^{-bD}) + \beta_2 (1-e^{-b\vec{b} Q \vec{b}^t}) 'normalize': in this case, we fit to $\frac{S}{S_0}$, but our regressor set is normalized to maximum of 1 in each columns. This affects the values of the weights, and also the goodness-of-fit (because of the relative scaling of the regressors in the OLS). The equation in this case is: .. math:: \frac{S}{S_0} = \beta_1 + \beta_2 \frac{e^{-b\vec{b} Q \vec{b}^t}}{max(e^{-b\vec{b} Q \vec{b}^t})} 'log': in this case, we fit to $log(\frac{S}{S_0})$ and our regressors are the exponents: .. math:: log(\frac{S}{S_0}) = \beta_1 -bD + \beta_1 -b\vec{b}Q\vec{b}^t iso_diffusivity: optional, float What the diffusivity of the isotropic component should be set to. This is irrelevant for the 'normalize' mode. Defaults to be equal to the axial_diffusivity """ # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, sub_sample=sub_sample, params_file=params_file, verbose=verbose) self.ad = axial_diffusivity self.rd = radial_diffusivity if iso_diffusivity is None: iso_diffusivity = axial_diffusivity self.iso_diffusivity = iso_diffusivity if over_sample is not None: # Symmetric spheres from dipy: if over_sample in [362, 642]: # We want to get these vertices: verts = dpd.get_sphere('symmetric%s' % over_sample).vertices # Their convention is transposed relative to ours: self.rot_vecs = verts.T elif (isinstance(over_sample, int) and (over_sample <= 150 or over_sample in [246, 755])): self.rot_vecs = ozu.get_camino_pts(over_sample) elif over_sample == 'quad132': pp = os.path.split(oz.__file__)[0] + '/data/SparseKernelModel/' self.rot_vecs = np.loadtxt(pp + 'qsph1-16-132DP.dat')[:, :-1].T else: e_s = "You asked to sample the sphere in %s" % over_sample e_s += " different directions. Can only do that for n<=150" e_s += " or n in [246, 362, 642, 755]" raise ValueError(e_s) else: self.rot_vecs = self.bvecs[:, self.b_idx] if mode not in [ 'relative_signal', 'signal_attenuation', 'normalize', 'log' ]: raise ValueError("Not a recognized mode of CanonicalTensorModel") self.mode = mode self.iso_diffusivity = iso_diffusivity
def __init__(self, data, bvecs, bvals, params_file=None, mask=None, scaling_factor=SCALE_FACTOR, sub_sample=None, verbose=True, fit_method='WLS'): """ Parameters ----------- data, bvecs, bvals: see DWI inputs scaling_factor: This scales the b value for the Stejskal/Tanner equation mask: ndarray or file-name An array of the same shape as the data, containing a binary mask pointing to the locations of voxels that should be analyzed. sub_sample: int or array of ints. If we want to sub-sample the DWI data on the sphere (in the bvecs), we can do one of two things: 1. If sub_sample is an integer, that number of random bvecs will be chosen from the data. 2. If an array of indices is provided, these will serve as indices into the last dimension of the data and only that part of the data will be used params_file: A file to cache the initial tensor calculation in. If this file already exists, we pull the tensor fit out of it. Otherwise, we calculate the tensor fit and save this file with the params of the tensor fit. fit_method: str 'WLS' for weighted least squares fitting (default) or 'LS'/'OLS' for ordinary least squares. """ # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=None, mask=mask, scaling_factor=scaling_factor, sub_sample=sub_sample, params_file=params_file, verbose=verbose) # Allow using 'OLS' to denote the ordinary least-squares method if fit_method == 'OLS': fit_method = 'LS' self.scaling_factor = scaling_factor self.fit_method = fit_method self.gtab = gradients.gradient_table(self.bvals, self.bvecs)
def __init__(self, data, bvecs, bvals, model_coeffs, params_file=None, axial_diffusivity=None, radial_diffusivity=None, response_file=None, affine=None, mask=None, scaling_factor=SCALE_FACTOR, sub_sample=None, verbose=True): """ Initialize a SphericalHarmonicsModel class instance. Parameters ---------- DWI: osmosis.dwi.DWI class instance. model_coefficients: ndarray Coefficients for a SH model, organized according to the conventions used by mrtrix (see sph_harm_set for details). """ # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=affine, mask=mask, scaling_factor=scaling_factor, sub_sample=sub_sample, params_file=params_file, verbose=verbose) # If it's a string, assume it's a full path to a nifti file: if isinstance(model_coeffs, str): self.model_coeffs = ni.load(model_coeffs).get_data() else: # Otherwise, it had better be an array: self.model_coeffs = model_coeffs self.L = self._calculate_L(self.model_coeffs.shape[-1]) self.n_params = self.model_coeffs.shape[-1] self.ad = axial_diffusivity self.rd = radial_diffusivity if (axial_diffusivity is None and radial_diffusivity is None and response_file is None): self.ad = AD self.rd = RD elif (axial_diffusivity is not None and radial_diffusivity is not None and response_file is not None): e_s = "Need to provide information to generate canonical tensor" e_s += " *or* path to response file for response function. " e_s += "Not both!" raise ValueError(e_s) self.response_file = response_file
def __init__(self, data, bvecs, bvals, params_file=None, mask=None, scaling_factor=SCALE_FACTOR, sub_sample=None, verbose=True, fit_method='WLS'): """ Parameters ----------- data, bvecs, bvals: see DWI inputs scaling_factor: This scales the b value for the Stejskal/Tanner equation mask: ndarray or file-name An array of the same shape as the data, containing a binary mask pointing to the locations of voxels that should be analyzed. sub_sample: int or array of ints. If we want to sub-sample the DWI data on the sphere (in the bvecs), we can do one of two things: 1. If sub_sample is an integer, that number of random bvecs will be chosen from the data. 2. If an array of indices is provided, these will serve as indices into the last dimension of the data and only that part of the data will be used params_file: A file to cache the initial tensor calculation in. If this file already exists, we pull the tensor fit out of it. Otherwise, we calculate the tensor fit and save this file with the params of the tensor fit. fit_method: str 'WLS' for weighted least squares fitting (default) or 'LS'/'OLS' for ordinary least squares. """ # Initialize the super-class: BaseModel.__init__(self, data, bvecs, bvals, affine=None, mask=mask, scaling_factor=scaling_factor, sub_sample=sub_sample, params_file=params_file, verbose=verbose) # Allow using 'OLS' to denote the ordinary least-squares method if fit_method=='OLS': fit_method = 'LS' self.scaling_factor = scaling_factor self.fit_method = fit_method self.gtab = gradients.gradient_table(self.bvals, self.bvecs)