Skip to content
Merged
153 changes: 75 additions & 78 deletions odl/test/tomo/backends/astra_setup_test.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
# Copyright 2014-2017 The ODL contributors
# Copyright 2014-2019 The ODL contributors
#
# This file is part of ODL.
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.

"""Test astra setup functions."""
"""Test ASTRA setup functions."""

from __future__ import division

import numpy as np
import pytest
try:
import astra
except ImportError:
pass

import odl
from odl.tomo.backends.astra_setup import astra_supports
from odl.tomo.backends.astra_setup import (
astra_algorithm, astra_data, astra_projection_geometry, astra_projector,
astra_supports, astra_volume_geometry)
from odl.util.testutils import is_subdict

try:
import astra
except ImportError:
pass

pytestmark = pytest.mark.skipif("not odl.tomo.ASTRA_AVAILABLE")

Expand All @@ -40,7 +43,7 @@ def _discrete_domain(ndim, interp):
Returns a `DiscreteLp` instance
"""
max_pt = np.arange(1, ndim + 1)
min_pt = - max_pt
min_pt = -max_pt
shape = np.arange(1, ndim + 1) * 10

return odl.uniform_discr(min_pt, max_pt, shape=shape, interp=interp,
Expand Down Expand Up @@ -86,7 +89,7 @@ def test_vol_geom_2d():
'WindowMinY': -1.0, # x_min
'WindowMaxY': 1.0}} # x_amx

vol_geom = odl.tomo.astra_volume_geometry(discr_dom)
vol_geom = astra_volume_geometry(discr_dom)
assert vol_geom == correct_dict

# Anisotropic voxel case
Expand All @@ -101,11 +104,11 @@ def test_vol_geom_2d():
'WindowMaxY': 1.0}} # x_amx

if astra_supports('anisotropic_voxels_2d'):
vol_geom = odl.tomo.astra_volume_geometry(discr_dom)
vol_geom = astra_volume_geometry(discr_dom)
assert vol_geom == correct_dict
else:
with pytest.raises(NotImplementedError):
odl.tomo.astra_volume_geometry(discr_dom)
astra_volume_geometry(discr_dom)


def test_vol_geom_3d():
Expand All @@ -129,7 +132,7 @@ def test_vol_geom_3d():
'WindowMinZ': -1.0, # x_min
'WindowMaxZ': 1.0}} # x_amx

vol_geom = odl.tomo.astra_volume_geometry(discr_dom)
vol_geom = astra_volume_geometry(discr_dom)
assert vol_geom == correct_dict

discr_dom = _discrete_domain_anisotropic(3, 'nearest')
Expand All @@ -147,11 +150,11 @@ def test_vol_geom_3d():
'WindowMaxZ': 1.0}} # x_amx

if astra_supports('anisotropic_voxels_3d'):
vol_geom = odl.tomo.astra_volume_geometry(discr_dom)
vol_geom = astra_volume_geometry(discr_dom)
assert vol_geom == correct_dict
else:
with pytest.raises(NotImplementedError):
odl.tomo.astra_volume_geometry(discr_dom)
astra_volume_geometry(discr_dom)


def test_proj_geom_parallel_2d():
Expand All @@ -161,7 +164,7 @@ def test_proj_geom_parallel_2d():
dpart = odl.uniform_partition(-1, 1, 10)
geom = odl.tomo.Parallel2dGeometry(apart, dpart)

proj_geom = odl.tomo.astra_projection_geometry(geom)
proj_geom = astra_projection_geometry(geom)

correct_subdict = {
'type': 'parallel',
Expand All @@ -175,7 +178,7 @@ def test_astra_projection_geometry():
"""Create ASTRA projection geometry from geometry objects."""

with pytest.raises(TypeError):
odl.tomo.astra_projection_geometry(None)
astra_projection_geometry(None)

apart = odl.uniform_partition(0, 2 * np.pi, 5)
dpart = odl.uniform_partition(-40, 40, 10)
Expand All @@ -185,42 +188,42 @@ def test_astra_projection_geometry():
odl.RectGrid([0, 1, 3]))
geom_p2d = odl.tomo.Parallel2dGeometry(apart, dpart=dpart_0)
with pytest.raises(ValueError):
odl.tomo.astra_projection_geometry(geom_p2d)
astra_projection_geometry(geom_p2d)

# detector sampling grid, motion sampling grid
geom_p2d = odl.tomo.Parallel2dGeometry(apart, dpart)
odl.tomo.astra_projection_geometry(geom_p2d)
astra_projection_geometry(geom_p2d)

# Parallel 2D geometry
geom_p2d = odl.tomo.Parallel2dGeometry(apart, dpart)
astra_geom = odl.tomo.astra_projection_geometry(geom_p2d)
astra_geom = astra_projection_geometry(geom_p2d)
assert astra_geom['type'] == 'parallel'

# Fan flat
src_rad = 10
det_rad = 5
geom_ff = odl.tomo.FanBeamGeometry(apart, dpart, src_rad, det_rad)
astra_geom = odl.tomo.astra_projection_geometry(geom_ff)
astra_geom = astra_projection_geometry(geom_ff)
assert astra_geom['type'] == 'fanflat_vec'

dpart = odl.uniform_partition([-40, -3], [40, 3], (10, 5))

# Parallel 3D geometry
geom_p3d = odl.tomo.Parallel3dAxisGeometry(apart, dpart)
odl.tomo.astra_projection_geometry(geom_p3d)
astra_geom = odl.tomo.astra_projection_geometry(geom_p3d)
astra_projection_geometry(geom_p3d)
astra_geom = astra_projection_geometry(geom_p3d)
assert astra_geom['type'] == 'parallel3d_vec'

# Circular conebeam flat
geom_ccf = odl.tomo.ConeBeamGeometry(apart, dpart, src_rad, det_rad)
astra_geom = odl.tomo.astra_projection_geometry(geom_ccf)
astra_geom = astra_projection_geometry(geom_ccf)
assert astra_geom['type'] == 'cone_vec'

# Helical conebeam flat
pitch = 1
geom_hcf = odl.tomo.ConeBeamGeometry(apart, dpart, src_rad, det_rad,
pitch=pitch)
astra_geom = odl.tomo.astra_projection_geometry(geom_hcf)
astra_geom = astra_projection_geometry(geom_hcf)
assert astra_geom['type'] == 'cone_vec'


Expand All @@ -234,14 +237,14 @@ def test_volume_data_2d():
"""Create ASTRA data structure in 2D."""

# From scratch
data_id = odl.tomo.astra_data(VOL_GEOM_2D, 'volume', ndim=2)
data_id = astra_data(VOL_GEOM_2D, 'volume', ndim=2)
data_out = astra.data2d.get_shared(data_id)
assert data_out.shape == (10, 20)

# From existing
discr_dom = _discrete_domain(2, 'nearest')
data_in = discr_dom.element(np.ones((10, 20), dtype='float32'))
data_id = odl.tomo.astra_data(VOL_GEOM_2D, 'volume', data=data_in)
data_id = astra_data(VOL_GEOM_2D, 'volume', data=data_in)
data_out = astra.data2d.get_shared(data_id)
assert data_out.shape == (10, 20)

Expand All @@ -255,14 +258,14 @@ def test_volume_data_3d():
"""Create ASTRA data structure in 2D."""

# From scratch
data_id = odl.tomo.astra_data(VOL_GEOM_3D, 'volume', ndim=3)
data_id = astra_data(VOL_GEOM_3D, 'volume', ndim=3)
data_out = astra.data3d.get_shared(data_id)
assert data_out.shape == (10, 20, 30)

# From existing
discr_dom = _discrete_domain(3, 'nearest')
data_in = discr_dom.element(np.ones((10, 20, 30), dtype='float32'))
data_id = odl.tomo.astra_data(VOL_GEOM_3D, 'volume', data=data_in)
data_id = astra_data(VOL_GEOM_3D, 'volume', data=data_in)
data_out = astra.data3d.get_shared(data_id)
assert data_out.shape == (10, 20, 30)

Expand All @@ -281,68 +284,60 @@ def test_volume_data_3d():

def test_parallel_2d_projector():
"""Create ASTRA 2D projectors."""

# We can just test if it runs
odl.tomo.astra_projector('nearest', VOL_GEOM_2D, PROJ_GEOM_2D,
ndim=2, impl='cpu')
odl.tomo.astra_projector('linear', VOL_GEOM_2D, PROJ_GEOM_2D,
ndim=2, impl='cpu')
astra_projector('line', VOL_GEOM_2D, PROJ_GEOM_2D, ndim=2)
astra_projector('linear', VOL_GEOM_2D, PROJ_GEOM_2D, ndim=2)

with pytest.raises(ValueError):
astra_projector('line_fanflat', VOL_GEOM_2D, PROJ_GEOM_2D, ndim=2)
with pytest.raises(ValueError):
astra_projector('linearcone', VOL_GEOM_2D, PROJ_GEOM_2D, ndim=2)


@pytest.mark.xfail(reason='3D CPU projectors not supported by ASTRA')
def test_parallel_3d_projector():
"""Create ASTRA 3D projectors."""

# Run as a real test once ASTRA supports this construction
with pytest.raises(ValueError):
odl.tomo.astra_projector('nearest', VOL_GEOM_3D, PROJ_GEOM_3D,
ndim=3, impl='cpu')

with pytest.raises(ValueError):
odl.tomo.astra_projector('linear', VOL_GEOM_3D, PROJ_GEOM_3D,
ndim=3, impl='cpu')
# We can just test if it runs
astra_projector('linear3d', VOL_GEOM_3D, PROJ_GEOM_3D, ndim=3)


@pytest.mark.skipif(not odl.tomo.ASTRA_CUDA_AVAILABLE,
reason="ASTRA cuda not available")
reason="ASTRA CUDA not available")
def test_parallel_3d_projector_gpu():
"""Create ASTRA 3D projectors on GPU."""

odl.tomo.astra_projector('nearest', VOL_GEOM_3D, PROJ_GEOM_3D, ndim=3,
impl='cuda')
astra_projector('cuda3d', VOL_GEOM_3D, PROJ_GEOM_3D, ndim=3)


def test_astra_algorithm():
"""Create ASTRA algorithm object."""

direction = 'forward'
ndim = 2
impl = 'cpu'
vol_id = odl.tomo.astra_data(VOL_GEOM_2D, 'volume', ndim=ndim)
sino_id = odl.tomo.astra_data(PROJ_GEOM_2D, 'projection', ndim=ndim)
proj_id = odl.tomo.astra_projector('nearest', VOL_GEOM_2D, PROJ_GEOM_2D,
ndim=ndim, impl=impl)
vol_id = astra_data(VOL_GEOM_2D, 'volume', ndim=ndim)
sino_id = astra_data(PROJ_GEOM_2D, 'projection', ndim=ndim)
proj_id = astra_projector('linear', VOL_GEOM_2D, PROJ_GEOM_2D, ndim=ndim)

# Checks
with pytest.raises(ValueError):
odl.tomo.astra_algorithm('none', ndim, vol_id, sino_id, proj_id, impl)
astra_algorithm('none', ndim, vol_id, sino_id, proj_id, impl)
with pytest.raises(ValueError):
odl.tomo.astra_algorithm(direction, 0, vol_id, sino_id, proj_id, impl)
astra_algorithm(direction, 0, vol_id, sino_id, proj_id, impl)
with pytest.raises(ValueError):
odl.tomo.astra_algorithm('none', ndim, vol_id, sino_id, proj_id,
'none')
astra_algorithm('none', ndim, vol_id, sino_id, proj_id, 'none')
with pytest.raises(ValueError):
odl.tomo.astra_algorithm('backward', ndim, vol_id, sino_id,
proj_id=None, impl='cpu')
alg_id = odl.tomo.astra_algorithm(direction, ndim, vol_id, sino_id,
proj_id, impl)
astra_algorithm(
'backward', ndim, vol_id, sino_id, proj_id=None, impl='cpu'
)
alg_id = astra_algorithm(direction, ndim, vol_id, sino_id, proj_id, impl)
astra.algorithm.delete(alg_id)

# 2D CPU
ndim = 2
impl = 'cpu'
for direction in {'forward', 'backward'}:
alg_id = odl.tomo.astra_algorithm(direction, ndim, vol_id, sino_id,
proj_id, impl)
alg_id = astra_algorithm(
direction, ndim, vol_id, sino_id, proj_id, impl
)
astra.algorithm.delete(alg_id)


Expand All @@ -353,37 +348,39 @@ def test_astra_algorithm_gpu():

direction = 'forward'
ndim = 2
vol_id = odl.tomo.astra_data(VOL_GEOM_2D, 'volume', ndim=ndim)
rec_id = odl.tomo.astra_data(VOL_GEOM_2D, 'volume', ndim=ndim)
sino_id = odl.tomo.astra_data(PROJ_GEOM_2D, 'projection', ndim=ndim)
vol_id = astra_data(VOL_GEOM_2D, 'volume', ndim=ndim)
rec_id = astra_data(VOL_GEOM_2D, 'volume', ndim=ndim)
sino_id = astra_data(PROJ_GEOM_2D, 'projection', ndim=ndim)

# 2D CUDA
proj_id = odl.tomo.astra_projector('nearest', VOL_GEOM_2D, PROJ_GEOM_2D,
ndim=ndim, impl='cuda')
proj_id = astra_projector('cuda', VOL_GEOM_2D, PROJ_GEOM_2D, ndim=ndim)

# 2D CUDA FP
alg_id = odl.tomo.astra_algorithm('forward', ndim, vol_id, sino_id,
proj_id=proj_id, impl='cuda')
alg_id = astra_algorithm(
'forward', ndim, vol_id, sino_id, proj_id=proj_id, impl='cuda'
)
astra.algorithm.delete(alg_id)

# 2D CUDA BP
alg_id = odl.tomo.astra_algorithm('backward', ndim, rec_id, sino_id,
proj_id=proj_id, impl='cuda')
alg_id = astra_algorithm(
'backward', ndim, rec_id, sino_id, proj_id=proj_id, impl='cuda'
)
astra.algorithm.delete(alg_id)

ndim = 3
vol_id = odl.tomo.astra_data(VOL_GEOM_3D, 'volume', ndim=ndim)
sino_id = odl.tomo.astra_data(PROJ_GEOM_3D, 'projection', ndim=ndim)
proj_id = odl.tomo.astra_projector('nearest', VOL_GEOM_3D, PROJ_GEOM_3D,
ndim=ndim, impl='cuda')
vol_id = astra_data(VOL_GEOM_3D, 'volume', ndim=ndim)
sino_id = astra_data(PROJ_GEOM_3D, 'projection', ndim=ndim)
proj_id = astra_projector('cuda3d', VOL_GEOM_3D, PROJ_GEOM_3D, ndim=ndim)

with pytest.raises(NotImplementedError):
odl.tomo.astra_algorithm(direction, ndim, vol_id, sino_id,
proj_id=proj_id, impl='cpu')
astra_algorithm(
direction, ndim, vol_id, sino_id, proj_id=proj_id, impl='cpu'
)

for direction in {'forward', 'backward'}:
odl.tomo.astra_algorithm(direction, ndim, vol_id, sino_id,
proj_id=proj_id, impl='cuda')
astra_algorithm(
direction, ndim, vol_id, sino_id, proj_id=proj_id, impl='cuda'
)


def test_geom_to_vec():
Expand Down
4 changes: 2 additions & 2 deletions odl/test/tomo/backends/skimage_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import odl
from odl.tomo.backends.skimage_radon import (
skimage_radon_forward, skimage_radon_back_projector)
skimage_radon_forward_projector, skimage_radon_back_projector)
from odl.tomo.util.testutils import skip_if_no_skimage


Expand All @@ -34,7 +34,7 @@ def test_skimage_radon_projector_parallel2d():
proj_space = odl.uniform_discr_frompartition(geom.partition)

# Forward evaluation
proj_data = skimage_radon_forward(phantom, geom, proj_space)
proj_data = skimage_radon_forward_projector(phantom, geom, proj_space)
assert proj_data.shape == proj_space.shape
assert proj_data.norm() > 0

Expand Down
14 changes: 11 additions & 3 deletions odl/tomo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@
from .geometry import *
__all__ += geometry.__all__

from .backends import *
__all__ += backends.__all__

from .operators import *
__all__ += operators.__all__

from .analytic import *
__all__ += analytic.__all__

from .backends import (
ASTRA_AVAILABLE, ASTRA_CUDA_AVAILABLE, SKIMAGE_AVAILABLE,
astra_conebeam_2d_geom_to_vec, astra_conebeam_3d_geom_to_vec)
__all__ += (
'ASTRA_AVAILABLE',
'ASTRA_CUDA_AVAILABLE',
'SKIMAGE_AVAILABLE',
'astra_conebeam_2d_geom_to_vec',
'astra_conebeam_3d_geom_to_vec',
)
Loading