def dipy_gt():
    print("Loading slice...")
    sample_slice, qvecs, gtab = load_slice('./test_data/david_data', '3112_BL_data_subject_space.nii.gz', gtab=True)
    mapmodel = GeneralizedQSamplingModel(gtab)
    mapfit = mapmodel.fit(sample_slice)
    sphere = get_sphere('repulsion724')
    odfs = mapfit.odf(sphere)
    vis_2d_field(odfs, sphere)
Exemple #2
0
def test_gqi():
    #load symmetric 724 sphere
    sphere = get_sphere('symmetric724')
    #load icosahedron sphere
    sphere2 = create_unit_sphere(5)
    btable = np.loadtxt(get_data('dsi515btable'))
    bvals = btable[:, 0]
    bvecs = btable[:, 1:]
    gtab = gradient_table(bvals, bvecs)
    data, golden_directions = SticksAndBall(gtab,
                                            d=0.0015,
                                            S0=100,
                                            angles=[(0, 0), (90, 0)],
                                            fractions=[50, 50],
                                            snr=None)
    gq = GeneralizedQSamplingModel(gtab, method='gqi2', sampling_length=1.4)

    #symmetric724
    gqfit = gq.fit(data)
    odf = gqfit.odf(sphere)
    directions, values, indices = peak_directions(odf, sphere, .35, 25)
    assert_equal(len(directions), 2)
    assert_almost_equal(angular_similarity(directions, golden_directions), 2,
                        1)

    #5 subdivisions
    gqfit = gq.fit(data)
    odf2 = gqfit.odf(sphere2)
    directions, values, indices = peak_directions(odf2, sphere2, .35, 25)
    assert_equal(len(directions), 2)
    assert_almost_equal(angular_similarity(directions, golden_directions), 2,
                        1)

    sb_dummies = sticks_and_ball_dummies(gtab)
    for sbd in sb_dummies:
        data, golden_directions = sb_dummies[sbd]
        odf = gq.fit(data).odf(sphere2)
        directions, values, indices = peak_directions(odf, sphere2, .35, 25)
        if len(directions) <= 3:
            assert_equal(len(directions), len(golden_directions))
        if len(directions) > 3:
            assert_equal(gfa(odf) < 0.1, True)
Exemple #3
0
def test_mvoxel_gqi():
    data, gtab = dsi_voxels()
    gq = GeneralizedQSamplingModel(gtab, 'standard')
    sphere = get_sphere('symmetric724')
    gq.direction_finder.config(sphere=sphere, 
                                min_separation_angle=25,
                                relative_peak_threshold=.35)
    gqfit = gq.fit(data)
    directions = gqfit.directions
    assert_equal(directions[0, 0, 0].shape[0], 2)
    assert_equal(directions[-1, -1, -1].shape[0], 2)
def gqi(training, category, snr, denoised, odeconv, tv, method, weight=0.1, sl=3.):

    data, affine, gtab, mask, evals, S0, prefix = prepare(training,
                                                          category,
                                                          snr,
                                                          denoised,
                                                          odeconv,
                                                          tv,
                                                          method)
    


    model = GeneralizedQSamplingModel(gtab,
                                      method='gqi2',
                                      sampling_length=sl,
                                      normalize_peaks=False)

    fit = model.fit(data, mask)

    sphere = get_sphere('symmetric724')   

    odf = fit.odf(sphere)

    if odeconv == True:

        odf_sh = sf_to_sh(odf, sphere, sh_order=8,
                          basis_type='mrtrix')

        # # nib.save(nib.Nifti1Image(odf_sh, affine), model_tag + 'odf_sh.nii.gz')

        reg_sphere = get_sphere('symmetric724')

        fodf_sh = odf_sh_to_sharp(odf_sh,
                                  reg_sphere, basis='mrtrix', ratio=3.8 / 16.6,
                                  sh_order=8, Lambda=1., tau=1.)

        # # nib.save(nib.Nifti1Image(odf_sh, affine), model_tag + 'fodf_sh.nii.gz')

        fodf_sh[np.isnan(fodf_sh)]=0

        r, theta, phi = cart2sphere(sphere.x, sphere.y, sphere.z)
        B_regul, m, n = real_sph_harm_mrtrix(8, theta[:, None], phi[:, None])

        fodf = np.dot(fodf_sh, B_regul.T)

        odf = fodf

    if tv == True:

        odf = tv_denoise_4d(odf, weight=weight)

    save_odfs_peaks(training, odf, affine, sphere, dres, prefix)
