Ejemplo n.º 1
0
def test_discretelp_init():
    """Test initialization and basic properties of DiscreteLp."""
    # Real space
    fspace = odl.FunctionSpace(odl.IntervalProd([0, 0], [1, 1]))
    part = odl.uniform_partition_fromintv(fspace.domain, (2, 4))
    tspace = odl.rn(part.shape)

    discr = DiscreteLp(fspace, part, tspace)
    assert discr.fspace == fspace
    assert discr.tspace == tspace
    assert discr.partition == part
    assert discr.interp == 'nearest'
    assert discr.interp_byaxis == ('nearest', 'nearest')
    assert discr.exponent == tspace.exponent
    assert discr.axis_labels == ('$x$', '$y$')
    assert discr.is_real

    discr = DiscreteLp(fspace, part, tspace, interp='linear')
    assert discr.interp == 'linear'
    assert discr.interp_byaxis == ('linear', 'linear')

    discr = DiscreteLp(fspace, part, tspace, interp=['nearest', 'linear'])
    assert discr.interp == ('nearest', 'linear')
    assert discr.interp_byaxis == ('nearest', 'linear')

    # Complex space
    fspace_c = odl.FunctionSpace(odl.IntervalProd([0, 0], [1, 1]),
                                 out_dtype=complex)
    tspace_c = odl.cn(part.shape)
    discr = DiscreteLp(fspace_c, part, tspace_c)
    assert discr.is_complex

    # Make sure repr shows something
    assert repr(discr)

    # Error scenarios
    with pytest.raises(ValueError):
        DiscreteLp(fspace, part, tspace_c)  # mixes real & complex

    with pytest.raises(ValueError):
        DiscreteLp(fspace_c, part, tspace)  # mixes complex & real

    part_1d = odl.uniform_partition(0, 1, 2)
    with pytest.raises(ValueError):
        DiscreteLp(fspace, part_1d, tspace)  # wrong dimensionality

    part_diffshp = odl.uniform_partition_fromintv(fspace.domain, (3, 4))
    with pytest.raises(ValueError):
        DiscreteLp(fspace, part_diffshp, tspace)  # shape mismatch
Ejemplo n.º 2
0
    def __init__(self, discr_domain, geometry, impl='astra_cpu', **kwargs):
        """Initialize a new instance.

        Parameters
        ----------
        discr_domain : `DiscreteLp`
            Discretized space, the domain of the forward projector
        geometry : `Geometry`
            Geometry of the transform, containing information about
            the operator range
        impl : {'astra_cpu', 'astra_cuda', 'scikit'}, optional
            Implementation back-end for the transform. Supported back-ends:
            'astra_cpu': ASTRA toolbox using CPU, only 2D
            'astra_cuda': ASTRA toolbox, using CUDA, 2D or 3D
            'scikit': scikit-image, only 2D parallel with square domain
        interp : {'nearest', 'linear'}
            Interpolation type for the discretization of the operator
            range.
            Default: 'nearest'
        """
        if not isinstance(discr_domain, DiscreteLp):
            raise TypeError('`discr_domain` {!r} is not a `DiscreteLp`'
                            ' instance'.format(discr_domain))

        if not isinstance(geometry, Geometry):
            raise TypeError('`geometry` {!r} is not a `Geometry` instance'
                            ''.format(geometry))

        impl, impl_in = str(impl).lower(), impl
        if impl not in _SUPPORTED_IMPL:
            raise ValueError('`impl` {!r} not supported'
                             ''.format(impl_in))

        # TODO: sanity checks between impl and discretization impl
        if impl.startswith('astra'):
            # TODO: these should be moved somewhere else
            if not ASTRA_AVAILABLE:
                raise ValueError("'astra' back-end not available")
            if impl == 'astra_cuda' and not ASTRA_CUDA_AVAILABLE:
                raise ValueError("'astra_cuda' back-end not available")
            if discr_domain.dspace.dtype not in (np.float32, np.complex64):
                raise ValueError('ASTRA support is limited to `float32` for '
                                 'real and `complex64` for complex data')
            if not np.allclose(discr_domain.partition.cell_sides[1:],
                               discr_domain.partition.cell_sides[:-1]):
                raise ValueError('ASTRA does not support different voxel '
                                 'sizes per axis, got {}'
                                 ''.format(discr_domain.partition.cell_sides))
            if geometry.ndim > 2 and impl.endswith('cpu'):
                raise ValueError('`impl` {}, only works for 2d geometries'
                                 ' got {}-d'.format(impl_in, geometry))
        elif impl == 'scikit':
            if not isinstance(geometry, Parallel2dGeometry):
                raise TypeError("'scikit' backend only supports 2d parallel "
                                'geometries')

            midp = discr_domain.domain.midpoint
            if not all(midp == [0, 0]):
                raise ValueError('`discr_domain.domain` needs to be '
                                 'centered on [0, 0], got {}'.format(midp))

            shape = discr_domain.shape
            if shape[0] != shape[1]:
                raise ValueError('`discr_domain.shape` needs to be square '
                                 'got {}'.format(shape))

            extent = discr_domain.domain.extent()
            if extent[0] != extent[1]:
                raise ValueError('`discr_domain.extent` needs to be square '
                                 'got {}'.format(extent))

        # TODO: sanity checks between domain and geometry (ndim, ...)
        self._geometry = geometry
        self._impl = impl
        self.kwargs = kwargs

        dtype = discr_domain.dspace.dtype

        # Create a discretized space (operator range) with the same data-space
        # type as the domain.
        # TODO: use a ProductSpace structure or find a way to treat different
        # dimensions differently in DiscreteLp (i.e. in partitions).
        range_uspace = FunctionSpace(geometry.params,
                                     out_dtype=dtype)

        # Approximate cell volume
        # TODO: angles and detector must be handled separately. While the
        # detector should be uniformly discretized, the angles do not have
        # to and often are not.
        extent = float(geometry.partition.extent().prod())
        size = float(geometry.partition.size)
        weight = extent / size

        range_dspace = discr_domain.dspace_type(geometry.partition.size,
                                                weight=weight, dtype=dtype)

        range_interp = kwargs.get('interp', 'nearest')
        discr_range = DiscreteLp(
            range_uspace, geometry.partition, range_dspace,
            interp=range_interp, order=discr_domain.order)

        super().__init__(discr_domain, discr_range, linear=True)
