def test_Wrotate_single_fiber(): # Rotate the kurtosis tensor of single fiber simulate to the diffusion # tensor diagonal and check that is equal to the kurtosis tensor of the # same single fiber simulated directly to the x-axis # Define single fiber simulate mevals = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) fie = 0.49 frac = [fie*100, (1 - fie)*100] # simulate single fiber not aligned to the x-axis theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) evals, evecs = decompose_tensor(from_lower_triangular(dt)) kt_rotated = dki.Wrotate(kt, evecs) # Now coordinate system has the DT diagonal aligned to the x-axis # Reference simulation in which DT diagonal is directly aligned to the # x-axis angles = (90, 0), (90, 0) signal, dt_ref, kt_ref = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) assert_array_almost_equal(kt_rotated, kt_ref)
def test_Wrotate_crossing_fibers(): # Test 2 - simulate crossing fibers intersecting at 70 degrees. # In this case, diffusion tensor principal eigenvector will be aligned in # the middle of the crossing fibers. Thus, after rotating the kurtosis # tensor, this will be equal to a kurtosis tensor simulate of crossing # fibers both deviating 35 degrees from the x-axis. Moreover, we know that # crossing fibers will be aligned to the x-y plane, because the smaller # diffusion eigenvalue, perpendicular to both crossings fibers, will be # aligned to the z-axis. # Simulate the crossing fiber angles = [(90, 30), (90, 30), (20, 30), (20, 30)] fie = 0.49 frac = [fie*50, (1-fie) * 50, fie*50, (1-fie) * 50] mevals = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087], [0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) evals, evecs = decompose_tensor(from_lower_triangular(dt)) kt_rotated = dki.Wrotate(kt, evecs) # Now coordinate system has diffusion tensor diagonal aligned to the x-axis # Simulate the reference kurtosis tensor angles = [(90, 35), (90, 35), (90, -35), (90, -35)] signal, dt, kt_ref = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # Compare rotated with the reference assert_array_almost_equal(kt_rotated, kt_ref)
def test_kurtosis_fa(): # KFA = sqrt(4/5) if kurtosis is non-zero only in one direction mevals = np.array([[0.002, 0, 0], [0.003, 0, 0]]) angles = [(45, 0), (45, 0)] fie = 0.5 frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) dkiF.kfa assert_almost_equal(dkiF.kfa, np.sqrt(4 / 5)) # KFA = sqrt(13/5) for systems of two tensors with same AD and RD values # See appendix of Gleen et al., 2015 Quantitative assessment of diffusional # kurtosis anisotropy. NMR Biomed 28; 448-459. doi:10.1002/nbm.3271 mevals = np.array([[0.003, 0.001, 0.001], [0.003, 0.001, 0.001]]) angles = [(40, -10), (-45, 10)] fie = 0.5 frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) dkiF.kfa assert_almost_equal(dkiF.kfa, np.sqrt(13 / 15)) # KFA = 0 if MKT = 0 mevals = np.array([[0.003, 0.001, 0.001], [0.003, 0.001, 0.001]]) angles = [(40, -10), (40, -10)] fie = 0.5 frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) dkiF.kfa assert_almost_equal(dkiF.kfa, 0)
def test_DKI_simulations_aligned_fibers(): """ Testing DKI simulations when aligning the same fiber to different axis. If biological parameters don't change, kt[0] of a fiber aligned to axis x has to be equal to kt[1] of a fiber aligned to the axis y and equal to kt[2] of a fiber aligned to axis z. The same is applicable for dt """ # Defining parameters based on Neto Henriques et al., 2015. NeuroImage 111 mevals = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) # Intra-cellular # Extra-cellular frac = [49, 51] # Compartment volume fraction # axis x angles = [(90, 0), (90, 0)] signal_fx, dt_fx, kt_fx = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac) # axis y angles = [(90, 90), (90, 90)] signal_fy, dt_fy, kt_fy = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac) # axis z angles = [(0, 0), (0, 0)] signal_fz, dt_fz, kt_fz = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac) assert_array_equal([kt_fx[0], kt_fx[1], kt_fx[2]], [kt_fy[1], kt_fy[0], kt_fy[2]]) assert_array_equal([kt_fx[0], kt_fx[1], kt_fx[2]], [kt_fz[2], kt_fz[0], kt_fz[1]]) assert_array_equal([dt_fx[0], dt_fx[2], dt_fx[5]], [dt_fy[2], dt_fy[0], dt_fy[5]]) assert_array_equal([dt_fx[0], dt_fx[2], dt_fx[5]], [dt_fz[5], dt_fz[0], dt_fz[2]]) # testing S signal along axis x, y and z bvals = np.array([0, 0, 0, 1000, 1000, 1000, 2000, 2000, 2000]) bvecs = np.asarray( [[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1]] ) gtab_axis = gradient_table(bvals, bvecs) # axis x S_fx = DKI_signal(gtab_axis, dt_fx, kt_fx, S0=100) assert_array_almost_equal(S_fx[0:3], [100, 100, 100]) # test S f0r b=0 # axis y S_fy = DKI_signal(gtab_axis, dt_fy, kt_fy, S0=100) assert_array_almost_equal(S_fy[0:3], [100, 100, 100]) # test S f0r b=0 # axis z S_fz = DKI_signal(gtab_axis, dt_fz, kt_fz, S0=100) assert_array_almost_equal(S_fz[0:3], [100, 100, 100]) # test S f0r b=0 # test S for b = 1000 assert_array_almost_equal([S_fx[3], S_fx[4], S_fx[5]], [S_fy[4], S_fy[3], S_fy[5]]) assert_array_almost_equal([S_fx[3], S_fx[4], S_fx[5]], [S_fz[5], S_fz[3], S_fz[4]]) # test S for b = 2000 assert_array_almost_equal([S_fx[6], S_fx[7], S_fx[8]], [S_fy[7], S_fy[6], S_fy[8]]) assert_array_almost_equal([S_fx[6], S_fx[7], S_fx[8]], [S_fz[8], S_fz[6], S_fz[7]])
def test_DKI_crossing_fibers_simulations(): """ Testing DKI simulations of a crossing fiber """ # two fiber not aligned to planes x = 0, y = 0, or z = 0 mevals = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087], [0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) angles = [(80, 10), (80, 10), (20, 30), (20, 30)] fie = 0.49 frac = [fie*50, (1 - fie)*50, fie*50, (1 - fie)*50] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # in this simulations dt and kt cannot have zero elements for i in range(len(dt)): assert dt[i] != 0 for i in range(len(kt)): assert kt[i] != 0 # test S, dt and kt relative to the expected values computed from another # DKI package - UDKI (Neto Henriques et al., 2015) dt_ref = [1.0576161e-3, 0.1292542e-3, 0.4786179e-3, 0.2667081e-3, 0.1136643e-3, 0.9888660e-3] kt_ref = [2.3529944, 0.8226448, 2.3011221, 0.2017312, -0.0437535, 0.0404011, 0.0355281, 0.2449859, 0.2157668, 0.3495910, 0.0413366, 0.3461519, -0.0537046, 0.0133414, -0.017441] assert_array_almost_equal(dt, dt_ref) assert_array_almost_equal(kt, kt_ref) assert_array_almost_equal(signal, dki_signal(gtab_2s, dt_ref, kt_ref, S0=1., snr=None), decimal=5)
def test_DKI_crossing_fibers_simulations(): """ Testing DKI simulations of a crossing fiber """ # two fiber not aligned to planes x = 0, y = 0, or z = 0 mevals = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087], [0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) angles = [(80, 10), (80, 10), (20, 30), (20, 30)] fie = 0.49 frac = [fie*50, (1 - fie)*50, fie*50, (1 - fie)*50] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # in this simulations dt and kt cannot have zero elements for i in range(len(dt)): assert dt[i] != 0 for i in range(len(kt)): assert kt[i] != 0 # test S, dt and kt relative to the expected values computed from another # DKI package - UDKI (Neto Henriques et al., 2015) dt_ref = [1.0576161e-3, 0.1292542e-3, 0.4786179e-3, 0.2667081e-3, 0.1136643e-3, 0.9888660e-3] kt_ref = [2.3529944, 0.8226448, 2.3011221, 0.2017312, -0.0437535, 0.0404011, 0.0355281, 0.2449859, 0.2157668, 0.3495910, 0.0413366, 0.3461519, -0.0537046, 0.0133414, -0.017441] assert_array_almost_equal(dt, dt_ref) assert_array_almost_equal(kt, kt_ref) assert_array_almost_equal(signal, DKI_signal(gtab_2s, dt_ref, kt_ref, S0=100, snr=None), decimal=5)
def test_dki_micro_predict_single_voxel(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # prepare simulation: theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie*100, (1 - fie)*100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) signal_gt, da = multi_tensor(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # Defined DKI microstrutural model dkiM = dki_micro.KurtosisMicrostructureModel(gtab_2s) # Fit single voxel signal dkiF = dkiM.fit(signal) # Check predict of KurtosisMicrostruturalModel pred = dkiM.predict(dkiF.model_params) assert_array_almost_equal(pred, signal_gt, decimal=4) pred = dkiM.predict(dkiF.model_params, S0=100) assert_array_almost_equal(pred, signal_gt * 100, decimal=4) # Check predict of KurtosisMicrostruturalFit pred = dkiF.predict(gtab_2s, S0=100) assert_array_almost_equal(pred, signal_gt * 100, decimal=4)
def test_cholesky_functions(): S, dt, kt = multi_tensor_dki(gtab, mevals, S0=100, angles=[(45., 45.), (45., 45.)], fractions=[80, 20]) R = lower_triangular_to_cholesky(dt) tensor = cholesky_to_lower_triangular(R) assert_array_almost_equal(dt, tensor)
def test_smt2_specific_cases(): mdkiM = msdki.MeanDiffusionKurtosisModel(gtab_3s) # Check smt2 is sepecific cases with knowm g.t: # 1) Intrisic diffusion is equal MSD for single Gaussian isotropic # diffusion (i.e. awf=0) sig_gaussian = single_tensor(gtab_3s, evals=np.array([2e-3, 2e-3, 2e-3])) mdkiF = mdkiM.fit(sig_gaussian) assert_almost_equal(mdkiF.msk, 0.0) assert_almost_equal(mdkiF.msd, 2.0e-3) assert_almost_equal(mdkiF.smt2f, 0) assert_almost_equal(mdkiF.smt2di, 2.0e-3) # 2) Intrisic diffusion is equal to MSD/3 for single powder-averaged stick # compartment Da = 2.0e-3 mevals = np.zeros((64, 3)) mevals[:, 0] = Da fracs = np.ones(64) * 100 / 64 signal_pa, dt_sph, kt_sph = multi_tensor_dki(gtab_3s, mevals, angles=bvecs[1:, :], fractions=fracs, snr=None) mdkiF = mdkiM.fit(signal_pa) # decimal is set to 1 because of finite number of directions for powder # average calculation assert_almost_equal(mdkiF.msk, 2.4, decimal=1) assert_almost_equal(mdkiF.msd * 1000, Da / 3 * 1000, decimal=1) assert_almost_equal(mdkiF.smt2f, 1, decimal=1) assert_almost_equal(mdkiF.smt2di, mdkiF.msd * 3, decimal=1)
def test_multi_voxel_kurtosis_maximum(): # Multi-voxel simulations parameters FIE = np.array([[[0.30, 0.32], [0.74, 0.51]], [[0.47, 0.21], [0.80, 0.63]]]) RDI = np.zeros((2, 2, 2)) ADI = np.array([[[1e-3, 1.3e-3], [0.8e-3, 1e-3]], [[0.9e-3, 0.99e-3], [0.89e-3, 1.1e-3]]]) ADE = np.array([[[2.2e-3, 2.3e-3], [2.8e-3, 2.1e-3]], [[1.9e-3, 2.5e-3], [1.89e-3, 2.1e-3]]]) Tor = np.array([[[2.6, 2.4], [2.8, 2.1]], [[2.9, 2.5], [2.7, 2.3]]]) RDE = ADE / Tor # prepare simulation: DWIsim = np.zeros((2, 2, 2, gtab_2s.bvals.size)) for i in range(2): for j in range(2): for k in range(2): ADi = ADI[i, j, k] RDi = RDI[i, j, k] ADe = ADE[i, j, k] RDe = RDE[i, j, k] fie = FIE[i, j, k] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim[i, j, k, :] = signal # Ground truth Maximum kurtosis RD = FIE * RDI + (1 - FIE) * RDE RK = 3 * FIE * (1 - FIE) * ((RDI - RDE) / RD)**2 # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(DWIsim) sphere = get_sphere('symmetric724') # TEST - when no sphere is given k_max = dki.kurtosis_maximum(dkiF.model_params) assert_almost_equal(k_max, RK, decimal=4) # TEST - when sphere is given k_max = dki.kurtosis_maximum(dkiF.model_params, sphere) assert_almost_equal(k_max, RK, decimal=4) # TEST - when mask is given mask = np.ones((2, 2, 2), dtype='bool') mask[1, 1, 1] = 0 RK[1, 1, 1] = 0 k_max = dki.kurtosis_maximum(dkiF.model_params, mask=mask) assert_almost_equal(k_max, RK, decimal=4)
def test_multi_voxel_kurtosis_maximum(): # Multi-voxel simulations parameters FIE = np.array([[[0.30, 0.32], [0.74, 0.51]], [[0.47, 0.21], [0.80, 0.63]]]) RDI = np.zeros((2, 2, 2)) ADI = np.array([[[1e-3, 1.3e-3], [0.8e-3, 1e-3]], [[0.9e-3, 0.99e-3], [0.89e-3, 1.1e-3]]]) ADE = np.array([[[2.2e-3, 2.3e-3], [2.8e-3, 2.1e-3]], [[1.9e-3, 2.5e-3], [1.89e-3, 2.1e-3]]]) Tor = np.array([[[2.6, 2.4], [2.8, 2.1]], [[2.9, 2.5], [2.7, 2.3]]]) RDE = ADE / Tor # prepare simulation: DWIsim = np.zeros((2, 2, 2, gtab_2s.bvals.size)) for i in range(2): for j in range(2): for k in range(2): ADi = ADI[i, j, k] RDi = RDI[i, j, k] ADe = ADE[i, j, k] RDe = RDE[i, j, k] fie = FIE[i, j, k] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie*100, (1 - fie)*100] theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim[i, j, k, :] = signal # Ground truth Maximum kurtosis RD = FIE*RDI + (1-FIE)*RDE RK = 3 * FIE * (1-FIE) * ((RDI-RDE) / RD) ** 2 # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(DWIsim) sphere = get_sphere('symmetric724') # TEST - when no sphere is given k_max = dki.kurtosis_maximum(dkiF.model_params) assert_almost_equal(k_max, RK, decimal=4) # TEST - when sphere is given k_max = dki.kurtosis_maximum(dkiF.model_params, sphere) assert_almost_equal(k_max, RK, decimal=4) # TEST - when mask is given mask = np.ones((2, 2, 2), dtype='bool') mask[1, 1, 1] = 0 RK[1, 1, 1] = 0 k_max = dki.kurtosis_maximum(dkiF.model_params, mask=mask) assert_almost_equal(k_max, RK, decimal=4)
def test_single_voxel_DKI_stats(): # tests if AK and RK are equal to expected values for a single fiber # simulate randomly oriented ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # Reference values AD = fie * ADi + (1 - fie) * ADe AK = 3 * fie * (1 - fie) * ((ADi - ADe) / AD)**2 RD = fie * RDi + (1 - fie) * RDe RK = 3 * fie * (1 - fie) * ((RDi - RDe) / RD)**2 ref_vals = np.array([AD, AK, RD, RK]) # simulate fiber randomly oriented theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) evals, evecs = decompose_tensor(from_lower_triangular(dt)) dki_par = np.concatenate((evals, evecs[0], evecs[1], evecs[2], kt), axis=0) # Estimates using dki functions ADe1 = dti.axial_diffusivity(evals) RDe1 = dti.radial_diffusivity(evals) AKe1 = axial_kurtosis(dki_par) RKe1 = radial_kurtosis(dki_par) e1_vals = np.array([ADe1, AKe1, RDe1, RKe1]) assert_array_almost_equal(e1_vals, ref_vals) # Estimates using the kurtosis class object dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) e2_vals = np.array([dkiF.ad, dkiF.ak(), dkiF.rd, dkiF.rk()]) assert_array_almost_equal(e2_vals, ref_vals) # test MK (note this test correspond to the MK singularity L2==L3) MK_as = dkiF.mk() sph = Sphere(xyz=gtab.bvecs[gtab.bvals > 0]) MK_nm = np.mean(dkiF.akc(sph)) assert_array_almost_equal(MK_as, MK_nm, decimal=1)
def test_MK_singularities(): # To test MK in case that analytical solution was a singularity not covered # by other tests dkiM = dki.DiffusionKurtosisModel(gtab_2s) # test singularity L1 == L2 - this is the case of a prolate diffusion # tensor for crossing fibers at 90 degrees angles_all = np.array([[(90, 0), (90, 0), (0, 0), (0, 0)], [(89.9, 0), (89.9, 0), (0, 0), (0, 0)]]) for angles_90 in angles_all: s_90, dt_90, kt_90 = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles_90, fractions=frac_cross, snr=None) dkiF = dkiM.fit(s_90) MK = dkiF.mk() sph = Sphere(xyz=gtab.bvecs[gtab.bvals > 0]) MK_nm = np.mean(dkiF.akc(sph)) assert_almost_equal(MK, MK_nm, decimal=2) # test singularity L1 == L3 and L1 != L2 # since L1 is defined as the larger eigenvalue and L3 the smallest # eigenvalue, this singularity teoretically will never be called, # because for L1 == L3, L2 have also to be = L1 and L2. # Nevertheless, I decided to include this test since this singularity # is revelant for cases that eigenvalues are not ordered # artificially revert the eigenvalue and eigenvector order dki_params = dkiF.model_params.copy() dki_params[1] = dkiF.model_params[2] dki_params[2] = dkiF.model_params[1] dki_params[4] = dkiF.model_params[5] dki_params[5] = dkiF.model_params[4] dki_params[7] = dkiF.model_params[8] dki_params[8] = dkiF.model_params[7] dki_params[10] = dkiF.model_params[11] dki_params[11] = dkiF.model_params[10] MK = dki.mean_kurtosis(dki_params) MK_nm = np.mean(dki.apparent_kurtosis_coef(dki_params, sph)) assert_almost_equal(MK, MK_nm, decimal=2)
def test_single_voxel_DKI_stats(): # tests if AK and RK are equal to expected values for a single fiber # simulate randomly oriented ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # Reference values AD = fie * ADi + (1 - fie) * ADe AK = 3 * fie * (1 - fie) * ((ADi-ADe) / AD) ** 2 RD = fie * RDi + (1 - fie) * RDe RK = 3 * fie * (1 - fie) * ((RDi-RDe) / RD) ** 2 ref_vals = np.array([AD, AK, RD, RK]) # simulate fiber randomly oriented theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, S0=100, angles=angles, fractions=frac, snr=None) evals, evecs = decompose_tensor(from_lower_triangular(dt)) dki_par = np.concatenate((evals, evecs[0], evecs[1], evecs[2], kt), axis=0) # Estimates using dki functions ADe1 = dti.axial_diffusivity(evals) RDe1 = dti.radial_diffusivity(evals) AKe1 = axial_kurtosis(dki_par) RKe1 = radial_kurtosis(dki_par) e1_vals = np.array([ADe1, AKe1, RDe1, RKe1]) assert_array_almost_equal(e1_vals, ref_vals) # Estimates using the kurtosis class object dkiM = dki.DiffusionKurtosisModel(gtab_2s) dkiF = dkiM.fit(signal) e2_vals = np.array([dkiF.ad, dkiF.ak(), dkiF.rd, dkiF.rk()]) assert_array_almost_equal(e2_vals, ref_vals) # test MK (note this test correspond to the MK singularity L2==L3) MK_as = dkiF.mk() sph = Sphere(xyz=gtab.bvecs[gtab.bvals > 0]) MK_nm = np.mean(dkiF.akc(sph)) assert_array_almost_equal(MK_as, MK_nm, decimal=1)
def make_dki_data(out_fbval, out_fbvec, out_fdata, out_shape=(5, 6, 7)): """ Create a synthetic data-set with a 2-shell acquisition out_fbval, out_fbvec, out_fdata : str Full paths to generated data and bval/bvec files out_shape : tuple The 3D shape of the output volum """ # This is one-shell (b=1000) data: fimg, fbvals, fbvecs = dpd.get_fnames('small_64D') img = nib.load(fimg) bvals, bvecs = dio.read_bvals_bvecs(fbvals, fbvecs) # So we create two shells out of it bvals_2s = np.concatenate((bvals, bvals * 2), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = dpg.gradient_table(bvals_2s, bvecs_2s) # Simulate a signal based on the DKI model: mevals_cross = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087], [0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) angles_cross = [(80, 10), (80, 10), (20, 30), (20, 30)] fie = 0.49 frac_cross = [fie * 50, (1 - fie) * 50, fie * 50, (1 - fie) * 50] # Noise free simulates signal_cross, dt_cross, kt_cross = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles_cross, fractions=frac_cross, snr=None) DWI = np.zeros(out_shape + (len(gtab_2s.bvals), )) DWI[:] = signal_cross nib.save(nib.Nifti1Image(DWI, img.affine), out_fdata) np.savetxt(out_fbval, bvals_2s) np.savetxt(out_fbvec, bvecs_2s)
def make_dki_data(out_fbval, out_fbvec, out_fdata, out_shape=(5, 6, 7)): """ Create a synthetic data-set with a 2-shell acquisition out_fbval, out_fbvec, out_fdata : str Full paths to generated data and bval/bvec files out_shape : tuple The 3D shape of the output volum """ # This is one-shell (b=1000) data: fimg, fbvals, fbvecs = dpd.get_data('small_64D') img = nib.load(fimg) bvals, bvecs = dio.read_bvals_bvecs(fbvals, fbvecs) # So we create two shells out of it bvals_2s = np.concatenate((bvals, bvals * 2), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = dpg.gradient_table(bvals_2s, bvecs_2s) # Simulate a signal based on the DKI model: mevals_cross = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087], [0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) angles_cross = [(80, 10), (80, 10), (20, 30), (20, 30)] fie = 0.49 frac_cross = [fie * 50, (1 - fie) * 50, fie * 50, (1 - fie) * 50] # Noise free simulates signal_cross, dt_cross, kt_cross = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles_cross, fractions=frac_cross, snr=None) DWI = np.zeros(out_shape + (len(gtab_2s.bvals), )) DWI[:] = signal_cross nib.save(nib.Nifti1Image(DWI, img.affine), out_fdata) np.savetxt(out_fbval, bvals_2s) np.savetxt(out_fbvec, bvecs_2s)
In ``fractions`` we save the percentage of the contribution of each compartment, which is computed by multiplying the percentage of contribution of each fiber population and the water fraction of each different medium """ fie = 0.49 # intra axonal water fraction fractions = [fie*50, (1 - fie)*50, fie*50, (1 - fie)*50] """ Having defined the parameters for all tissue compartments, the elements of the diffusion tensor (DT), the elements of the kurtosis tensor (KT) and the DW signals simulated from the DKI model can be obtain using the function ``multi_tensor_dki``. """ signal_dki, dt, kt = multi_tensor_dki(gtab, mevals, S0=200, angles=angles, fractions=fractions, snr=None) """ We can also add Rician noise with a specific SNR. """ signal_noisy, dt, kt = multi_tensor_dki(gtab, mevals, S0=200, angles=angles, fractions=fractions, snr=10) """ For comparison purposes, we also compute the DW signal if only the diffusion tensor components are taken into account. For this we use DIPY's function ``single_tensor`` which requires that dt is decomposed into its eigenvalues and eigenvectors. """
def test_kurtosis_maximum(): # TEST 1 # simulate a crossing fibers interserting at 70 degrees. The first fiber # is aligned to the x-axis while the second fiber is aligned to the x-z # plane with an angular deviation of 70 degrees from the first one. # According to Neto Henriques et al, 2015 (NeuroImage 111: 85-99), the # kurtosis tensor of this simulation will have a maxima aligned to axis y angles = [(90, 0), (90, 0), (20, 0), (20, 0)] signal_70, dt_70, kt_70 = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles, fractions=frac_cross, snr=None) # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal_70) MD = dkiF.md kt = dkiF.kt R = dkiF.evecs evals = dkiF.evals dt = lower_triangular(np.dot(np.dot(R, np.diag(evals)), R.T)) sphere = get_sphere('symmetric724') # compute maxima k_max_cross, max_dir = dki._voxel_kurtosis_maximum(dt, MD, kt, sphere, gtol=1e-5) yaxis = np.array([0., 1., 0.]) cos_angle = np.abs(np.dot(max_dir[0], yaxis)) assert_almost_equal(cos_angle, 1.) # TEST 2 # test the function on cases of well aligned fibers oriented in a random # defined direction. According to Neto Henriques et al, 2015 (NeuroImage # 111: 85-99), the maxima of kurtosis is any direction perpendicular to the # fiber direction. Moreover, according to multicompartmetal simulations, # kurtosis in this direction has to be equal to: fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 RD = fie*RDi + (1-fie)*RDe RK = 3 * fie * (1-fie) * ((RDi-RDe) / RD) ** 2 # prepare simulation: theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie*100, (1 - fie)*100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # prepare inputs dkiM = dki.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal) MD = dkiF.md kt = dkiF.kt R = dkiF.evecs evals = dkiF.evals dt = lower_triangular(np.dot(np.dot(R, np.diag(evals)), R.T)) # compute maxima k_max, max_dir = dki._voxel_kurtosis_maximum(dt, MD, kt, sphere, gtol=1e-5) # check if max direction is perpendicular to fiber direction fdir = np.array([sphere2cart(1., np.deg2rad(theta), np.deg2rad(phi))]) cos_angle = np.abs(np.dot(max_dir[0], fdir[0])) assert_almost_equal(cos_angle, 0., decimal=5) # check if max direction is equal to expected value assert_almost_equal(k_max, RK) # According to Neto Henriques et al., 2015 (NeuroImage 111: 85-99), # e.g. see figure 1 of this article, kurtosis maxima for the first test is # also equal to the maxima kurtosis value of well-aligned fibers, since # simulations parameters (apart from fiber directions) are equal assert_almost_equal(k_max_cross, RK) # Test 3 - Test performance when kurtosis is spherical - this case, can be # problematic since a spherical kurtosis does not have an maximum k_max, max_dir = dki._voxel_kurtosis_maximum(dt_sph, np.mean(evals_sph), kt_sph, sphere, gtol=1e-2) assert_almost_equal(k_max, Kref_sphere) # Test 4 - Test performance when kt have all elements zero - this case, can # be problematic this case does not have an maximum k_max, max_dir = dki._voxel_kurtosis_maximum(dt_sph, np.mean(evals_sph), np.zeros(15), sphere, gtol=1e-2) assert_almost_equal(k_max, 0.0)
def test_single_fiber_model(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # prepare simulation: theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie*100, (1 - fie)*100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # DKI fit dkiM = dki_micro.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal) # Axonal Water Fraction sphere = get_sphere('symmetric724') AWF = dki_micro.axonal_water_fraction(dkiF.model_params, sphere, mask=None, gtol=1e-5) assert_almost_equal(AWF, fie) # Extra-cellular and intra-cellular components edt, idt = dki_micro.diffusion_components(dkiF.model_params, sphere) EDT = eig_from_lo_tri(edt) IDT = eig_from_lo_tri(idt) # check eigenvalues assert_array_almost_equal(EDT[0:3], np.array([ADe, RDe, RDe])) assert_array_almost_equal(IDT[0:3], np.array([ADi, RDi, RDi])) # first eigenvalue should be the direction of the fibers fiber_direction = _check_directions([(theta, phi)]) f_norm = abs(np.dot(fiber_direction, np.array((EDT[3], EDT[6], EDT[9])))) assert_almost_equal(f_norm, 1.) f_norm = abs(np.dot(fiber_direction, np.array((IDT[3], IDT[6], IDT[9])))) assert_almost_equal(f_norm, 1.) # Test model and fit objects wmtiM = dki_micro.KurtosisMicrostructureModel(gtab_2s, fit_method="WLS") wmtiF = wmtiM.fit(signal) assert_almost_equal(wmtiF.awf, AWF) assert_array_almost_equal(wmtiF.hindered_evals, np.array([ADe, RDe, RDe])) assert_array_almost_equal(wmtiF.restricted_evals, np.array([ADi, RDi, RDi])) assert_almost_equal(wmtiF.hindered_ad, ADe) assert_almost_equal(wmtiF.hindered_rd, RDe) assert_almost_equal(wmtiF.axonal_diffusivity, ADi) assert_almost_equal(wmtiF.tortuosity, ADe/RDe, decimal=4) # Test diffusion_components when a kurtosis tensors is associated with # negative kurtosis values. E.g of this cases is given below: dkiparams = np.array([1.67135726e-03, 5.03651205e-04, 9.35365328e-05, -7.11167583e-01, 6.23186820e-01, -3.25390313e-01, -1.75247376e-02, -4.78415563e-01, -8.77958674e-01, 7.02804064e-01, 6.18673368e-01, -3.51154825e-01, 2.18384153, -2.76378153e-02, 2.22893297, -2.68306546e-01, -1.28411610, -1.56557645e-01, -1.80850619e-01, -8.33152110e-01, -3.62410766e-01, 1.57775442e-01, 8.73775381e-01, 2.77188975e-01, -3.67415502e-02, -1.56330984e-01, -1.62295407e-02]) edt, idt = dki_micro.diffusion_components(dkiparams) assert_(np.all(np.isfinite(edt)))
# 2 shells for techniques that requires multishell data bvals_2s = np.concatenate((bvals, bvals * 2), axis=0) bvecs_2s = np.concatenate((bvecs, bvecs), axis=0) gtab_2s = gradient_table(bvals_2s, bvecs_2s) # Simulation 1. signals of two crossing fibers are simulated mevals_cross = np.array([[0.00099, 0, 0], [0.00226, 0.00087, 0.00087], [0.00099, 0, 0], [0.00226, 0.00087, 0.00087]]) angles_cross = [(80, 10), (80, 10), (20, 30), (20, 30)] fie = 0.49 frac_cross = [fie*50, (1-fie) * 50, fie*50, (1-fie) * 50] # Noise free simulates signal_cross, dt_cross, kt_cross = multi_tensor_dki(gtab_2s, mevals_cross, S0=100, angles=angles_cross, fractions=frac_cross, snr=None) evals_cross, evecs_cross = decompose_tensor(from_lower_triangular(dt_cross)) crossing_ref = np.concatenate((evals_cross, evecs_cross[0], evecs_cross[1], evecs_cross[2], kt_cross), axis=0) # Simulation 2. Spherical kurtosis tensor.- for white matter, this can be a # biological implaussible scenario, however this simulation is usefull for # testing the estimation of directional apparent kurtosis and the mean # kurtosis, since its directional and mean kurtosis ground truth are a constant # which can be easly mathematicaly calculated. Di = 0.00099 De = 0.00226 mevals_sph = np.array([[Di, Di, Di], [De, De, De]]) frac_sph = [50, 50]
for i in range(2): for j in range(2): for k in range(2): ADi = ADI[i, j, k] RDi = RDI[i, j, k] ADe = ADE[i, j, k] RDe = RDE[i, j, k] fie = FIE[i, j, k] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim[i, j, k, :] = signal signal, sticks = multi_tensor(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim_all_taylor[i, j, k, :] = signal def test_single_fiber_model(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099
compartment, which is computed by multiplying the percentage of contribution of each fiber population and the water fraction of each different medium """ fie = 0.49 # intra axonal water fraction fractions = [fie * 50, (1 - fie) * 50, fie * 50, (1 - fie) * 50] """ Having defined the parameters for all tissue compartments, the elements of the diffusion tensor (dt), the elements of the kurtosis tensor (kt) and the DW signals simulated from the DKI model can be obtain using the function ``multi_tensor_dki``. """ signal_dki, dt, kt = multi_tensor_dki(gtab, mevals, S0=200, angles=angles, fractions=fractions, snr=None) """ We can also add rician noise with a specific SNR. """ signal_noisy, dt, kt = multi_tensor_dki(gtab, mevals, S0=200, angles=angles, fractions=fractions, snr=10) """ For comparison purposes, we also compute the DW signal if only the diffusion tensor components are taken into account. For this we use Dipy's function
# 2 shells for techniques that requires multishell data bvals_3s = np.concatenate((bvals, bvals*1.5, bvals * 2), axis=0) bvecs_3s = np.concatenate((bvecs, bvecs, bvecs), axis=0) gtab_3s = gradient_table(bvals_3s, bvecs_3s) # Simulation 1. Spherical kurtosis tensor - MSK and MSD from the MSDKI model # should be equa to the MK and MD of the DKI tensor for cases of # spherical kurtosis tensors Di = 0.00099 De = 0.00226 mevals_sph = np.array([[Di, Di, Di], [De, De, De]]) f = 0.5 frac_sph = [f * 100, (1.0 - f) * 100] signal_sph, dt_sph, kt_sph = multi_tensor_dki(gtab_3s, mevals_sph, S0=100, fractions=frac_sph, snr=None) # Compute ground truth values MDgt = f * Di + (1 - f) * De MKgt = 3 * f * (1-f) * ((Di-De) / MDgt) ** 2 params_single = np.array([MDgt, MKgt]) msignal_sph = np.zeros(4) msignal_sph[0] = signal_sph[0] msignal_sph[1] = signal_sph[1] msignal_sph[2] = signal_sph[100] msignal_sph[3] = signal_sph[180] # Simulation 2. Multi-voxel simulations DWI = np.zeros((2, 2, 2, len(gtab_3s.bvals))) MDWI = np.zeros((2, 2, 2, 4)) MDgt_multi = np.zeros((2, 2, 2))
def test_single_fiber_model(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087 # prepare simulation: theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie * 100, (1 - fie) * 100] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) # DKI fit dkiM = dki_micro.DiffusionKurtosisModel(gtab_2s, fit_method="WLS") dkiF = dkiM.fit(signal) # Axonal Water Fraction sphere = get_sphere('symmetric724') AWF = dki_micro.axonal_water_fraction(dkiF.model_params, sphere, mask=None, gtol=1e-5) assert_almost_equal(AWF, fie) # Extra-cellular and intra-cellular components edt, idt = dki_micro.diffusion_components(dkiF.model_params, sphere) EDT = eig_from_lo_tri(edt) IDT = eig_from_lo_tri(idt) # check eigenvalues assert_array_almost_equal(EDT[0:3], np.array([ADe, RDe, RDe])) assert_array_almost_equal(IDT[0:3], np.array([ADi, RDi, RDi])) # first eigenvalue should be the direction of the fibers fiber_direction = _check_directions([(theta, phi)]) f_norm = abs(np.dot(fiber_direction, np.array((EDT[3], EDT[6], EDT[9])))) assert_almost_equal(f_norm, 1.) f_norm = abs(np.dot(fiber_direction, np.array((IDT[3], IDT[6], IDT[9])))) assert_almost_equal(f_norm, 1.) # Test model and fit objects wmtiM = dki_micro.KurtosisMicrostructureModel(gtab_2s, fit_method="WLS") wmtiF = wmtiM.fit(signal) assert_almost_equal(wmtiF.awf, AWF) assert_array_almost_equal(wmtiF.hindered_evals, np.array([ADe, RDe, RDe])) assert_array_almost_equal(wmtiF.restricted_evals, np.array([ADi, RDi, RDi])) assert_almost_equal(wmtiF.hindered_ad, ADe) assert_almost_equal(wmtiF.hindered_rd, RDe) assert_almost_equal(wmtiF.axonal_diffusivity, ADi) assert_almost_equal(wmtiF.tortuosity, ADe / RDe, decimal=4) # Test diffusion_components when a kurtosis tensors is associated with # negative kurtosis values. E.g of this cases is given below: dkiparams = np.array([ 1.67135726e-03, 5.03651205e-04, 9.35365328e-05, -7.11167583e-01, 6.23186820e-01, -3.25390313e-01, -1.75247376e-02, -4.78415563e-01, -8.77958674e-01, 7.02804064e-01, 6.18673368e-01, -3.51154825e-01, 2.18384153, -2.76378153e-02, 2.22893297, -2.68306546e-01, -1.28411610, -1.56557645e-01, -1.80850619e-01, -8.33152110e-01, -3.62410766e-01, 1.57775442e-01, 8.73775381e-01, 2.77188975e-01, -3.67415502e-02, -1.56330984e-01, -1.62295407e-02 ]) edt, idt = dki_micro.diffusion_components(dkiparams) assert_(np.all(np.isfinite(edt)))
# 2 shells for techniques that requires multishell data bvals_3s = np.concatenate((bvals, bvals * 1.5, bvals * 2), axis=0) bvecs_3s = np.concatenate((bvecs, bvecs, bvecs), axis=0) gtab_3s = gradient_table(bvals_3s, bvecs_3s) # Simulation 1. Spherical kurtosis tensor - MSK and MSD from the MSDKI model # should be equal to the MK and MD of the DKI tensor for cases of # spherical kurtosis tensors Di = 0.00099 De = 0.00226 mevals_sph = np.array([[Di, Di, Di], [De, De, De]]) f = 0.5 frac_sph = [f * 100, (1.0 - f) * 100] signal_sph, dt_sph, kt_sph = multi_tensor_dki(gtab_3s, mevals_sph, S0=100, fractions=frac_sph, snr=None) # Compute ground truth values MDgt = f * Di + (1 - f) * De MKgt = 3 * f * (1 - f) * ((Di - De) / MDgt)**2 params_single = np.array([MDgt, MKgt]) msignal_sph = np.zeros(4) msignal_sph[0] = signal_sph[0] msignal_sph[1] = signal_sph[1] msignal_sph[2] = signal_sph[100] msignal_sph[3] = signal_sph[180] # Simulation 2. Multi-voxel simulations DWI = np.zeros((2, 2, 2, len(gtab_3s.bvals))) MDWI = np.zeros((2, 2, 2, 4))
def test_DKI_simulations_aligned_fibers(): """ Testing DKI simulations when aligning the same fiber to different axis. If biological parameters don't change, kt[0] of a fiber aligned to axis x has to be equal to kt[1] of a fiber aligned to the axis y and equal to kt[2] of a fiber aligned to axis z. The same is applicable for dt """ # Defining parameters based on Neto Henriques et al., 2015. NeuroImage 111 mevals = np.array([ [0.00099, 0, 0], # Intra-cellular [0.00226, 0.00087, 0.00087] ]) # Extra-cellular frac = [49, 51] # Compartment volume fraction # axis x angles = [(90, 0), (90, 0)] signal_fx, dt_fx, kt_fx = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac) # axis y angles = [(90, 90), (90, 90)] signal_fy, dt_fy, kt_fy = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac) # axis z angles = [(0, 0), (0, 0)] signal_fz, dt_fz, kt_fz = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac) assert_array_equal([kt_fx[0], kt_fx[1], kt_fx[2]], [kt_fy[1], kt_fy[0], kt_fy[2]]) assert_array_equal([kt_fx[0], kt_fx[1], kt_fx[2]], [kt_fz[2], kt_fz[0], kt_fz[1]]) assert_array_equal([dt_fx[0], dt_fx[2], dt_fx[5]], [dt_fy[2], dt_fy[0], dt_fy[5]]) assert_array_equal([dt_fx[0], dt_fx[2], dt_fx[5]], [dt_fz[5], dt_fz[0], dt_fz[2]]) # testing S signal along axis x, y and z bvals = np.array([0, 0, 0, 1000, 1000, 1000, 2000, 2000, 2000]) bvecs = np.asarray([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1]]) gtab_axis = gradient_table(bvals, bvecs) # axis x S_fx = dki_signal(gtab_axis, dt_fx, kt_fx, S0=100) assert_array_almost_equal(S_fx[0:3], [100, 100, 100]) # test S f0r b=0 # axis y S_fy = dki_signal(gtab_axis, dt_fy, kt_fy, S0=100) assert_array_almost_equal(S_fy[0:3], [100, 100, 100]) # test S f0r b=0 # axis z S_fz = dki_signal(gtab_axis, dt_fz, kt_fz, S0=100) assert_array_almost_equal(S_fz[0:3], [100, 100, 100]) # test S f0r b=0 # test S for b = 1000 assert_array_almost_equal([S_fx[3], S_fx[4], S_fx[5]], [S_fy[4], S_fy[3], S_fy[5]]) assert_array_almost_equal([S_fx[3], S_fx[4], S_fx[5]], [S_fz[5], S_fz[3], S_fz[4]]) # test S for b = 2000 assert_array_almost_equal([S_fx[6], S_fx[7], S_fx[8]], [S_fy[7], S_fy[6], S_fy[8]]) assert_array_almost_equal([S_fx[6], S_fx[7], S_fx[8]], [S_fz[8], S_fz[6], S_fz[7]])
for i in range(2): for j in range(2): for k in range(2): ADi = ADI[i, j, k] RDi = RDI[i, j, k] ADe = ADE[i, j, k] RDe = RDE[i, j, k] fie = FIE[i, j, k] mevals = np.array([[ADi, RDi, RDi], [ADe, RDe, RDe]]) frac = [fie*100, (1 - fie)*100] theta = random.uniform(0, 180) phi = random.uniform(0, 320) angles = [(theta, phi), (theta, phi)] signal, dt, kt = multi_tensor_dki(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim[i, j, k, :] = signal signal, sticks = multi_tensor(gtab_2s, mevals, angles=angles, fractions=frac, snr=None) DWIsim_all_taylor[i, j, k, :] = signal def test_single_fiber_model(): # single fiber simulate (which is the assumption of our model) fie = 0.49 ADi = 0.00099 ADe = 0.00226 RDi = 0 RDe = 0.00087