Exemple #5
0
def test_gqi():
    # load symmetric 724 sphere
    sphere = get_sphere('symmetric724')
    # load icosahedron sphere
    sphere2 = create_unit_sphere(5)
    btable = np.loadtxt(get_fnames('dsi515btable'))
    bvals = btable[:, 0]
    bvecs = btable[:, 1:]
    gtab = gradient_table(bvals, bvecs)
    data, golden_directions = SticksAndBall(gtab, d=0.0015,
                                            S0=100, angles=[(0, 0), (90, 0)],
                                            fractions=[50, 50], snr=None)
    gq = GeneralizedQSamplingModel(gtab, method='gqi2', sampling_length=1.4)

    # symmetric724
    gqfit = gq.fit(data)
    odf = gqfit.odf(sphere)
    directions, values, indices = peak_directions(odf, sphere, .35, 25)
    assert_equal(len(directions), 2)
    assert_almost_equal(angular_similarity(directions, golden_directions), 2,
                        1)

    # 5 subdivisions
    gqfit = gq.fit(data)
    odf2 = gqfit.odf(sphere2)
    directions, values, indices = peak_directions(odf2, sphere2, .35, 25)
    assert_equal(len(directions), 2)
    assert_almost_equal(angular_similarity(directions, golden_directions), 2,
                        1)

    sb_dummies = sticks_and_ball_dummies(gtab)
    for sbd in sb_dummies:
        data, golden_directions = sb_dummies[sbd]
        odf = gq.fit(data).odf(sphere2)
        directions, values, indices = peak_directions(odf, sphere2, .35, 25)
        if len(directions) <= 3:
            assert_equal(len(directions), len(golden_directions))
        if len(directions) > 3:
            assert_equal(gfa(odf) < 0.1, True)
Exemple #6
0
def test_mvoxel_gqi():
    data, gtab = dsi_voxels()
    sphere = get_sphere('symmetric724')

    gq = GeneralizedQSamplingModel(gtab, 'standard')
    gqfit = gq.fit(data)
    all_odfs = gqfit.odf(sphere)

    # Check that the first and last voxels each have 2 peaks
    odf = all_odfs[0, 0, 0]
    directions, values, indices = peak_directions(odf, sphere, .35, 25)
    assert_equal(directions.shape[0], 2)
    odf = all_odfs[-1, -1, -1]
    directions, values, indices = peak_directions(odf, sphere, .35, 25)
    assert_equal(directions.shape[0], 2)
Exemple #7
0
def test_mvoxel_gqi():
    data, gtab = dsi_voxels()
    sphere = get_sphere('symmetric724')

    gq = GeneralizedQSamplingModel(gtab, 'standard')
    gqfit = gq.fit(data)
    all_odfs = gqfit.odf(sphere)

    # Check that the first and last voxels each have 2 peaks
    odf = all_odfs[0, 0, 0]
    directions, values, indices = peak_directions(odf, sphere, .35, 25)
    assert_equal(directions.shape[0], 2)
    odf = all_odfs[-1, -1, -1]
    directions, values, indices = peak_directions(odf, sphere, .35, 25)
    assert_equal(directions.shape[0], 2)