Ejemplo n.º 3
0
    def __init__(self, discr_range, geometry, impl='astra_cpu', **kwargs):
        """Initialize a new instance.

        Parameters
        ----------
        discr_range : `DiscreteLp`
            Reconstruction space, the range of the back-projector
        geometry : `Geometry`
            The geometry of the transform, contains information about
            the operator domain
        impl : {'astra_cpu', 'astra_cuda', 'scikit'}, optional
            Implementation back-end for the transform. Supported back-ends:
            'astra_cpu': ASTRA toolbox using CPU, only 2D
            'astra_cuda': ASTRA toolbox, using CUDA, 2D or 3D
            'scikit': scikit-image, only 2D parallel with square domain
        interp : {'nearest', 'linear'}
            Interpolation type for the discretization of the operator range.
            Default: 'nearest'
        """
        if not isinstance(discr_range, DiscreteLp):
            raise TypeError('`discr_range` {!r} is not a `DiscreteLp`'
                            ' instance'.format(discr_range))

        if not isinstance(geometry, Geometry):
            raise TypeError('`geometry` {!r} is not a `Geometry` instance'
                            ''.format(geometry))

        impl, impl_in = str(impl).lower(), impl
        if impl not in _SUPPORTED_IMPL:
            raise ValueError("`impl` '{}' not supported"
                             ''.format(impl_in))

        if impl.startswith('astra'):
            if not ASTRA_AVAILABLE:
                raise ValueError("'astra' backend not available")
            if impl == 'astra_cuda' and not ASTRA_CUDA_AVAILABLE:
                raise ValueError("'astra_cuda' backend not available")
            if discr_range.dspace.dtype not in (np.float32, np.complex64):
                raise ValueError('ASTRA support is limited to `float32` for '
                                 'real and `complex64` for complex data')
            if not np.allclose(discr_range.partition.cell_sides[1:],
                               discr_range.partition.cell_sides[:-1]):
                raise ValueError('ASTRA does not support different voxel '
                                 'sizes per axis, got {}'
                                 ''.format(discr_range.partition.cell_sides))

        self._geometry = geometry
        self._impl = impl
        self.kwargs = kwargs

        dtype = discr_range.dspace.dtype

        # Create a discretized space (operator domain) with the same data-space
        # type as the range.
        domain_uspace = FunctionSpace(geometry.params, out_dtype=dtype)

        # Approximate cell volume
        extent = float(geometry.partition.extent().prod())
        size = float(geometry.partition.size)
        weight = extent / size

        domain_dspace = discr_range.dspace_type(geometry.partition.size,
                                                weight=weight, dtype=dtype)

        domain_interp = kwargs.get('interp', 'nearest')
        disc_domain = DiscreteLp(
            domain_uspace, geometry.partition, domain_dspace,
            interp=domain_interp, order=discr_range.order)
        super().__init__(disc_domain, discr_range, linear=True)
