Exemplo n.º 1
0
    def test_get_extrapolation_points(self, setup):
        """
        Check that the points to be used for extrapolation are identified
        correctly.
        """
        key = setup['key']
        order = 4

        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        bcs = BoundaryConditions({2 * i: 0
                                  for i in range(1 + order // 2)}, order)

        stencils = StencilSet(2, 0, bcs, cache=cache)

        out_l, out_r = stencils._get_outside(key)

        ext_l, ext_r, l_floor, r_floor = stencils._get_extrapolation_points(
            key, out_l, out_r)

        # Should be false in this case
        if setup['f']:
            assert l_floor or r_floor
        else:
            assert not l_floor or r_floor

        assert np.all(ext_l == setup['el'])
        assert np.all(ext_r == setup['er'])
Exemplo n.º 2
0
    def test_get_keys(self, order, setup):
        """
        Test that the keys returned are correct
        """
        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        offset = setup['offset']
        deriv = setup['deriv']

        if setup['bcs'] == 'even':
            bcs = BoundaryConditions({2 * i: 0
                                      for i in range(1 + order // 2)}, order)
            key_len = order + 1
            min_left = 0.5 - order // 2
            max_right = order // 2 - 0.5
        else:
            bcs = BoundaryConditions(
                {2 * i + 1: 0
                 for i in range(1 + order // 2)}, order)
            key_len = order + 3
            min_left = -0.5 - order // 2
            max_right = order // 2 + 0.5

        stencils = StencilSet(deriv, offset, bcs, cache=cache)

        keys = stencils._get_keys()

        if offset == 0:
            assert keys.shape[0] == key_len**2
        else:
            assert keys.shape[0] == key_len * (key_len + 1)

        left = keys[:, 0]
        right = keys[:, 1]

        max_left = 0
        min_right = 0
        if offset == -0.5:
            min_right = -0.5
        elif offset == 0.5:
            max_left = 0.5

        assert np.amax(left[~np.isnan(left)]) == max_left
        assert np.amin(left[~np.isnan(left)]) == min_left

        assert np.amax(right[~np.isnan(right)]) == max_right
        assert np.amin(right[~np.isnan(right)]) == min_right
Exemplo n.º 3
0
    def test_get_outside(self, setup):
        """Check that oints outside boundary are identified correctly"""
        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'
        order = setup['ord']
        key = (setup['l'], setup['r'])

        bcs = BoundaryConditions({2 * i + 1: 0
                                  for i in range(1 + order // 2)}, order)

        # Quick test so only on one stencil type
        stencils = StencilSet(1, -0.5, bcs, cache=cache)

        points_l, points_r = stencils._get_outside(key)

        assert np.all(points_l == setup['el'])
        assert np.all(points_r == setup['er'])
Exemplo n.º 4
0
    def test_zero_handling(self, order, spec):
        """
        Check that stencils with distances of zero evaluate correctly.
        """
        # Unpack the spec
        bc_type = spec['bcs']
        deriv = spec['deriv']
        goffset = spec['goffset']
        eoffset = spec['eoffset']
        if bc_type == 'even':
            bcs = BoundaryConditions({2 * i: 0
                                      for i in range(1 + order // 2)}, order)
        else:
            bcs = BoundaryConditions(
                {2 * i + 1: 0
                 for i in range(1 + order // 2)}, order)

        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        stencils = StencilSet(deriv, eoffset, bcs, cache=cache)
        lambdas = stencils.lambdaify
        max_ext_points = stencils.max_ext_points

        distances = np.full((10, 1, 1), -2 * order, dtype=float)
        if goffset == 0.5:
            distances[4, :, :] = 0.5
        else:
            distances[4, :, :] = 0

        data = get_data_inc_reciprocals(distances, 1, 'x', goffset, eoffset)
        add_distance_column(data)
        data = data.iloc[1:-1]
        data = get_n_pts(data, 'double', order, eoffset)

        grid = Grid(shape=(10, 1, 11), extent=(9, 0, 0))
        s_dim = Dimension(name='s')
        ncoeffs = 2 * max_ext_points + 1

        w_shape = grid.shape + (ncoeffs, )
        w_dims = grid.dimensions + (s_dim, )

        w = Function(name='w', dimensions=w_dims, shape=w_shape)

        fill_stencils(data, 'double', max_ext_points, lambdas, w, 10, 'x')

        # Derivative stencils should be zero if evaluation offset is zero
        assert (np.all(np.abs(w.data) < np.finfo(np.float).eps))
Exemplo n.º 5
0
    def test_stencil_evaluation(self, order, spec, inside, dist_val):
        """Check that stencil coefficients are selected and evaluated to expected values"""
        # Unpack the spec
        bc_type = spec['bcs']
        deriv = spec['deriv']
        goffset = spec['goffset']
        eoffset = spec['eoffset']

        if bc_type == 'even':
            bcs = BoundaryConditions({2 * i: 0
                                      for i in range(1 + order // 2)}, order)
        else:
            bcs = BoundaryConditions(
                {2 * i + 1: 0
                 for i in range(1 + order // 2)}, order)

        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        # stencils_lambda = get_stencils_lambda(deriv, eoffset, bcs, cache=cache)
        stencils = StencilSet(deriv, eoffset, bcs, cache=cache)
        lambdas = stencils.lambdaify
        max_ext_points = stencils.max_ext_points

        # Generate a suitable 1D distance field, hitting several stencil types
        distances = np.full((10, 1, 1), -order // 2, dtype=float)
        ind = np.array([1, 2, 5])
        distances[ind] = dist_val

        # Create a function to generate weights for
        grid = Grid(shape=(10, 1, 1), extent=(9, 0, 0))
        x, y, z = grid.dimensions
        if goffset == 0.:
            f = Function(name='f', grid=grid, space_order=order)
        elif goffset == 0.5:
            f = Function(name='f', grid=grid, space_order=order, staggered=x)

        # Generate an accompanying section
        interior = np.full((10, 1, 1), False)
        if inside:
            # Generate one segmentation
            inner_points = np.array([0, 1, 3, 4, 5])
        else:
            # Generate the other segmentation
            inner_points = np.array([2, 6, 7, 8, 9])
        interior[inner_points] = True

        # Evaluate stencils
        w = get_component_weights(distances, 0, f, deriv, lambdas, interior,
                                  max_ext_points, eoffset)

        # Check against precalculated stencils
        # Generate filename
        filename = str(dist_val) + '_' + str(inside) + '_' + str(
            order) + '_' + bc_type + '_' + str(deriv) + '_' + str(
                goffset) + '_' + str(eoffset)
        # Load reference data
        reference = np.load(
            os.path.dirname(__file__) + '/evaluated_stencils/' + filename +
            '.npy')

        assert np.all(np.absolute(w.data - reference) < np.finfo(float).eps)
Exemplo n.º 6
0
    def test_zero_handling_staggered(self, side, order, spec):
        """
        Check that stencils with distances of zero evaluate correctly for staggered
        systems.
        """
        # Unpack the spec
        bc_type = spec['bcs']
        deriv = spec['deriv']
        goffset = spec['goffset']
        eoffset = spec['eoffset']
        if bc_type == 'even':
            bcs = BoundaryConditions({2 * i: 0
                                      for i in range(1 + order // 2)}, order)
        else:
            bcs = BoundaryConditions(
                {2 * i + 1: 0
                 for i in range(1 + order // 2)}, order)

        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        # stencils_lambda = get_stencils_lambda(deriv, eoffset, bcs, cache=cache)
        stencils = StencilSet(deriv, eoffset, bcs, cache=cache)
        lambdas = stencils.lambdaify
        max_ext_points = stencils.max_ext_points

        distances = np.full((10, 1, 1), -2 * order, dtype=float)
        if goffset == 0.5:
            distances[4, :, :] = 0.5
        else:
            distances[4, :, :] = 0

        data = get_data_inc_reciprocals(distances, 1, 'x', goffset, eoffset)
        add_distance_column(data)

        right_dist = pd.notna(data.eta_l)
        left_dist = pd.notna(data.eta_r)
        data.loc[right_dist, 'dist'] = order
        data.loc[left_dist, 'dist'] = -order

        first = data.loc[left_dist]
        last = data.loc[right_dist]
        first = shift_grid_endpoint(first, 'x', goffset, eoffset)
        last = shift_grid_endpoint(last, 'x', goffset, eoffset)
        first = get_n_pts(first, 'first', order, eoffset)
        last = get_n_pts(last, 'last', order, eoffset)

        grid = Grid(shape=(10, 1, 1), extent=(9, 0, 0))
        s_dim = Dimension(name='s')
        ncoeffs = 2 * max_ext_points + 1

        w_shape = grid.shape + (ncoeffs, )
        w_dims = grid.dimensions + (s_dim, )

        w = Function(name='w', dimensions=w_dims, shape=w_shape)

        # Fill the weights using the standard stencil (for interior)
        if max_ext_points > order // 2:
            # Need to zero pad the standard stencil
            zero_pad = max_ext_points - order // 2
            w.data[:, :, :,
                   zero_pad:-zero_pad] = standard_stencil(deriv,
                                                          order,
                                                          offset=eoffset)
        else:
            w.data[:] = standard_stencil(deriv, order, offset=eoffset)

        if side == 'first':
            w.data[4:] = 0
            fill_stencils(first, 'first', max_ext_points, lambdas, w, 10, 'x')
        if side == 'last':
            w.data[:5] = 0
            fill_stencils(last, 'last', max_ext_points, lambdas, w, 10, 'x')

        # Check against a saved correct version
        # Generate filename
        filename = side + '_' + str(order) + '_' + bc_type + '_' + str(
            deriv) + '_' + str(goffset) + '_' + str(eoffset)

        # Load reference data
        reference = np.load(
            os.path.dirname(__file__) + '/zero_handling_stencils/' + filename +
            '.npy')

        assert np.all(np.absolute(w.data - reference) < np.finfo(float).eps)
Exemplo n.º 7
0
    def test_fill_stencils_offset(self, offset, point_type, order, spacing):
        """
        Check that offsetting the grid and boundary by the same amount results
        in identical stencils for both cases. This is checked on both sides of
        the boundary.
        """

        spec = {2 * i: 0 for i in range(1 + order // 2)}
        bcs = BoundaryConditions(spec, order)
        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        stencils = StencilSet(2, 0, bcs, cache=cache)
        lambdas = stencils.lambdaify
        max_ext_points = stencils.max_ext_points

        distances = np.full((10, 1, 10), -2 * order * spacing, dtype=float)
        distances[4, :, :] = np.linspace(0, 0.9 * spacing, 10)

        offset_distances = np.full((10, 1, 10),
                                   -2 * order * spacing,
                                   dtype=float)
        if offset == 0.5:
            # +ve stagger
            offset_distances[4, :, :5] = np.linspace(0.5 * spacing,
                                                     0.9 * spacing, 5)
            offset_distances[5, :, 5:] = np.linspace(0, 0.4 * spacing, 5)
        else:
            # -ve stagger
            offset_distances[4, :, :] = np.linspace(-0.5 * spacing,
                                                    0.4 * spacing, 10)

        data = get_data_inc_reciprocals(distances, spacing, 'x', 0, 0)
        offset_data = get_data_inc_reciprocals(offset_distances, spacing, 'x',
                                               offset, 0)
        dmask = np.full(21, True, dtype=bool)
        dmask[1] = False
        data = data[dmask]
        offset_data = offset_data[dmask]
        add_distance_column(data)
        add_distance_column(offset_data)
        if point_type == 'first':
            data = data[::2]
            data.dist = -order // 2
            offset_data = offset_data[::2]
            offset_data.dist = -order // 2
            # No need to drop points or shift grid endpoint, as that is done here

        else:
            data = data[1::2]
            data.dist = order // 2
            offset_data = offset_data[1::2]
            offset_data.dist = order // 2
            # No need to drop points or shift grid endpoint, as that is done here

        # Set n_pts
        data['n_pts'] = order // 2
        offset_data['n_pts'] = order // 2

        grid = Grid(shape=(10, 1, 10), extent=(9 * spacing, 0, 9 * spacing))
        s_dim = Dimension(name='s')
        ncoeffs = order + 1

        w_shape = grid.shape + (ncoeffs, )
        w_dims = grid.dimensions + (s_dim, )

        w_normal = Function(name='w_n', dimensions=w_dims, shape=w_shape)
        w_offset = Function(name='w_o', dimensions=w_dims, shape=w_shape)

        fill_stencils(data, point_type, max_ext_points, lambdas, w_normal, 10,
                      'x')
        fill_stencils(offset_data, point_type, max_ext_points, lambdas,
                      w_offset, 10, 'x')

        if point_type == 'first':
            assert np.all(np.isclose(w_normal.data[2:5], w_offset.data[2:5]))
        else:
            assert np.all(np.isclose(w_normal.data[5:7], w_offset.data[5:7]))
Exemplo n.º 8
0
def get_weights(data,
                function,
                deriv,
                bcs,
                interior,
                fill_function=None,
                eval_offsets=(0., 0., 0.)):
    """
    Get the modified stencil weights for a function and derivative given the
    axial distances.

    Parameters
    ----------
    data : devito VectorFunction
        The axial distance function
    function : devito Function
        The function for which stencils should be calculated
    deriv : int
        The order of the derivative to which the stencils pertain
    bcs : list of devito Eq
        The boundary conditions which should hold at the surface
    interior : ndarray
        The interior-exterior segmentation of the domain
    fill_function : devito Function
        A secondary function to use when creating the Coefficient objects. If none
        then the Function supplied with the function argument will be used instead.
    eval_offsets : tuple of float
        The relative offsets at which derivatives should be evaluated for each
        axis.

    Returns
    -------
    substitutions : tuple of Coefficient
        The substitutions to be included in the devito equation
    """
    cache = os.path.dirname(__file__) + '/extrapolation_cache.dat'

    # This wants to start as an empty list
    weights = []
    for axis in range(3):
        print(deriv, function, function.grid.dimensions[axis])
        stencils = StencilSet(deriv, eval_offsets[axis], bcs, cache=cache)
        lambdas = stencils.lambdaify
        max_span = stencils.max_span

        axis_weights = get_component_weights(data[axis].data, axis, function,
                                             deriv, lambdas, interior,
                                             max_span, eval_offsets[axis])

        if fill_function is None:
            weights.append(
                Coefficient(deriv, function, function.grid.dimensions[axis],
                            axis_weights))
        else:
            weights.append(
                Coefficient(deriv, fill_function,
                            fill_function.grid.dimensions[axis], axis_weights))

    # Raise error if list is empty
    if len(weights) == 0:
        raise ValueError("No boundary-adjacent points in provided fields")
    return tuple(weights)
Exemplo n.º 9
0
    def test_derivative_recovery(self, setup):
        """
        Test that appropriate polynomials and their derivatives are exactly
        recovered by the generated stencils.
        """
        print(setup)
        # First need to create the stencils and get the lambdaified versions
        order = setup['order']

        if setup['bcs'] == 'even':
            bcs = BoundaryConditions({2 * i: 0
                                      for i in range(1 + order // 2)}, order)

            # Define benchmark function
            def fnc(x):
                return sum([
                    x**term if term % 2 != 0 else 0
                    for term in range(order + 1)
                ])

            if setup['deriv'] == 1:

                def tru_drv(x):
                    return sum([
                        term * x**(term - 1) if term % 2 != 0 else 0
                        for term in range(1, order + 1)
                    ])
            elif setup['deriv'] == 2:

                def tru_drv(x):
                    return sum([
                        term * (term - 1) *
                        x**(term - 2) if term % 2 != 0 else 0
                        for term in range(2, order + 1)
                    ])
        else:
            bcs = BoundaryConditions(
                {2 * i + 1: 0
                 for i in range(1 + order // 2)}, order)

            # Define benchmark function
            def fnc(x):
                return sum([
                    x**term if term % 2 == 0 else 0
                    for term in range(order + 1)
                ])

            if setup['deriv'] == 1:

                def tru_drv(x):
                    return sum([
                        term * x**(term - 1) if term % 2 == 0 else 0
                        for term in range(1, order + 1)
                    ])
            elif setup['deriv'] == 2:

                def tru_drv(x):
                    return sum([
                        term * (term - 1) * x**(term - 2) if term %
                        2 == 0 else 0 for term in range(2, order + 1)
                    ])

        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        stencils = StencilSet(setup['deriv'],
                              setup['offset'],
                              bcs,
                              cache=cache)

        lambdas = stencils.lambdaify

        # Create a set of distances to test and a corresponding set of keys
        l_mod = setup['offset'] == 0.5
        r_mod = setup['offset'] == -0.5
        # TODO: Would be more rigorous if it used separate left and right distances
        distances = np.linspace(0.1 - order / 2 + l_mod,
                                order / 2 - 0.1 - r_mod, 5 * order)
        if setup['offset'] == 0.5:
            max_l = 0.5
        else:
            max_l = 0
        if setup['offset'] == -0.5:
            min_r = -0.5
        else:
            min_r = 0

        l_dist = distances[distances < max_l]
        r_dist = distances[distances > min_r]
        l_len = l_dist.shape
        r_len = r_dist.shape

        l_dist = np.append(l_dist, np.full(r_len, np.NaN))
        r_dist = np.append(np.full(l_len, np.NaN), r_dist)

        misfit = np.zeros(len(l_dist))

        dx = 1
        # Loop over lambda keys
        for key in lambdas:
            eta_l, eta_r = key
            if np.isnan(eta_l):
                mask = np.logical_and(r_dist >= eta_r, r_dist < eta_r + 0.5)
            elif np.isnan(eta_r):
                mask = np.logical_and(l_dist < eta_l, l_dist >= eta_l - 0.5)
            else:
                mask = np.full(l_dist.shape, False)
            key_l = l_dist[mask]
            key_r = r_dist[mask]
            key_s = np.zeros(key_l.shape)
            for index in lambdas[key]:
                if np.isnan(eta_l):
                    key_s += lambdas[key][index](key_l, key_r) * fnc(
                        (index - key_r) * dx)
                elif np.isnan(eta_r):
                    key_s += lambdas[key][index](key_l, key_r) * fnc(
                        (index - key_l) * dx)
            if np.isnan(eta_l):
                misfit[mask] = np.abs((key_s / dx**setup['deriv']) -
                                      tru_drv((setup['offset'] - key_r) * dx))
            elif np.isnan(eta_r):
                misfit[mask] = np.abs((key_s / dx**setup['deriv']) -
                                      tru_drv((setup['offset'] - key_l) * dx))

        assert np.median(misfit) < 5e-6
Exemplo n.º 10
0
    def test_stencil_convergence(self, setup):
        """
        Check that grid refinement increases accuracy in line with discretization order.
        """
        # First need to create the stencils and get the lambdaified versions
        order = setup['order']

        if setup['bcs'] == 'even':
            bcs = BoundaryConditions({2 * i: 0
                                      for i in range(1 + order // 2)}, order)

            # Define benchmark function
            def fnc(x):
                return np.sin(x)

            if setup['deriv'] == 1:

                def tru_drv(x):
                    return np.cos(x)
            elif setup['deriv'] == 2:

                def tru_drv(x):
                    return -np.sin(x)
        else:
            bcs = BoundaryConditions(
                {2 * i + 1: 0
                 for i in range(1 + order // 2)}, order)

            # Define benchmark function
            def fnc(x):
                return np.cos(x)

            if setup['deriv'] == 1:

                def tru_drv(x):
                    return -np.sin(x)
            elif setup['deriv'] == 2:

                def tru_drv(x):
                    return -np.cos(x)

        cache = os.path.dirname(
            __file__) + '/../devitoboundary/extrapolation_cache.dat'

        stencils = StencilSet(setup['deriv'],
                              setup['offset'],
                              bcs,
                              cache=cache)

        lambdas = stencils.lambdaify

        # Create a set of distances to test and a corresponding set of keys
        l_mod = setup['offset'] == 0.5
        r_mod = setup['offset'] == -0.5
        # TODO: Would be more rigorous if it used separate left and right distances
        distances = np.linspace(0.1 - order / 2 + l_mod,
                                order / 2 - 0.1 - r_mod, 5 * order)
        if setup['offset'] == 0.5:
            max_l = 0.5
        else:
            max_l = 0
        if setup['offset'] == -0.5:
            min_r = -0.5
        else:
            min_r = 0

        l_dist = distances[distances < max_l]
        r_dist = distances[distances > min_r]
        l_len = l_dist.shape
        r_len = r_dist.shape

        l_dist = np.append(l_dist, np.full(r_len, np.NaN))
        r_dist = np.append(np.full(l_len, np.NaN), r_dist)

        # Create a set of spacings
        spacings = np.linspace(2, 0.2, 20)

        misfit = np.zeros((len(spacings), len(l_dist)))
        for i in range(len(spacings)):
            dx = spacings[i]
            # Loop over lambda keys
            for key in lambdas:
                eta_l, eta_r = key
                if np.isnan(eta_l):
                    mask = np.logical_and(r_dist >= eta_r,
                                          r_dist < eta_r + 0.5)
                elif np.isnan(eta_r):
                    mask = np.logical_and(l_dist < eta_l,
                                          l_dist >= eta_l - 0.5)
                else:
                    mask = np.full(l_dist.shape, False)
                key_l = l_dist[mask]
                key_r = r_dist[mask]
                key_s = np.zeros(key_l.shape)
                for index in lambdas[key]:
                    if np.isnan(eta_l):
                        key_s += lambdas[key][index](key_l, key_r) * fnc(
                            (index - key_r) * dx)
                    elif np.isnan(eta_r):
                        key_s += lambdas[key][index](key_l, key_r) * fnc(
                            (index - key_l) * dx)
                if np.isnan(eta_l):
                    misfit[i,
                           mask] = np.abs((key_s / dx**setup['deriv']) -
                                          tru_drv((setup['offset'] - key_r) *
                                                  dx))
                elif np.isnan(eta_r):
                    misfit[i,
                           mask] = np.abs((key_s / dx**setup['deriv']) -
                                          tru_drv((setup['offset'] - key_l) *
                                                  dx))

        log_dx = np.log10(spacings)
        log_m = np.log10(misfit)

        convergence_gradients = np.polyfit(log_dx, log_m, 1)[0]
        assert np.mean(convergence_gradients) > order - 1