Exemple #8
0
def test_gqi():
    #load symmetric 724 sphere
    sphere = get_sphere('symmetric724')
    #load icosahedron sphere
    sphere2 = create_unit_sphere(5)
    btable = np.loadtxt(get_data('dsi515btable'))    
    bvals = btable[:,0]
    bvecs = btable[:,1:]        
    data, golden_directions = SticksAndBall(bvals, bvecs, d=0.0015, 
                               S0=100, angles=[(0, 0), (90, 0)], 
                               fractions=[50, 50], snr=None) 
    gtab = gradient_table(bvals, bvecs) 
    gq = GeneralizedQSamplingModel(gtab, method='gqi2', sampling_length=1.4)
    #symmetric724
    gq.direction_finder.config(sphere=sphere, min_separation_angle=25,
                               relative_peak_threshold=.35)
    gqfit = gq.fit(data)
    odf = gqfit.odf(sphere)
    #from dipy.viz._show_odfs import show_odfs
    #show_odfs(odf[None,None,None,:], (sphere.vertices, sphere.faces))
    directions = gqfit.directions
    assert_equal(len(directions), 2)
    assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1)
    #5 subdivisions
    gq.direction_finder.config(sphere=sphere2, min_separation_angle=25,
                              relative_peak_threshold=.35)
    gqfit = gq.fit(data)
    odf2 = gqfit.odf(sphere2)
    directions = gqfit.directions
    assert_equal(len(directions), 2)
    assert_almost_equal(angular_similarity(directions, golden_directions), 2, 1)
    #show_odfs(odf[None,None,None,:], (sphere.vertices, sphere.faces))
    sb_dummies=sticks_and_ball_dummies(gtab)
    for sbd in sb_dummies:
        data, golden_directions = sb_dummies[sbd]
        odf = gq.fit(data).odf(sphere2)
        directions = gq.fit(data).directions
        #show_odfs(odf[None, None, None, :], (sphere2.vertices, sphere2.faces))
        if len(directions) <= 3:
            assert_equal(len(gq.fit(data).directions), len(golden_directions))
        if len(directions) > 3:
            assert_equal(gfa(gq.fit(data).odf(sphere2)) < 0.1, True)
Exemple #9
0
"""
Instantiate the model and apply it to the data.
"""

gqmodel = GeneralizedQSamplingModel(gtab, sampling_length=3)
"""
The parameter ``sampling_length`` is used here to

Lets just use one slice only from the data.
"""

