def test_empty_partition(): """Check if empty partitions behave as expected and all methods work.""" part = odl.RectPartition(odl.IntervalProd([], []), odl.uniform_grid([], [], ())) assert part.cell_boundary_vecs == () assert part.nodes_on_bdry is True assert part.nodes_on_bdry_byaxis == () assert part.has_isotropic_cells assert part.boundary_cell_fractions == () assert part.cell_sizes_vecs == () assert np.array_equal(part.cell_sides, []) assert part.cell_volume == 0 same = odl.RectPartition(odl.IntervalProd([], []), odl.uniform_grid([], [], ())) assert part == same assert hash(part) == hash(same) other = odl.uniform_partition(0, 1, 4) assert part != other assert part[[]] == part assert part.insert(0, other) == other assert other.insert(0, part) == other assert other.insert(1, part) == other assert part.squeeze() == part assert part.index([]) == () part.byaxis assert part == odl.uniform_partition([], [], ()) repr(part)
def test_reciprocal_grid_nd_halfcomplex(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) stride_last = 2 * np.pi / (s[-1] * n[-1]) n[-1] = n[-1] // 2 + 1 # Without shift rgrid = reciprocal_grid(grid, shift=False, halfcomplex=True) assert all_equal(rgrid.shape, n) assert rgrid.max_pt[-1] == 0 # last dim is odd # With shift rgrid = reciprocal_grid(grid, shift=True, halfcomplex=True) assert all_equal(rgrid.shape, n) assert rgrid.max_pt[-1] == -stride_last / 2 # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=True, halfcx_parity='odd') assert irgrid.approx_equals(grid, atol=1e-6) with pytest.raises(ValueError): realspace_grid(rgrid, grid.min_pt, halfcomplex=True, halfcx_parity='+')
def test_reciprocal_grid_nd_axes(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) axes_list = [[1, -1], [0], 0, [0, 2, 1], [2, 0]] for axes in axes_list: active = np.zeros(grid.ndim, dtype=bool) active[axes] = True inactive = np.logical_not(active) true_recip_stride = np.empty(grid.ndim) true_recip_stride[active] = 2 * np.pi / (s[active] * n[active]) true_recip_stride[inactive] = s[inactive] # Without shift altogether rgrid = reciprocal_grid(grid, shift=False, axes=axes, halfcomplex=False) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt[active], -rgrid.max_pt[active]) assert all_equal(rgrid.min_pt[inactive], grid.min_pt[inactive]) assert all_equal(rgrid.max_pt[inactive], grid.max_pt[inactive]) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, axes=axes, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_reciprocal_grid_1d(halfcomplex, shift, parity): shape = 10 if parity == 'even' else 11 grid = odl.uniform_grid(0, 1, shape=shape) s = grid.stride n = np.array(grid.shape) rgrid = reciprocal_grid(grid, shift=shift, halfcomplex=halfcomplex) # Independent of halfcomplex, shift and parity true_recip_stride = 2 * np.pi / (s * n) assert all_almost_equal(rgrid.stride, true_recip_stride) if halfcomplex: assert all_equal(rgrid.shape, n // 2 + 1) if parity == 'odd' and shift: # Max point should be half a negative recip stride assert all_almost_equal(rgrid.max_pt, -true_recip_stride / 2) elif parity == 'even' and not shift: # Max point should be half a positive recip stride assert all_almost_equal(rgrid.max_pt, true_recip_stride / 2) elif (parity == 'odd' and not shift) or (parity == 'even' and shift): # Max should be zero assert all_almost_equal(rgrid.max_pt, 0) else: raise RuntimeError('parameter combination not covered') else: # halfcomplex = False assert all_equal(rgrid.shape, n) if (parity == 'even' and shift) or (parity == 'odd' and not shift): # Zero should be at index n // 2 assert all_almost_equal(rgrid[n // 2], 0) elif (parity == 'odd' and shift) or (parity == 'even' and not shift): # No point should be closer to 0 than half a recip stride atol = 0.999 * true_recip_stride / 2 assert not rgrid.approx_contains(0, atol=atol) else: raise RuntimeError('parameter combination not covered') if not shift: # Grid Should be symmetric assert all_almost_equal(rgrid.min_pt, -rgrid.max_pt) if parity == 'odd': # Midpoint should be 0 assert all_almost_equal(rgrid.mid_pt, 0) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=halfcomplex, halfcx_parity=parity) assert irgrid.approx_equals(grid, atol=1e-6)
def test_reciprocal_grid_nd(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) true_recip_stride = 2 * np.pi / (s * n) # Without shift altogether rgrid = reciprocal_grid(grid, shift=False, halfcomplex=False) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt, -rgrid.max_pt) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_reciprocal_grid_nd_shift_list(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) shift = [False, True, False] true_recip_stride = 2 * np.pi / (s * n) # Shift only the even dimension, then zero must be contained rgrid = reciprocal_grid(grid, shift=shift, halfcomplex=False) noshift = np.where(np.logical_not(shift)) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt[noshift], -rgrid.max_pt[noshift]) assert all_almost_equal(rgrid[n // 2], [0] * 3) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_partition_cell_volume(): grid = odl.uniform_grid([0, 1], [2, 4], (5, 3)) intv = odl.IntervalProd([0, 1], [2, 4]) part = odl.RectPartition(intv, grid) true_volume = 0.5 * 1.5 assert part.cell_volume == true_volume
def test_partition_cell_sides(): grid = odl.uniform_grid([0, 1], [2, 4], (5, 3)) intv = odl.IntervalProd([0, 1], [2, 4]) part = odl.RectPartition(intv, grid) true_sides = [0.5, 1.5] assert all_equal(part.cell_sides, true_sides)
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 numba_example(): # Some functions are not easily vectorized, here we can use Numba to # improve performance. # See http://numba.pydata.org/ try: import numba except ImportError: print('Numba not installed, skipping.') return def myfunc(x): """Return x - y if x > y, otherwise return x + y.""" if x[0] > x[1]: return x[0] - x[1] else: return x[0] + x[1] # Numba expects functions f(x1, x2, x3, ...), while we have the # convention f(x) with x = (x1, x2, x3, ...). Therefore we need # to wrap the Numba-vectorized function. vectorized = numba.vectorize(lambda x, y: x - y if x > y else x + y) def myfunc_numba(x): """Return x - y if x > y, otherwise return x + y.""" return vectorized(x[0], x[1]) def myfunc_vec(x): """Return x - y if x > y, otherwise return x + y.""" # This implementation uses Numpy's fast built-in vectorization # directly. The function np.where checks the condition in the # first argument and takes the values from the second argument # for all entries where the condition is `True`, otherwise # the values from the third argument are taken. The arrays are # automatically broadcast, i.e. the broadcast shape of the # condition expression determines the output shape. return np.where(x[0] > x[1], x[0] - x[1], x[0] + x[1]) # Create (continuous) functions in the space of function defined # on the rectangle [0, 1] x [0, 1]. f_vec = sampling_function(myfunc_vec, domain=odl.IntervalProd([0, 0], [1, 1])) f_numba = sampling_function(myfunc_numba, domain=odl.IntervalProd([0, 0], [1, 1])) # Create a unform grid in [0, 1] x [0, 1] (fspace.domain) with 2000 # samples per dimension. grid = odl.uniform_grid([0, 0], [1, 1], shape=(2000, 2000)) # The points() method really creates all grid points (2000^2) and # stores them one-by-one (row-wise) in a large array with shape # (2000*2000, 2). Since the function expects points[i] to be the # array of i-th components of all points, we need to transpose. points = grid.points().T # The meshgrid property only returns a sparse representation of the # grid, a tuple whose i-th entry is the vector of all possible i-th # components in the grid (2000). Extra dimensions are added to the # vector in order to support automatic broadcasting. This is both # faster and more memory-friendly than creating the full point array. # See the numpy.meshgrid function for more information. mesh = grid.meshgrid # Returns a sparse meshgrid (2000 * 2) print('Native vectorized runtime (points): {:5f}' ''.format(timeit.timeit(lambda: f_vec(points), number=1))) print('Native vectorized runtime (meshgrid): {:5f}' ''.format(timeit.timeit(lambda: f_vec(mesh), number=1))) print('Numba vectorized runtime (points): {:5f}' ''.format(timeit.timeit(lambda: f_numba(points), number=1))) print('Numba vectorized runtime (meshgrid): {:5f}' ''.format(timeit.timeit(lambda: f_numba(mesh), number=1)))