Ejemplo n.º 4
0
def test_norm_rectangle_boundary(odl_tspace_impl, exponent):
    # Check the constant function 1 in different situations regarding the
    # placement of the outermost grid points.
    impl = odl_tspace_impl

    dtype = 'float32'
    rect = odl.IntervalProd([-1, -2], [1, 2])
    fspace = odl.FunctionSpace(rect, out_dtype=dtype)

    # Standard case
    discr = odl.uniform_discr_fromspace(fspace, (4, 8),
                                        impl=impl,
                                        exponent=exponent)
    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert (discr.one().norm() == pytest.approx(rect.volume**(1 /
                                                                  exponent)))

    # Nodes on the boundary (everywhere)
    discr = odl.uniform_discr_fromspace(fspace, (4, 8),
                                        exponent=exponent,
                                        impl=impl,
                                        nodes_on_bdry=True)

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert (discr.one().norm() == pytest.approx(rect.volume**(1 /
                                                                  exponent)))

    # Nodes on the boundary (selective)
    discr = odl.uniform_discr_fromspace(fspace, (4, 8),
                                        exponent=exponent,
                                        impl=impl,
                                        nodes_on_bdry=((False, True), False))

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert (discr.one().norm() == pytest.approx(rect.volume**(1 /
                                                                  exponent)))

    discr = odl.uniform_discr_fromspace(fspace, (4, 8),
                                        exponent=exponent,
                                        impl=impl,
                                        nodes_on_bdry=(False, (True, False)))

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert (discr.one().norm() == pytest.approx(rect.volume**(1 /
                                                                  exponent)))

    # Completely arbitrary boundary
    grid = odl.uniform_grid([0, 0], [1, 1], (4, 4))
    part = odl.RectPartition(rect, grid)
    weight = 1.0 if exponent == float('inf') else part.cell_volume
    tspace = odl.rn(part.shape,
                    dtype=dtype,
                    impl=impl,
                    exponent=exponent,
                    weighting=weight)
    discr = DiscreteLp(fspace, part, tspace)

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert (discr.one().norm() == pytest.approx(rect.volume**(1 /
                                                                  exponent)))
Ejemplo n.º 5
0
def test_norm_rectangle_boundary(fn_impl, exponent):
    # Check the constant function 1 in different situations regarding the
    # placement of the outermost grid points.

    if exponent == float('inf'):
        pytest.xfail('inf-norm not implemented in CUDA')

    dtype = 'float32'
    rect = odl.IntervalProd([-1, -2], [1, 2])
    fspace = odl.FunctionSpace(rect, out_dtype=dtype)

    # Standard case
    discr = odl.uniform_discr_fromspace(fspace, (4, 8),
                                        impl=fn_impl, exponent=exponent)
    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    # Nodes on the boundary (everywhere)
    discr = odl.uniform_discr_fromspace(
        fspace, (4, 8), exponent=exponent,
        impl=fn_impl, nodes_on_bdry=True)

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    # Nodes on the boundary (selective)
    discr = odl.uniform_discr_fromspace(
        fspace, (4, 8), exponent=exponent,
        impl=fn_impl, nodes_on_bdry=((False, True), False))

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    discr = odl.uniform_discr_fromspace(
        fspace, (4, 8), exponent=exponent,
        impl=fn_impl, nodes_on_bdry=(False, (True, False)))

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    # Completely arbitrary boundary
    grid = odl.uniform_grid([0, 0], [1, 1], (4, 4))
    part = odl.RectPartition(rect, grid)
    weight = 1.0 if exponent == float('inf') else part.cell_volume
    dspace = odl.rn(part.size, dtype=dtype, impl=fn_impl, exponent=exponent,
                    weighting=weight)
    discr = DiscreteLp(fspace, part, dspace, exponent=exponent)

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))
Ejemplo n.º 6
0
def test_norm_rectangle_boundary(impl, exponent):
    # Check the constant function 1 in different situations regarding the
    # placement of the outermost grid points.

    if exponent == float('inf'):
        pytest.xfail('inf-norm not implemented in CUDA')

    rect = odl.Rectangle([-1, -2], [1, 2])

    # Standard case
    discr = odl.uniform_discr_fromspace(odl.FunctionSpace(rect), (4, 8),
                                        impl=impl, exponent=exponent)
    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    # Nodes on the boundary (everywhere)
    discr = odl.uniform_discr_fromspace(
        odl.FunctionSpace(rect), (4, 8), exponent=exponent,
        impl=impl, nodes_on_bdry=True)

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    # Nodes on the boundary (selective)
    discr = odl.uniform_discr_fromspace(
        odl.FunctionSpace(rect), (4, 8), exponent=exponent,
        impl=impl, nodes_on_bdry=((False, True), False))

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    discr = odl.uniform_discr_fromspace(
        odl.FunctionSpace(rect), (4, 8), exponent=exponent,
        impl=impl, nodes_on_bdry=(False, (True, False)))

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))

    # Completely arbitrary boundary
    grid = odl.RegularGrid([0, 0], [1, 1], (4, 4))
    part = odl.RectPartition(rect, grid)
    weight = 1.0 if exponent == float('inf') else part.cell_volume
    dspace = odl.Rn(part.size, exponent=exponent, weight=weight)
    discr = DiscreteLp(odl.FunctionSpace(rect), part, dspace,
                       impl=impl, exponent=exponent)

    if exponent == float('inf'):
        assert discr.one().norm() == 1
    else:
        assert almost_equal(discr.one().norm(),
                            (rect.volume) ** (1 / exponent))