dataslice = data[:, :, data.shape[2] // 2]

mask = dataslice[..., 0] > 50

gqfit = gqmodel.fit(dataslice, mask=mask)
"""
Load an ODF reconstruction sphere
"""

sphere = get_sphere('repulsion724')
"""
Calculate the ODFs with this specific sphere
"""

ODF = gqfit.odf(sphere)

print('ODF.shape (%d, %d, %d)' % ODF.shape)
"""
ODF.shape ``(96, 96, 724)``
Exemple #10
0
def test_gqi():

    # load odf sphere
    vertices, faces = sphere_vf_from("symmetric724")
    edges = unique_edges(faces)
    half_vertices, half_edges, half_faces = reduce_antipodal(vertices, faces)

    # load bvals and gradients
    btable = np.loadtxt(get_data("dsi515btable"))
    bvals = btable[:, 0]
    bvecs = btable[:, 1:]
    S, stics = SticksAndBall(
        bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (90, 0), (90, 90)], fractions=[50, 50, 0], snr=None
    )
    # pdf0,odf0,peaks0=standard_dsi_algorithm(S,bvals,bvecs)
    S2 = S.copy()
    S2 = S2.reshape(1, len(S))

    odf_sphere = (vertices, faces)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    dsfit = ds.fit(S)
    assert_equal((dsfit.peak_values > 0).sum(), 3)

    # change thresholds
    ds.relative_peak_threshold = 0.5
    ds.angular_distance_threshold = 30
    dsfit = ds.fit(S)
    assert_equal((dsfit.peak_values > 0).sum(), 2)

    # 1 fiber
    S, stics = SticksAndBall(
        bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (90, 0), (90, 90)], fractions=[100, 0, 0], snr=None
    )
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    ds.relative_peak_threshold = 0.5
    ds.angular_distance_threshold = 20
    dsfit = ds.fit(S)
    QA = dsfit.qa
    # 1/0
    assert_equal(np.sum(QA > 0), 1)

    # 2 fibers
    S, stics = SticksAndBall(
        bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (90, 0), (90, 90)], fractions=[50, 50, 0], snr=None
    )
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    ds.relative_peak_threshold = 0.5
    ds.angular_distance_threshold = 20
    dsfit = ds.fit(S)
    QA = dsfit.qa
    assert_equal(np.sum(QA > 0), 2)

    # 3 fibers
    S, stics = SticksAndBall(
        bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (90, 0), (90, 90)], fractions=[33, 33, 33], snr=None
    )
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    ds.relative_peak_threshold = 0.5
    dsfit = ds.fit(S)
    QA = dsfit.qa
    assert_equal(np.sum(QA > 0), 3)

    # isotropic
    S, stics = SticksAndBall(
        bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (90, 0), (90, 90)], fractions=[0, 0, 0], snr=None
    )
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    dsfit = ds.fit(S)
    QA = dsfit.qa
    assert_equal(np.sum(QA > 0), 0)

    # 3 fibers DSI2
    S, stics = SticksAndBall(
        bvals, bvecs, d=0.0015, S0=100, angles=[(0, 0), (90, 0), (90, 90)], fractions=[33, 33, 33], snr=None
    )
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere, squared=True)
    ds.relative_peak_threshold = 0.5
    dsfit = ds.fit(S, gfa_thr=0.05)
    QA = dsfit.qa

    # 3 fibers DSI2 with a 3D volume
    data = np.zeros((3, 3, 3, len(S)))
    data[..., :] = S.copy()
    dsfit = ds.fit(data, gfa_thr=0.05)
    # 1/0
    assert_array_almost_equal(np.sum(dsfit.peak_values > 0, axis=-1), 3 * np.ones((3, 3, 3)))
Exemple #11
0
                   [0.0017, 0.0003, 0.0003],
                   [0.0017, 0.0003, 0.0003]])

# ang = [(20, 10), (70, 20), (45, 60)]
ang = [(0, 0), (45, 45), (90, 90)]

data, sticks = MultiTensor(gtab, mevals, S0=100, angles=ang,
                           fractions=[33.3, 33.3, 33.4], snr=100)


gqi_model = GeneralizedQSamplingModel(gtab,
                                      method='gqi2',
                                      sampling_length=4.,
                                      normalize_peaks=False)

gqi_fit = gqi_model.fit(data)

sphere = get_sphere('symmetric724')
gqi_odf = gqi_fit.odf(sphere)


def optimal_transform(model, data, sphere):
    from dipy.reconst.gqi import squared_radial_component

    H = squared_radial_component

    b_vector = model.b_vector
    bnorm = np.sqrt(np.sum(b_vector ** 2, axis=1))

    # # linearize
    # b_vector2 = b_vector * bnorm[:, None]
    #1/0

    data = data[25 - 10:25 + 10, 25 - 10:25 + 10, 25]
    mask = mask[25 - 10:25 + 10, 25 - 10:25 + 10, 25]
    # data = data[:, :, 25]

    model_tag = 'dsdeconv_'

    model = GeneralizedQSamplingModel(gtab,
                                      method='gqi2',
                                      sampling_length=3.,
                                      normalize_peaks=False)

    #model = DiffusionSpectrumDeconvModel(gtab)

    fit = model.fit(data, mask)

    sphere = get_sphere('symmetric724')

    odf = fit.odf(sphere)

    


    #nib.save(nib.Nifti1Image(odf, affine), model_tag + 'odf.nii.gz')

    odf_sh = sf_to_sh(odf, sphere, sh_order=8,
                      basis_type='mrtrix')

    #nib.save(nib.Nifti1Image(odf_sh, affine), model_tag + 'odf_sh.nii.gz')
Exemple #13
0
Instantiate the Model and apply it to the data.
"""

gqmodel = GeneralizedQSamplingModel(gtab, sampling_length=3)

"""
The parameter `sampling_length` is used here to

Lets just use one slice only from the data.
"""

dataslice = data[:, :, data.shape[2] / 2]

mask = dataslice[..., 0] > 50

gqfit = gqmodel.fit(dataslice, mask=mask)

"""
Load an odf reconstruction sphere
"""

sphere = get_sphere('symmetric724')

"""
Calculate the ODFs with this specific sphere
"""

ODF = gqfit.odf(sphere)

print('ODF.shape (%d, %d, %d)' % ODF.shape)
Exemple #14
0
fvtk.show(r)

# from pylab import plot, show

# plot(S, 'b')
# plot(S2, 'r')
# show()
# # plot(np.abs(S - S2))
# plot((S - S2))
# show()


gq = GeneralizedQSamplingModel(gtab_full, sampling_length=3.5)

gqfit = gq.fit(SS)
gqodf = gqfit.odf(sphere)

gqdir, _, _ = peak_directions(gqodf, sphere, .35, 15)

print angular_similarity(sticks, gqdir)

grid_size = 35
dds = DiffusionSpectrumDeconvModel(gtab_full,
                                   qgrid_size=grid_size,
                                   r_start=0.2 * (grid_size // 2),
                                   r_end=0.7 * (grid_size // 2),
                                   r_step=0.02 * (grid_size // 2),
                                   filter_width=np.inf,
                                   normalize_peaks=False)
Exemple #15
0
    """
    w=10
    data_roi = data[:, :, 32]
    #data_roi = data[48-w:48+w, 48-w:48+w, 32] #27-w:27+w,:]
    data_roi = data_roi[:,:,None,:]
    data = data_roi.astype('f8')
    """

    S0 = data[..., 0]
    mask = S0 > 50

    gq = GeneralizedQSamplingModel(gtab)
    gq.direction_finder.config(sphere=sphere, 
                                min_separation_angle=25, 
                                relative_peak_threshold=.35)
    gqfit = gq.fit(data, mask)
    gfa = gqfit.gfa
    peak_values = gqfit.peak_values
    peak_indices = gqfit.peak_indices
    qa = gqfit.qa
    #ODF = gqfit.odf(sphere)


    """
    data, gtab = half_to_full_qspace(data, gtab)
    ds = DiffusionSpectrumModel(gtab)
    ds.direction_finder.config(sphere=sphere, 
                                min_separation_angle=25, 
                                relative_peak_threshold=.35)

    dsfit = ds.fit(data, mask)
Exemple #16
0
def test_gqi():

    #load odf sphere
    vertices, faces = sphere_vf_from('symmetric724')
    edges = unique_edges(faces)
    half_vertices, half_edges, half_faces = reduce_antipodal(vertices, faces)

    #load bvals and gradients
    btable = np.loadtxt(get_data('dsi515btable'))
    bvals = btable[:, 0]
    bvecs = btable[:, 1:]
    S, stics = SticksAndBall(bvals,
                             bvecs,
                             d=0.0015,
                             S0=100,
                             angles=[(0, 0), (90, 0), (90, 90)],
                             fractions=[50, 50, 0],
                             snr=None)
    #pdf0,odf0,peaks0=standard_dsi_algorithm(S,bvals,bvecs)
    S2 = S.copy()
    S2 = S2.reshape(1, len(S))

    odf_sphere = (vertices, faces)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    dsfit = ds.fit(S)
    assert_equal((dsfit.peak_values > 0).sum(), 3)

    #change thresholds
    ds.relative_peak_threshold = 0.5
    ds.angular_distance_threshold = 30
    dsfit = ds.fit(S)
    assert_equal((dsfit.peak_values > 0).sum(), 2)

    #1 fiber
    S, stics = SticksAndBall(bvals,
                             bvecs,
                             d=0.0015,
                             S0=100,
                             angles=[(0, 0), (90, 0), (90, 90)],
                             fractions=[100, 0, 0],
                             snr=None)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    ds.relative_peak_threshold = 0.5
    ds.angular_distance_threshold = 20
    dsfit = ds.fit(S)
    QA = dsfit.qa
    #1/0
    assert_equal(np.sum(QA > 0), 1)

    #2 fibers
    S, stics = SticksAndBall(bvals,
                             bvecs,
                             d=0.0015,
                             S0=100,
                             angles=[(0, 0), (90, 0), (90, 90)],
                             fractions=[50, 50, 0],
                             snr=None)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    ds.relative_peak_threshold = 0.5
    ds.angular_distance_threshold = 20
    dsfit = ds.fit(S)
    QA = dsfit.qa
    assert_equal(np.sum(QA > 0), 2)

    #3 fibers
    S, stics = SticksAndBall(bvals,
                             bvecs,
                             d=0.0015,
                             S0=100,
                             angles=[(0, 0), (90, 0), (90, 90)],
                             fractions=[33, 33, 33],
                             snr=None)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    ds.relative_peak_threshold = 0.5
    dsfit = ds.fit(S)
    QA = dsfit.qa
    assert_equal(np.sum(QA > 0), 3)

    #isotropic
    S, stics = SticksAndBall(bvals,
                             bvecs,
                             d=0.0015,
                             S0=100,
                             angles=[(0, 0), (90, 0), (90, 90)],
                             fractions=[0, 0, 0],
                             snr=None)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere)
    dsfit = ds.fit(S)
    QA = dsfit.qa
    assert_equal(np.sum(QA > 0), 0)

    #3 fibers DSI2
    S, stics = SticksAndBall(bvals,
                             bvecs,
                             d=0.0015,
                             S0=100,
                             angles=[(0, 0), (90, 0), (90, 90)],
                             fractions=[33, 33, 33],
                             snr=None)
    ds = GeneralizedQSamplingModel(bvals, bvecs, odf_sphere, squared=True)
    ds.relative_peak_threshold = 0.5
    dsfit = ds.fit(S, gfa_thr=0.05)
    QA = dsfit.qa

    #3 fibers DSI2 with a 3D volume
    data = np.zeros((3, 3, 3, len(S)))
    data[..., :] = S.copy()
    dsfit = ds.fit(data, gfa_thr=0.05)
    #1/0
    assert_array_almost_equal(np.sum(dsfit.peak_values > 0, axis=-1),
                              3 * np.ones((3, 3, 3)))
Exemple #17
0
from dipy.reconst.odf import gfa
from dipy.reconst.dsi import DiffusionSpectrumDeconvModel
from dipy.data import get_sphere
from dipy.viz.mayavi.spheres import show_odfs
from load_data import get_train_dsi


data, affine, gtab = get_train_dsi(30)

gqi_model = GeneralizedQSamplingModel(gtab,
                                      method='gqi2',
                                      sampling_length=3,
                                      normalize_peaks=True)

crop = 20
gqi_fit = gqi_model.fit(data[crop:29,crop:29,crop:29])
sphere = get_sphere('symmetric724')
gqi_odf = gqi_fit.odf(sphere)
gqi_gfa = gfa(gqi_odf)

import nibabel as nib

affine[:3,3] +=  crop 
print affine
nib.save(nib.Nifti1Image(gqi_odf, affine), 'gqi_odf_norm.nii.gz')
nib.save(nib.Nifti1Image(gqi_gfa, affine), 'gfa_norm.nii.gz')

import numpy as np


np.savetxt('sphere724.txt', sphere.vertices)
Exemple #18
0
bvals, bvecs = read_bvals_bvecs(fdsi_bvals, fdsi_bvecs)
gtab = gradient_table(bvals, bvecs)


#sb = sticks_and_ball_dummies(gtab)

S, sticks = SticksAndBall(gtab, d=0.0015, S0=100,
                              angles=[(0, 0), (30, 0)],
                              fractions=[50, 50], snr=30.0)

sphere = get_sphere('symmetric724')
sphere = sphere.subdivide(n=1)

r=np.zeros(sphere.vertices.shape[0])
sampling_lengths=[1.25,1.5,2.,2.5,3.,3.5,4.]
for ss in sampling_lengths:

	gqi_model = GeneralizedQSamplingModel(gtab,
	                                      method='gqi2',
	                                      sampling_length=ss,
	                                      normalize_peaks=False)

	gqi_fit = gqi_model.fit(S)

	gqi_odf = gqi_fit.odf(sphere)

	r=np.vstack((r,gqi_odf))

show_odfs(r[:,None,None], sphere)