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
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)
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)
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)))
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))
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))