def create_noddi_watson_model(lambda_iso_diff=3.e-9, lambda_par_diff=1.7e-9): """Creates NODDI mulit-compartment model with Watson distribution.""" """ Arguments: lambda_iso_diff: float isotropic diffusivity lambda_par_diff: float parallel diffusivity Returns: MultiCompartmentModel instance NODDI Watson multi-compartment model instance """ ball = gaussian_models.G1Ball() stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() watson_dispersed_bundle = SD1WatsonDistributed(models=[stick, zeppelin]) watson_dispersed_bundle.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0') watson_dispersed_bundle.set_equal_parameter('G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') watson_dispersed_bundle.set_fixed_parameter('G2Zeppelin_1_lambda_par', lambda_par_diff) NODDI_mod = MultiCompartmentModel(models=[ball, watson_dispersed_bundle]) NODDI_mod.set_fixed_parameter('G1Ball_1_lambda_iso', lambda_iso_diff) return NODDI_mod
def test_orienting_stick(): # test for orienting the axis of the Stick along mu # first test to see if Estick equals Gaussian with lambda_par along mu random_n_mu_vector = np.random.rand(2) * np.pi n = utils.sphere2cart(np.r_[1, random_n_mu_vector]) random_bval = np.r_[np.random.rand() * 1e9] random_lambda_par = np.random.rand() * 3e-9 scheme = acquisition_scheme_from_bvalues( random_bval, np.atleast_2d(n), delta, Delta) # initialize model stick = cylinder_models.C1Stick(mu=random_n_mu_vector, lambda_par=random_lambda_par) # test if parallel direction attenuation as a Gaussian E_stick = stick(scheme) E_check = np.exp(-random_bval * (random_lambda_par)) assert_almost_equal(E_stick, E_check) # test if perpendicular direction does not attenuate n_perp = perpendicular_vector(n) scheme = acquisition_scheme_from_bvalues( random_bval, np.atleast_2d(n_perp), delta, Delta) E_stick_perp = stick(scheme) assert_almost_equal(E_stick_perp, 1.)
def test_spherical_harmonics_model_raises(odi=0.15, mu=[0., 0.], lambda_par=1.7e-9): stick = cylinder_models.C1Stick() ball = gaussian_models.G1Ball() watsonstick = distribute_models.SD1WatsonDistributed([stick]) params = { 'SD1Watson_1_odi': odi, 'SD1Watson_1_mu': mu, 'C1Stick_1_lambda_par': lambda_par } data = watsonstick(scheme, **params) assert_raises(ValueError, modeling_framework.MultiCompartmentSphericalHarmonicsModel, [ball]) sh_mod = modeling_framework.MultiCompartmentSphericalHarmonicsModel( [stick]) assert_raises(ValueError, sh_mod.fit, scheme, data, solver='csd_cvxpy') sh_mod = modeling_framework.MultiCompartmentSphericalHarmonicsModel( [stick, ball]) sh_mod.set_fixed_parameter('C1Stick_1_lambda_par', lambda_par) sh_mod.set_fixed_parameter('G1Ball_1_lambda_iso', 3e-9) assert_raises(ValueError, sh_mod.fit, scheme, data, solver='csd_tournier07')
def test_all_models_dispersable(): scheme = wu_minn_hcp_acquisition_scheme() dispersable_models = [ [cylinder_models.C1Stick()], [cylinder_models.C2CylinderStejskalTannerApproximation()], [cylinder_models.C3CylinderCallaghanApproximation()], [cylinder_models.C4CylinderGaussianPhaseApproximation()], [gaussian_models.G1Ball(), gaussian_models.G2Zeppelin()], [gaussian_models.G3TemporalZeppelin()], [sphere_models.S1Dot(), gaussian_models.G2Zeppelin()], [ sphere_models.S2SphereStejskalTannerApproximation(), gaussian_models.G2Zeppelin() ] ] spherical_distributions = [ distribute_models.SD1WatsonDistributed, distribute_models.SD2BinghamDistributed ] for model in dispersable_models: for distribution in spherical_distributions: dist_mod = distribution(model) params = {} for param, card in dist_mod.parameter_cardinality.items(): params[param] = np.random.rand( card) * dist_mod.parameter_scales[param] assert_equal(isinstance(dist_mod(scheme, **params), np.ndarray), True)
def test_all_fitted_model_properties(): stick = cylinder_models.C1Stick() watsonstick = distribute_models.SD1WatsonDistributed([stick]) params = {} for parameter, card, in watsonstick.parameter_cardinality.items(): params[parameter] = (np.random.rand(card) * watsonstick.parameter_scales[parameter]) data = np.atleast_2d(watsonstick(scheme, **params)) mcmod = modeling_framework.MultiCompartmentModel([watsonstick]) mcfit = mcmod.fit(scheme, data) vertices = np.random.rand(10, 3) vertices /= np.linalg.norm(vertices, axis=1)[:, None] assert_(isinstance(mcfit.fitted_parameters, dict)) assert_(isinstance(mcfit.fitted_parameters_vector, np.ndarray)) assert_(isinstance(mcfit.fod(vertices), np.ndarray)) assert_(isinstance(mcfit.fod_sh(), np.ndarray)) assert_(isinstance(mcfit.peaks_spherical(), np.ndarray)) assert_(isinstance(mcfit.peaks_cartesian(), np.ndarray)) assert_(isinstance(mcfit.mean_squared_error(data), np.ndarray)) assert_(isinstance(mcfit.R2_coefficient_of_determination(data), np.ndarray)) assert_(isinstance(mcfit.predict(), np.ndarray)) mcmod_sm = modeling_framework.MultiCompartmentSphericalMeanModel([stick]) mcfit_sm = mcmod_sm.fit(scheme, data) assert_(isinstance(mcfit_sm.fitted_parameters, dict)) assert_(isinstance(mcfit_sm.fitted_parameters_vector, np.ndarray)) assert_(isinstance(mcfit.mean_squared_error(data), np.ndarray)) assert_(isinstance(mcfit.R2_coefficient_of_determination(data), np.ndarray)) assert_(isinstance(mcfit.predict(), np.ndarray))
def test_stick_tortuous_zeppelin(): stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() stick_and_zeppelin = ( modeling_framework.MultiCompartmentModel( models=[stick, zeppelin]) ) stick_and_zeppelin.set_tortuous_parameter( 'G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1' ) stick_and_zeppelin.set_equal_parameter( 'C1Stick_1_mu', 'G2Zeppelin_1_mu' ) stick_and_zeppelin.set_equal_parameter( 'G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par' ) fitted_params = (stick_and_zeppelin.fit( scheme, camino_parallel.signal_attenuation[::20], ).fitted_parameters) mean_abs_error = np.mean( abs(fitted_params['partial_volume_0'].squeeze( ) - camino_parallel.fractions[::20])) assert_equal(mean_abs_error < 0.02, True)
def test_multi_compartment_fod_with_parametric_model( odi=0.15, mu=[0., 0.], lambda_iso=3e-9, lambda_par=1.7e-9, vf_intra=0.7): stick = cylinder_models.C1Stick() ball = gaussian_models.G1Ball() watsonstick = distribute_models.SD1WatsonDistributed( [stick]) mc_mod = modeling_framework.MultiCompartmentModel([watsonstick, ball]) sh_mod = modeling_framework.MultiCompartmentSphericalHarmonicsModel( [stick, ball]) sh_mod.set_fixed_parameter('G1Ball_1_lambda_iso', lambda_iso) sh_mod.set_fixed_parameter('C1Stick_1_lambda_par', lambda_par) simulation_parameters = mc_mod.parameters_to_parameter_vector( G1Ball_1_lambda_iso=lambda_iso, SD1WatsonDistributed_1_SD1Watson_1_mu=mu, SD1WatsonDistributed_1_C1Stick_1_lambda_par=lambda_par, SD1WatsonDistributed_1_SD1Watson_1_odi=odi, partial_volume_0=vf_intra, partial_volume_1=1 - vf_intra) data = mc_mod.simulate_signal(scheme, simulation_parameters) sh_fit = sh_mod.fit(scheme, data) vf_intra_estimated = sh_fit.fitted_parameters['partial_volume_0'] assert_almost_equal(vf_intra, vf_intra_estimated) predicted_signal = sh_fit.predict() assert_array_almost_equal(data, predicted_signal[0], 4)
def test_simple_ball_and_stick_optimization(): stick = cylinder_models.C1Stick() ball = gaussian_models.G1Ball() ball_and_stick = (modeling_framework.MultiCompartmentModel( models=[ball, stick])) gt_mu = np.clip(np.random.rand(2), .3, np.inf) gt_lambda_par = (np.random.rand() + 1.) * 1e-9 gt_lambda_iso = gt_lambda_par / 2. gt_partial_volume = 0.3 gt_parameter_vector = ball_and_stick.parameters_to_parameter_vector( C1Stick_1_lambda_par=gt_lambda_par, G1Ball_1_lambda_iso=gt_lambda_iso, C1Stick_1_mu=gt_mu, partial_volume_0=gt_partial_volume, partial_volume_1=1 - gt_partial_volume) E = ball_and_stick.simulate_signal(scheme, gt_parameter_vector) vf_rand = np.random.rand() ball_and_stick.set_initial_guess_parameter('C1Stick_1_lambda_par', (np.random.rand() + 1.) * 1e-9) ball_and_stick.set_initial_guess_parameter('G1Ball_1_lambda_iso', gt_lambda_par / 2.) ball_and_stick.set_initial_guess_parameter('C1Stick_1_mu', np.random.rand(2)) ball_and_stick.set_initial_guess_parameter('partial_volume_0', vf_rand) ball_and_stick.set_initial_guess_parameter('partial_volume_1', 1 - vf_rand) res = ball_and_stick.fit(scheme, E).fitted_parameters_vector assert_array_almost_equal(gt_parameter_vector, res.squeeze(), 2)
def test_multi_tissue_mc_model(): scheme = wu_minn_hcp_acquisition_scheme() ball = gaussian_models.G1Ball() cyl = cylinder_models.C1Stick() models = [ball, cyl] S0_responses = [1., 2.] mt_mc = modeling_framework.MultiCompartmentModel( models=models, S0_tissue_responses=S0_responses) mt_mc.set_fixed_parameter('C1Stick_1_lambda_par', 1.7e-9) mt_mc.set_fixed_parameter('G1Ball_1_lambda_iso', 3e-9) mt_mc.set_fixed_parameter('C1Stick_1_mu', [0., 0.]) param_dict = {'partial_volume_0': .5, 'partial_volume_1': .5} E = mt_mc.simulate_signal(scheme, param_dict) mt_mc_fit = mt_mc.fit(scheme, E) sig_fracts = mt_mc_fit.fitted_parameters vol_fracts = mt_mc_fit.fitted_multi_tissue_fractions vol_fracts_norm = mt_mc_fit.fitted_multi_tissue_fractions_normalized assert_almost_equal( sig_fracts['partial_volume_0'], vol_fracts['partial_volume_0'], 2) assert_almost_equal( sig_fracts['partial_volume_1'], vol_fracts['partial_volume_1'] * 2., 2) assert_almost_equal( vol_fracts_norm['partial_volume_0'], 2 / 3., 2) assert_almost_equal( vol_fracts_norm['partial_volume_1'], 1 / 3., 2)
def test_equivalence_csd_and_parametric_fod( odi=0.15, mu=[0., 0.], lambda_par=1.7e-9): stick = cylinder_models.C1Stick() watsonstick = distribute_models.SD1WatsonDistributed( [stick]) params = {'SD1Watson_1_odi': odi, 'SD1Watson_1_mu': mu, 'C1Stick_1_lambda_par': lambda_par} data = watsonstick(scheme, **params) sh_mod = modeling_framework.MultiCompartmentSphericalHarmonicsModel( [stick]) sh_mod.set_fixed_parameter('C1Stick_1_lambda_par', lambda_par) sh_fit = sh_mod.fit(scheme, data) fod = sh_fit.fod(sphere.vertices) watson = distributions.SD1Watson(mu=[0., 0.], odi=0.15) sf = watson(sphere.vertices) assert_array_almost_equal(fod[0], sf, 2) fitted_signal = sh_fit.predict() assert_array_almost_equal(data, fitted_signal[0], 4)
def test_laplacian_and_AI_with_regularization(odi=0.15, mu=[0., 0.], lambda_par=1.7e-9): stick = cylinder_models.C1Stick() watsonstick = distribute_models.SD1WatsonDistributed([stick]) params = { 'SD1Watson_1_odi': odi, 'SD1Watson_1_mu': mu, 'C1Stick_1_lambda_par': lambda_par } data = watsonstick(scheme, **params) sh_mod = modeling_framework.MultiCompartmentSphericalHarmonicsModel( [stick]) sh_mod.set_fixed_parameter('C1Stick_1_lambda_par', lambda_par) for solver in ['csd_tournier07', 'csd_cvxpy']: sh_fit = sh_mod.fit(scheme, data, solver=solver, lambda_lb=0.) sh_fit_reg = sh_mod.fit(scheme, data, solver=solver, lambda_lb=1e-3) ai = sh_fit.anisotropy_index() lb = sh_fit.norm_of_laplacian_fod() ai_reg = sh_fit_reg.anisotropy_index() lb_reg = sh_fit_reg.norm_of_laplacian_fod() assert_(ai > ai_reg) assert_(lb > lb_reg)
def test_set_fixed_parameter_raises(): cyl = cylinder_models.C1Stick() distcyl = distribute_models.SD1WatsonDistributed([cyl]) assert_raises(ValueError, distcyl.set_fixed_parameter, 'SD1Watson_1_odi', [1]) assert_raises(ValueError, distcyl.set_fixed_parameter, 'SD1Watson_1_mu', [1]) assert_raises(ValueError, distcyl.set_fixed_parameter, 'blabla', [1])
def test_MIX_fitting_singlemodel(): stick = cylinder_models.C1Stick() stick_mod = (modeling_framework.MultiCompartmentModel(models=[stick])) parameter_vector = stick_mod.parameters_to_parameter_vector( C1Stick_1_mu=(np.pi / 2., np.pi / 2.), C1Stick_1_lambda_par=1.7e-9) E = stick_mod.simulate_signal(scheme, parameter_vector) fit = stick_mod.fit(scheme, E, solver='mix').fitted_parameters_vector assert_array_almost_equal(abs(fit).squeeze(), parameter_vector, 2)
def test_stick_and_tortuous_zeppelin_to_spherical_mean_fit(): """ this is a more complex test to see if we can generate 3D data using a stick and zeppelin model, where we assume the perpendicular diffusivity is linked to the parallel diffusivity and volume fraction using tortuosity. We then use the spherical mean models of stick and zeppelin with the same tortuosity assumption to fit the 3D data (and estimating the spherical mean of each shell). The final check is whether the parallel diffusivity and volume fraction between the 3D and spherical mean models correspond.""" gt_mu = np.clip(np.random.rand(2), .3, np.inf) gt_lambda_par = (np.random.rand() + 1.) * 1e-9 gt_partial_volume = 0.3 stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() stick_and_zeppelin = (modeling_framework.MultiCompartmentModel( models=[stick, zeppelin])) stick_and_zeppelin.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1') stick_and_zeppelin.set_equal_parameter('C1Stick_1_mu', 'G2Zeppelin_1_mu') stick_and_zeppelin.set_equal_parameter('C1Stick_1_lambda_par', 'G2Zeppelin_1_lambda_par') gt_parameter_vector = (stick_and_zeppelin.parameters_to_parameter_vector( C1Stick_1_lambda_par=gt_lambda_par, C1Stick_1_mu=gt_mu, partial_volume_0=gt_partial_volume, partial_volume_1=1 - gt_partial_volume)) E = stick_and_zeppelin.simulate_signal(scheme, gt_parameter_vector) # now we make the stick and zeppelin spherical mean model and check if the # same lambda_par and volume fraction result as the 3D generated data. stick_and_tortuous_zeppelin_sm = ( modeling_framework.MultiCompartmentSphericalMeanModel( models=[stick, zeppelin])) stick_and_tortuous_zeppelin_sm.set_tortuous_parameter( 'G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1') stick_and_tortuous_zeppelin_sm.set_equal_parameter( 'G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') res_sm = stick_and_tortuous_zeppelin_sm.fit(scheme, E).fitted_parameters_vector assert_array_almost_equal(np.r_[gt_lambda_par, gt_partial_volume], res_sm.squeeze()[:-1], 2)
def test_wrong_number_S0_tissue_responses_raises(): cyl = cylinder_models.C1Stick() mods = [cyl] S0s = [1., 1.] assert_raises(ValueError, modeling_framework.MultiCompartmentModel, mods, S0s) assert_raises(ValueError, modeling_framework.MultiCompartmentSphericalMeanModel, mods, S0s) assert_raises(ValueError, modeling_framework.MultiCompartmentSphericalHarmonicsModel, mods, S0s)
def test_raise_mix_with_tortuosity_in_mcmodel(): scheme = wu_minn_hcp_acquisition_scheme() stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() mc = modeling_framework.MultiCompartmentModel([stick, zeppelin]) mc.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1') data = stick(scheme, lambda_par=1.7e-9, mu=[0., 0.]) assert_raises(ValueError, mc.fit, scheme, data, solver='mix')
def test_multi_tissue_tortuosity_no_s0(): stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() ball = gaussian_models.G1Ball() model = modeling_framework.MultiCompartmentModel( models=[stick, zeppelin, ball]) model.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1', True) tort = model.parameter_links[0][2] s0ic, s0ec = tort.S0_intra, tort.S0_extra assert_(s0ic == 1 and s0ec == 1)
def test_multi_dimensional_x0(): stick = cylinder_models.C1Stick() ball = gaussian_models.G1Ball() ball_and_stick = ( modeling_framework.MultiCompartmentModel( models=[ball, stick],) ) gt_lambda_par = (np.random.rand() + 1.) * 1e-9 gt_lambda_iso = gt_lambda_par / 2. gt_partial_volume = 0.3 gt_mu_array = np.empty((10, 10, 2)) # I'm putting the orientation of the stick all over the sphere. for i, mu1 in enumerate(np.linspace(0, np.pi, 10)): for j, mu2 in enumerate(np.linspace(-np.pi, np.pi, 10)): gt_mu_array[i, j] = np.r_[mu1, mu2] gt_parameter_vector = ( ball_and_stick.parameters_to_parameter_vector( C1Stick_1_lambda_par=gt_lambda_par, G1Ball_1_lambda_iso=gt_lambda_iso, C1Stick_1_mu=gt_mu_array, partial_volume_0=gt_partial_volume, partial_volume_1=1 - gt_partial_volume) ) E_array = ball_and_stick.simulate_signal( scheme, gt_parameter_vector) ball_and_stick.set_initial_guess_parameter( 'C1Stick_1_lambda_par', gt_lambda_par) ball_and_stick.set_initial_guess_parameter( 'G1Ball_1_lambda_iso', gt_lambda_iso) ball_and_stick.set_initial_guess_parameter( 'C1Stick_1_mu', gt_mu_array) ball_and_stick.set_initial_guess_parameter( 'partial_volume_0', gt_partial_volume) ball_and_stick.set_initial_guess_parameter( 'partial_volume_1', 1 - gt_partial_volume) # I'm giving a voxel-dependent initial condition with gt_mu_array res = ball_and_stick.fit(scheme, E_array).fitted_parameters_vector # optimization should stop immediately as I'm giving the ground truth. assert_equal(np.all(np.ravel(res - gt_parameter_vector) == 0.), True) # and the parameter vector dictionaries of the results and x0 should also # be the same. res_parameters = ball_and_stick.parameter_vector_to_parameters(res) x0_parameters = ball_and_stick.parameter_vector_to_parameters( gt_parameter_vector) for key in res_parameters.keys(): assert_array_equal(x0_parameters[key], res_parameters[key])
def test_parametric_fod_spherical_mean_model(): stick = cylinder_models.C1Stick() watsonstick = distribute_models.SD1WatsonDistributed([stick]) params = {} for parameter, card, in watsonstick.parameter_cardinality.items(): params[parameter] = (np.random.rand(card) * watsonstick.parameter_scales[parameter]) data = np.atleast_2d(watsonstick(scheme, **params)) stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() smt = modeling_framework.MultiCompartmentSphericalMeanModel( [stick, zeppelin]) smt.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1') smt.set_equal_parameter('G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') smt_fit = smt.fit(scheme, data) assert_raises(ValueError, smt_fit.return_parametric_fod_model, Ncompartments=1.5) assert_raises(ValueError, smt_fit.return_parametric_fod_model, Ncompartments=0) assert_raises(ValueError, smt_fit.return_parametric_fod_model, distribution='bla') for distribution_name in ['watson', 'bingham']: fod_model = smt_fit.return_parametric_fod_model( distribution=distribution_name, Ncompartments=1) fitted_fod_model = fod_model.fit(scheme, data) assert_(isinstance(fitted_fod_model.fitted_parameters, dict))
def test_equivalence_sh_distributed_mc_with_mcsh(): """ We test if we can input a Watson-distributed zeppelin and stick into an SD3SphericalHarmonicsDistributedModel in an MC-model, and compare it with an MCSH model with the same watson distribution as a kernel. """ stick = cylinder_models.C1Stick() zep = gaussian_models.G2Zeppelin() mck_dist = distribute_models.SD1WatsonDistributed([stick, zep]) mck_dist.set_equal_parameter('G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') mck_dist.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'G2Zeppelin_1_lambda_par', 'partial_volume_0') mcsh = modeling_framework.MultiCompartmentSphericalHarmonicsModel( models=[mck_dist], sh_order=8) mc = modeling_framework.MultiCompartmentModel([ distribute_models.SD3SphericalHarmonicsDistributed([mck_dist], sh_order=8) ]) lambda_par = 0. odi = .02 sh_coeff = np.ones(45) sh_coeff[0] = 1 / (2 * np.sqrt(np.pi)) pv0 = .3 params_mcsh = { 'SD1WatsonDistributed_1_partial_volume_0': pv0, 'SD1WatsonDistributed_1_G2Zeppelin_1_lambda_par': lambda_par, 'SD1WatsonDistributed_1_SD1Watson_1_odi': odi, 'sh_coeff': sh_coeff } basemod = 'SD3SphericalHarmonicsDistributed_1_' params_mc = { basemod + 'SD1WatsonDistributed_1_partial_volume_0': pv0, basemod + 'SD1WatsonDistributed_1_G2Zeppelin_1_lambda_par': lambda_par, basemod + 'SD1WatsonDistributed_1_SD1Watson_1_odi': odi, basemod + 'SD3SphericalHarmonics_1_sh_coeff': sh_coeff } E_mcsh = mcsh.simulate_signal(scheme, params_mcsh) E_mc = mc.simulate_signal(scheme, params_mc) np.testing.assert_array_almost_equal(E_mcsh, E_mc)
def test_simple_stick_optimization(): stick = cylinder_models.C1Stick() gt_mu = np.random.rand(2) gt_lambda_par = (np.random.rand() + 1.) * 1e-9 stick_model = modeling_framework.MultiCompartmentModel(models=[stick]) gt_parameter_vector = stick_model.parameters_to_parameter_vector( C1Stick_1_lambda_par=gt_lambda_par, C1Stick_1_mu=gt_mu) E = stick_model.simulate_signal(scheme, gt_parameter_vector) stick_model.set_initial_guess_parameter('C1Stick_1_lambda_par', (np.random.rand() + 1.) * 1e-9) stick_model.set_initial_guess_parameter('C1Stick_1_mu', np.random.rand(2)) res = stick_model.fit(scheme, E).fitted_parameters_vector assert_array_almost_equal(gt_parameter_vector, res.squeeze(), 2)
def test_construction_observation_matrix( odi=0.15, mu=[0., 0.], lambda_par=1.7e-9, lmax=8): stick = cylinder_models.C1Stick(lambda_par=lambda_par) watsonstick = distribute_models.SD1WatsonDistributed( [stick]) params = {'SD1Watson_1_odi': odi, 'SD1Watson_1_mu': mu, 'C1Stick_1_lambda_par': lambda_par} data = watsonstick(scheme, **params) watson = distributions.SD1Watson(mu=mu, odi=odi) sh_watson = watson.spherical_harmonics_representation(lmax) stick_rh = stick.rotational_harmonics_representation(scheme) A = construct_model_based_A_matrix(scheme, stick_rh, lmax) data_approximated = A.dot(sh_watson) np.testing.assert_array_almost_equal(data_approximated, data, 4)
def test_bingham_dispersed_stick_tortuous_zeppelin(): stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() bingham_bundle = distribute_models.SD2BinghamDistributed( models=[stick, zeppelin]) bingham_bundle.set_tortuous_parameter( 'G2Zeppelin_1_lambda_perp', 'G2Zeppelin_1_lambda_par', 'partial_volume_0' ) bingham_bundle.set_equal_parameter( 'G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') bingham_bundle.set_fixed_parameter( 'G2Zeppelin_1_lambda_par', 1.7e-9) bingham_bundle.set_fixed_parameter( 'SD2Bingham_1_mu', [0., 0.]) mc_bingham = ( modeling_framework.MultiCompartmentModel( models=[bingham_bundle]) ) beta0 = camino_dispersed.beta > 0 diff17 = camino_dispersed.diffusivities == 1.7e-9 mask = np.all([beta0, diff17], axis=0) E_watson = camino_dispersed.signal_attenuation[mask] fractions_watson = camino_dispersed.fractions[mask] fitted_params = (mc_bingham.fit(scheme, E_watson[::200]).fitted_parameters ) mean_abs_error = np.mean( abs(fitted_params['SD2BinghamDistributed_1_partial_volume_0'].squeeze( ) - fractions_watson[::200])) assert_equal(mean_abs_error < 0.035, True)
def test_spherical_convolution_watson_sh(sh_order=4): sphere = get_sphere('symmetric724') n = sphere.vertices bval = np.tile(1e9, len(n)) scheme = acquisition_scheme_from_bvalues(bval, n, delta, Delta) indices_sphere_orientations = np.arange(sphere.vertices.shape[0]) np.random.shuffle(indices_sphere_orientations) mu_index = indices_sphere_orientations[0] mu_watson = sphere.vertices[mu_index] mu_watson_sphere = utils.cart2sphere(mu_watson)[1:] watson = distributions.SD1Watson(mu=mu_watson_sphere, odi=.3) f_sf = watson(n=sphere.vertices) f_sh = sf_to_sh(f_sf, sphere, sh_order) lambda_par = 2e-9 stick = cylinder_models.C1Stick(mu=[0, 0], lambda_par=lambda_par) k_sf = stick(scheme) sh_matrix, m, n = real_sym_sh_mrtrix(sh_order, sphere.theta, sphere.phi) sh_matrix_inv = np.linalg.pinv(sh_matrix) k_sh = np.dot(sh_matrix_inv, k_sf) k_rh = k_sh[m == 0] fk_convolved_sh = sh_convolution(f_sh, k_rh) fk_convolved_sf = sh_to_sf(fk_convolved_sh, sphere, sh_order) # assert if spherical mean is the same between kernel and convolved kernel assert_almost_equal(abs(np.mean(k_sf) - np.mean(fk_convolved_sf)), 0., 2) # assert if the lowest signal attenuation (E(b,n)) is orientation along # the orientation of the watson distribution. min_position = np.argmin(fk_convolved_sf) if min_position == mu_index: assert_equal(min_position, mu_index) else: # then it's the opposite direction sphere_positions = np.arange(sphere.vertices.shape[0]) opposite_index = np.all( np.round(sphere.vertices - mu_watson, 2) == 0, axis=1 ) min_position_opposite = sphere_positions[opposite_index] assert_equal(min_position_opposite, mu_index)
def test_simple_ball_and_stick_optimization_vf_fixed(): stick = cylinder_models.C1Stick() ball = gaussian_models.G1Ball() ball_and_stick = ( modeling_framework.MultiCompartmentModel( models=[ball, stick]) ) gt_mu = np.clip(np.random.rand(2), .3, np.inf) gt_lambda_par = (np.random.rand() + 1.) * 1e-9 gt_lambda_iso = gt_lambda_par / 2. gt_partial_volume = 0.3 gt_parameter_vector = ball_and_stick.parameters_to_parameter_vector( C1Stick_1_lambda_par=gt_lambda_par, G1Ball_1_lambda_iso=gt_lambda_iso, C1Stick_1_mu=gt_mu, partial_volume_0=gt_partial_volume, partial_volume_1=1 - gt_partial_volume ) E = ball_and_stick.simulate_signal( scheme, gt_parameter_vector) E2d = np.array([E, E]) vf_rand = np.random.rand() ball_and_stick.set_fixed_parameter( 'partial_volume_0', np.r_[vf_rand, vf_rand]) ball_and_stick.set_fixed_parameter( 'partial_volume_1', np.r_[1 - vf_rand, 1 - vf_rand]) ball_and_stick.set_initial_guess_parameter( 'C1Stick_1_lambda_par', (np.random.rand() + 1.) * 1e-9) ball_and_stick.set_initial_guess_parameter( 'G1Ball_1_lambda_iso', gt_lambda_par / 2.) ball_and_stick.set_initial_guess_parameter( 'C1Stick_1_mu', np.random.rand(2)) vf_fitted = ball_and_stick.fit( scheme, E2d).fitted_parameters['partial_volume_0'][0] assert_equal(vf_fitted, vf_rand)
def test_spherical_mean_stick_tortuous_zeppelin(): stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() mc_mdi = modeling_framework.MultiCompartmentSphericalMeanModel( models=[stick, zeppelin]) mc_mdi.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0', 'partial_volume_1') mc_mdi.set_equal_parameter('G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') fitted_params_par = ( mc_mdi.fit( scheme, camino_parallel.signal_attenuation[::20] ).fitted_parameters ) fitted_params_disp = ( mc_mdi.fit( scheme, camino_dispersed.signal_attenuation[::40] ).fitted_parameters ) mean_abs_error_par = np.mean( abs(fitted_params_par['partial_volume_0'].squeeze( ) - camino_parallel.fractions[::20])) mean_abs_error_disp = np.mean( abs(fitted_params_disp['partial_volume_0'].squeeze( ) - camino_dispersed.fractions[::40])) assert_equal(mean_abs_error_par < 0.02, True) assert_equal(mean_abs_error_disp < 0.02, True)
def main(): # Base Path of all given files for All models are wrong base_path = r'/nfs/masi/nathv/memento_2020/all_models_are_wrong/files_project_2927_session_1436090/' base_path = os.path.normpath(base_path) # Just dealing with PGSE for now pgse_acq_params_path = os.path.join(base_path, 'PGSE_AcqParams.txt') pgse_signal_path = os.path.join(base_path, 'PGSE_Simulations.txt') # Read files via Numpy pgse_acq_params = np.loadtxt(pgse_acq_params_path) pgse_signal_data = np.loadtxt(pgse_signal_path) pgse_example_sub_diff = np.loadtxt( '/nfs/masi/nathv/memento_2020/all_models_are_wrong/files_project_2927_session_1436090/2-AllModelsAreWrong-ExampleSubmissions/DIffusivity-ExampleSubmission3/PGSE.txt' ) pgse_example_sub_volfrac = np.loadtxt( '/nfs/masi/nathv/memento_2020/all_models_are_wrong/files_project_2927_session_1436090/2-AllModelsAreWrong-ExampleSubmissions/VolumeFraction-ExampleSubmission3/PGSE.txt' ) # Transpose the Signal data pgse_signal_data = pgse_signal_data.transpose() # Dissect the acquisition parameters to form the Acquisition Table bvecs = pgse_acq_params[:, 1:4] bvals = pgse_acq_params[:, 6] * 1e6 grad_str = pgse_acq_params[:, 0] small_del = pgse_acq_params[:, 4] big_del = pgse_acq_params[:, 5] subj_Acq_Scheme = acquisition_scheme_from_bvalues(bvals, bvecs, delta=small_del, Delta=big_del) print(subj_Acq_Scheme.print_acquisition_info) #### NODDI Watson #### ball = gaussian_models.G1Ball() stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() bingham_dispersed_bundle = SD2BinghamDistributed(models=[stick, zeppelin]) bingham_dispersed_bundle.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0') bingham_dispersed_bundle.set_equal_parameter('G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') bingham_dispersed_bundle.set_fixed_parameter('G2Zeppelin_1_lambda_par', 1.7e-9) NODDI_bingham_mod = MultiCompartmentModel( models=[ball, bingham_dispersed_bundle]) NODDI_bingham_mod.set_fixed_parameter('G1Ball_1_lambda_iso', 3e-9) print('Fitting the NODDI Model ...') fit_start_time = time.time() NODDI_fit_hcp = NODDI_bingham_mod.fit(subj_Acq_Scheme, pgse_signal_data, use_parallel_processing=True, number_of_processors=8) fit_end_time = time.time() print('Model Fitting Completed ... Time Taken to fit: {}'.format( fit_end_time - fit_start_time)) fit_time = np.int(np.round(fit_end_time - fit_start_time)) sub_1_pv0 = NODDI_fit_hcp.fitted_parameters['partial_volume_0'] sub_2_pv1 = NODDI_fit_hcp.fitted_parameters['partial_volume_1'] np.savetxt('noddi_bingham_pv0.txt', sub_1_pv0) np.savetxt('noddi_bingham_pv1.txt', sub_2_pv1) print('Debug here') return None
def test_set_fixed_parameter_raises(): cyl = cylinder_models.C1Stick() mod = modeling_framework.MultiCompartmentModel([cyl]) assert_raises(ValueError, mod.set_fixed_parameter, 'C1Stick_1_mu', [1]) assert_raises(ValueError, mod.set_fixed_parameter, 'blabla', [1])
def main(): #Argparse Stuff parser = argparse.ArgumentParser(description='subject_id') parser.add_argument('--subject_id', type=str, default='135124') args = parser.parse_args() # Plot Save Path base_plot_path = r'/nfs/masi/nathv/py_src_code_2020/dmipy_model_pictures' base_plot_path = os.path.normpath(base_plot_path) # Method Saving Paths # TODO KARTHIK base_save_path = r'/root/hcp_results' base_save_path = os.path.normpath(base_save_path) if os.path.exists(base_save_path)==False: os.mkdir(base_save_path) # Create base saving path for Method # TODO The Method name can be made an argument later on method_name = 'NODDI_WATSON' # Base HCP Data Path # TODO KARTHIK This is where we hard set HCP's Data Path base_data_path = r'/root/local_mount/data' base_data_path = os.path.normpath(base_data_path) # Subject ID subj_ID = args.subject_id # Subject Save Path subj_save_path = os.path.join(base_save_path, subj_ID) if os.path.exists(subj_save_path)==False: os.mkdir(subj_save_path) # TODO For later the subject data, bval and bvec reading part can be put inside a function subj_data_path = os.path.join(base_data_path, subj_ID, 'T1w', 'Diffusion') # Read the Nifti file, bvals and bvecs subj_bvals = np.loadtxt(os.path.join(subj_data_path, 'bvals')) subj_bvecs = np.loadtxt(os.path.join(subj_data_path, 'bvecs')) all_bvals = subj_bvals * 1e6 all_bvecs = np.transpose(subj_bvecs) subj_Acq_Scheme = acquisition_scheme_from_bvalues(all_bvals, all_bvecs) print(subj_Acq_Scheme.print_acquisition_info) print('Loading the Nifti Data ...') data_start_time = time.time() subj_babel_object = nib.load(os.path.join(subj_data_path, 'data.nii.gz')) subj_data = subj_babel_object.get_fdata() axial_slice_data = subj_data[50:65, 50:65, 60:62, :] data_end_time = time.time() data_time = np.int(np.round(data_end_time - data_start_time)) print('Data Loaded ... Time Taken: {}'.format(data_end_time - data_start_time)) print('The Data Dimensions are: {}'.format(subj_data.shape)) #### NODDI Watson #### ball = gaussian_models.G1Ball() stick = cylinder_models.C1Stick() zeppelin = gaussian_models.G2Zeppelin() watson_dispersed_bundle = SD1WatsonDistributed(models=[stick, zeppelin]) watson_dispersed_bundle.set_tortuous_parameter('G2Zeppelin_1_lambda_perp', 'C1Stick_1_lambda_par', 'partial_volume_0') watson_dispersed_bundle.set_equal_parameter('G2Zeppelin_1_lambda_par', 'C1Stick_1_lambda_par') watson_dispersed_bundle.set_fixed_parameter('G2Zeppelin_1_lambda_par', 1.7e-9) NODDI_mod = MultiCompartmentModel(models=[ball, watson_dispersed_bundle]) NODDI_mod.set_fixed_parameter('G1Ball_1_lambda_iso', 3e-9) print('Fitting the NODDI Model ...') fit_start_time = time.time() NODDI_fit_hcp = NODDI_mod.fit(subj_Acq_Scheme, subj_data, mask=subj_data[..., 0] > 0, use_parallel_processing=True, number_of_processors=32) fit_end_time = time.time() print('Model Fitting Completed ... Time Taken to fit: {}'.format(fit_end_time - fit_start_time)) fit_time = np.int(np.round(fit_end_time - fit_start_time)) fitted_parameters = NODDI_fit_hcp.fitted_parameters para_Names_list = [] for key, value in fitted_parameters.items(): para_Names_list.append(key) ### Nifti Saving Part # Create a directory per subject subj_method_save_path = os.path.join(subj_save_path, method_name) if os.path.exists(subj_method_save_path)==False: os.mkdir(subj_method_save_path) # Retrieve the affine from already Read Nifti file to form the header affine = subj_babel_object.affine # Loop over fitted parameters name list for each_fitted_parameter in para_Names_list: new_img = nib.Nifti1Image(fitted_parameters[each_fitted_parameter], affine) # Form the file path f_name = each_fitted_parameter + '.nii.gz' param_file_path = os.path.join(subj_method_save_path, f_name) nib.save(new_img, param_file_path) return None
def main(): #Argparse Stuff parser = argparse.ArgumentParser(description='subject_id') parser.add_argument('--subject_id', type=str, default='135124') args = parser.parse_args() # Plot Save Path base_plot_path = r'/nfs/masi/nathv/py_src_code_2020/dmipy_model_pictures' base_plot_path = os.path.normpath(base_plot_path) # Method Saving Paths # TODO KARTHIK base_save_path = r'/root/hcp_results' base_save_path = os.path.normpath(base_save_path) if os.path.exists(base_save_path) == False: os.mkdir(base_save_path) # Create base saving path for Method # TODO The Method name can be made an argument later on method_name = 'VERDICT' # Base HCP Data Path # TODO KARTHIK This is where we hard set HCP's Data Path base_data_path = r'/root/local_mount/data' base_data_path = os.path.normpath(base_data_path) # Subject ID subj_ID = args.subject_id # Subject Save Path subj_save_path = os.path.join(base_save_path, subj_ID) if os.path.exists(subj_save_path) == False: os.mkdir(subj_save_path) # TODO For later the subject data, bval and bvec reading part can be put inside a function subj_data_path = os.path.join(base_data_path, subj_ID, 'T1w', 'Diffusion') # Read the Nifti file, bvals and bvecs subj_bvals = np.loadtxt(os.path.join(subj_data_path, 'bvals')) subj_bvecs = np.loadtxt(os.path.join(subj_data_path, 'bvecs')) all_bvals = subj_bvals * 1e6 all_bvecs = np.transpose(subj_bvecs) subj_Acq_Scheme = acquisition_scheme_from_bvalues(all_bvals, all_bvecs, delta=10.6 * 1e-3, Delta=43.1 * 1e-3, TE=89.5 * 1e-3) print(subj_Acq_Scheme.print_acquisition_info) print('Loading the Nifti Data ...') data_start_time = time.time() subj_babel_object = nib.load(os.path.join(subj_data_path, 'data.nii.gz')) subj_data = subj_babel_object.get_fdata() #axial_slice_data = subj_data[55:60, 65:70, 60:62, :] mask_babel_object = nib.load( os.path.join(subj_data_path, 'nodif_brain_mask.nii.gz')) mask_data = mask_babel_object.get_fdata() data_end_time = time.time() data_time = np.int(np.round(data_end_time - data_start_time)) print('Data Loaded ... Time Taken: {}'.format(data_end_time - data_start_time)) print('The Data Dimensions are: {}'.format(subj_data.shape)) #### Verdict Begin #### sphere = sphere_models.S4SphereGaussianPhaseApproximation( diffusion_constant=0.9e-9) ball = gaussian_models.G1Ball() stick = cylinder_models.C1Stick() verdict_mod = MultiCompartmentModel(models=[sphere, ball, stick]) verdict_mod.set_fixed_parameter('G1Ball_1_lambda_iso', 0.9e-9) verdict_mod.set_parameter_optimization_bounds('C1Stick_1_lambda_par', [3.05e-9, 10e-9]) print('Fitting the Verdict Model ...') fit_start_time = time.time() mcdmi_fit = verdict_mod.fit(subj_Acq_Scheme, subj_data, mask=mask_data, solver='mix', use_parallel_processing=True, number_of_processors=64) fit_end_time = time.time() print('Model Fitting Completed ... Time Taken to fit: {}'.format( fit_end_time - fit_start_time)) fit_time = np.int(np.round(fit_end_time - fit_start_time)) fitted_parameters = mcdmi_fit.fitted_parameters # Get List of Estimated Parameter Names para_Names_list = [] for key, value in fitted_parameters.items(): para_Names_list.append(key) ### Nifti Saving Part # Create a directory per subject subj_method_save_path = os.path.join(subj_save_path, method_name) if os.path.exists(subj_method_save_path) == False: os.mkdir(subj_method_save_path) # Retrieve the affine from already Read Nifti file to form the header affine = subj_babel_object.affine # Loop over fitted parameters name list for each_fitted_parameter in para_Names_list: new_img = nib.Nifti1Image(fitted_parameters[each_fitted_parameter], affine) # Form the file path f_name = each_fitted_parameter + '.nii.gz' param_file_path = os.path.join(subj_method_save_path, f_name) nib.save(new_img, param_file_path) return None