Ejemplo n.º 1
0
def _rhs(x, s, eps, powers, diff, basis):
    ''' 
  Returns the differentiated RBF and polynomial terms evaluated at x
  '''
    x = x[None, :]
    # number of nodes in the stencil and the number of dimensions
    Ns, Ndim = s.shape
    # number of monomial terms
    Np = powers.shape[0]
    d = np.empty(Ns + Np, dtype=float)
    d[:Ns] = basis(x, s, eps=eps, diff=diff)[0, :]
    d[Ns:] = rbf.poly.mvmonos(x, powers, diff=diff)[0, :]
    return d
Ejemplo n.º 2
0
    def __init__(self,
                 y,
                 d,
                 sigma=None,
                 eps=1.0,
                 basis=rbf.basis.phs3,
                 order=1,
                 extrapolate=True):
        y = np.asarray(y)
        assert_shape(y, (None, None), 'y')

        d = np.asarray(d)
        assert_shape(d, (y.shape[0], ), 'd')

        q, dim = y.shape

        if sigma is None:
            # if sigma is not specified then it is zeros
            sigma = np.zeros(q)

        elif np.isscalar(sigma):
            # if a float is specified then use it as the uncertainties for
            # all observations
            sigma = np.repeat(sigma, q)

        else:
            sigma = np.asarray(sigma)
            assert_shape(sigma, (y.shape[0], ), 'sigma')

        # form block consisting of the RBF and uncertainties on the
        # diagonal
        K = basis(y, y, eps=eps)
        Cd = scipy.sparse.diags(sigma**2)
        # form the block consisting of the monomials
        powers = rbf.poly.powers(order, dim)
        P = rbf.poly.mvmonos(y, powers)
        # create zeros vector for the right-hand-side
        z = np.zeros((powers.shape[0], ))
        # solve for the RBF and mononomial coefficients
        basis_coeff, poly_coeff = PartitionedSolver(K + Cd, P).solve(d, z)

        self._y = y
        self._basis = basis
        self._order = order
        self._eps = eps
        self._basis_coeff = basis_coeff
        self._poly_coeff = poly_coeff
        self._powers = powers
        self.extrapolate = extrapolate
Ejemplo n.º 3
0
def _lhs(s, eps, powers, basis):
    ''' 
  Returns the transposed RBF alternant matrix with added polynomial 
  terms and constraints
  '''
    # number of nodes in the stencil and the number of dimensions
    Ns, Ndim = s.shape
    # number of monomial terms
    Np = powers.shape[0]
    # deriviative orders
    diff = np.zeros(Ndim, dtype=int)
    A = np.zeros((Ns + Np, Ns + Np), dtype=float)
    A[:Ns, :Ns] = basis(s, s, eps=eps, diff=diff).T
    Ap = rbf.poly.mvmonos(s, powers, diff=diff)
    A[Ns:, :Ns] = Ap.T
    A[:Ns, Ns:] = Ap
    return A
Ejemplo n.º 4
0
def _interpolation_matrix(xitp,x,diff,eps,basis,order):
  ''' 
  returns the matrix that maps the coefficients to the function values 
  at the interpolation points
  '''
  # number of interpolation points and spatial dimensions
  I,D = xitp.shape
  # number of observation points
  N = x.shape[0]
  # powers for the additional polynomials
  powers = rbf.poly.powers(order,D)
  # number of polynomial terms
  P = powers.shape[0]
  # allocate array 
  A = np.zeros((I,N+P))
  A[:,:N] = basis(xitp,x,eps=eps,diff=diff)
  A[:,N:] = rbf.poly.mvmonos(xitp,powers,diff=diff)
  return A
Ejemplo n.º 5
0
def _interpolation_matrix(xitp,x,diff,eps,basis,order):
  ''' 
  returns the matrix that maps the coefficients to the function values 
  at the interpolation points
  '''
  # number of interpolation points and spatial dimensions
  I,D = xitp.shape
  # number of observation points
  N = x.shape[0]
  # powers for the additional polynomials
  powers = rbf.poly.powers(order,D)
  # number of polynomial terms
  P = powers.shape[0]
  # allocate array 
  A = np.zeros((I,N+P))
  A[:,:N] = basis(xitp,x,eps=eps,diff=diff)
  A[:,N:] = rbf.poly.mvmonos(xitp,powers,diff=diff)
  return A
Ejemplo n.º 6
0
def _coefficient_matrix(x, eps, basis, order):
    ''' 
  returns the matrix used to compute the radial basis function 
  coefficients
  '''
    # number of observation points and spatial dimensions
    N, D = x.shape

    # powers for the additional polynomials
    powers = rbf.poly.monomial_powers(order, D)
    # number of polynomial terms
    P = powers.shape[0]
    # allocate array
    A = np.zeros((N + P, N + P))
    A[:N, :N] = basis(x, x, eps=eps)
    Ap = rbf.poly.mvmonos(x, powers)
    A[N:, :N] = Ap.T
    A[:N, N:] = Ap
    return A
Ejemplo n.º 7
0
def _coefficient_matrix(x,eps,basis,order):
  ''' 
  returns the matrix used to compute the radial basis function 
  coefficients
  '''
  # number of observation points and spatial dimensions
  N,D = x.shape

  # powers for the additional polynomials
  powers = rbf.poly.powers(order,D)
  # number of polynomial terms
  P = powers.shape[0]
  # allocate array 
  A = np.zeros((N+P,N+P))
  A[:N,:N] = basis(x,x,eps=eps)
  Ap = rbf.poly.mvmonos(x,powers)
  A[N:,:N] = Ap.T
  A[:N,N:] = Ap
  return A  
Ejemplo n.º 8
0
def weights(x,
            s,
            diffs,
            coeffs=None,
            basis=rbf.basis.phs3,
            order=None,
            eps=1.0):
    ''' 
  Returns the weights which map a functions values at `s` to an 
  approximation of that functions derivative at `x`. The weights are 
  computed using the RBF-FD method described in [1]. In this function 
  `x` is a single point in D-dimensional space. Use `weight_matrix` to 
  compute the weights for multiple point.

  Parameters
  ----------
  x : (D,) array
    Target point. The weights will approximate the derivative at this
    point.

  s : (N, D) array
    Stencil points. The derivative will be approximated with a
    weighted sum of the function values at this point.

  diffs : (D,) int array or (K, D) int array 
    Derivative orders for each spatial dimension. For example `[2, 0]`
    indicates that the weights should approximate the second
    derivative with respect to the first spatial dimension in
    two-dimensional space.  diffs can also be a (K, D) array, where
    each (D,) sub-array is a term in a differential operator. For
    example the two-dimensional Laplacian can be represented as
    `[[2, 0], [0, 2]]`.

  coeffs : (K,) array, optional 
    Coefficients for each term in the differential operator specified
    with `diffs`.  Defaults to an array of ones. If `diffs` was
    specified as a (D,) array then `coeffs` should be a length 1
    array.

  basis : rbf.basis.RBF, optional
    Type of RBF. Select from those available in `rbf.basis` or create
    your own.
 
  order : int, optional
    Order of the added polynomial. This defaults to the highest
    derivative order. For example, if `diffs` is `[[2, 0], [0, 1]]`, then
    order is set to 2.

  eps : float or (N,) array, optional
    Shape parameter for each RBF, which have centers `s`. This only 
    makes a difference when using RBFs that are not scale invariant. 
    All the predefined RBFs except for the odd order polyharmonic 
    splines are not scale invariant.

  Returns
  -------
  out : (N,) array
    RBF-FD weights
    
  Examples
  --------
  Calculate the weights for a one-dimensional second order derivative.

  >>> x = np.array([1.0]) 
  >>> s = np.array([[0.0], [1.0], [2.0]]) 
  >>> diff = (2,) 
  >>> weights(x, s, diff)
  array([ 1., -2., 1.])
    
  Calculate the weights for estimating an x derivative from three 
  points in a two-dimensional plane

  >>> x = np.array([0.25, 0.25])
  >>> s = np.array([[0.0, 0.0],
                    [1.0, 0.0],
                    [0.0, 1.0]])
  >>> diff = (1, 0)
  >>> weights(x, s, diff)
  array([ -1., 1., 0.])
    
  Notes
  -----
  This function may become unstable with high order polynomials (i.e.,
  `order` is high). This can be somewhat remedied by shifting the
  coordinate system so that x is zero

  References
  ----------
  [1] Fornberg, B. and N. Flyer. A Primer on Radial Basis 
  Functions with Applications to the Geosciences. SIAM, 2015.
    
  '''
    x = np.asarray(x, dtype=float)
    assert_shape(x, (None, ), 'x')

    s = np.asarray(s, dtype=float)
    assert_shape(s, (None, x.shape[0]), 's')

    diffs = np.asarray(diffs, dtype=int)
    diffs = _reshape_diffs(diffs)

    # stencil size and number of dimensions
    size, dim = s.shape
    if coeffs is None:
        coeffs = np.ones(diffs.shape[0], dtype=float)
    else:
        coeffs = np.asarray(coeffs, dtype=float)
        assert_shape(coeffs, (diffs.shape[0], ), 'coeffs')

    max_order = _max_poly_order(size, dim)
    if order is None:
        order = _default_poly_order(diffs)
        order = min(order, max_order)

    if order > max_order:
        raise ValueError('Polynomial order is too high for the stencil size')

    # get the powers for the added monomials
    powers = rbf.poly.powers(order, dim)
    # evaluate the RBF and monomials at each point in the stencil. This
    # becomes the left-hand-side
    A = basis(s, s, eps=eps)
    P = rbf.poly.mvmonos(s, powers)
    # Evaluate the RBF and monomials for each term in the differential
    # operator. This becomes the right-hand-side.
    a = coeffs[0] * basis(x[None, :], s, eps=eps, diff=diffs[0])
    p = coeffs[0] * rbf.poly.mvmonos(x[None, :], powers, diff=diffs[0])
    for c, d in zip(coeffs[1:], diffs[1:]):
        a += c * basis(x[None, :], s, eps=eps, diff=d)
        p += c * rbf.poly.mvmonos(x[None, :], powers, diff=d)

    # squeeze `a` and `p` into 1d arrays. `a` is ran through as_array
    # because it may be sparse.
    a = rbf.linalg.as_array(a)[0]
    p = p[0]

    # attempt to compute the RBF-FD weights
    try:
        w = PartitionedSolver(A, P).solve(a, p)[0]
        return w

    except np.linalg.LinAlgError:
        raise np.linalg.LinAlgError(
            'An error was raised while computing the RBF-FD weights at '
            'point %s with the RBF %s and the polynomial order %s. This '
            'may be due to a stencil with duplicate or collinear points. '
            'The stencil contains the following points:\n%s' %
            (x, basis, order, s))
Ejemplo n.º 9
0
forcing = sympy.lambdify((x, y), forcing_sym, 'numpy')

# define a circular domain
vert, smp = rbf.domain.circle()

nodes, smpid = menodes(N, vert, smp)
# smpid describes which boundary simplex, if any, the nodes are
# attached to. If it is -1, then the node is in the interior
boundary, = (smpid >= 0).nonzero()
interior, = (smpid == -1).nonzero()

# create the left-hand-side matrix which is the Laplacian of the basis
# function for interior nodes and the undifferentiated basis functions
# for the boundary nodes
A = np.zeros((N, N))
A[interior] = basis(nodes[interior], nodes, diff=[2, 0])
A[interior] += basis(nodes[interior], nodes, diff=[0, 2])
A[boundary, :] = basis(nodes[boundary], nodes)

# create the right-hand-side vector, consisting of the forcing term
# for the interior nodes and zeros for the boundary nodes
d = np.zeros(N)
d[interior] = forcing(nodes[interior, 0], nodes[interior, 1])
d[boundary] = true_soln(nodes[boundary, 0], nodes[boundary, 1])

# find the RBF coefficients that solve the PDE
coeff = np.linalg.solve(A, d)

# create a collection of interpolation points to evaluate the
# solution. It is easiest to just call menodes again
itp, dummy = menodes(10000, vert, smp, itr=0)
Ejemplo n.º 10
0
forcing = sympy.lambdify((x,y),forcing_sym,'numpy')

# define a circular domain
vert,smp = rbf.domain.circle()

nodes,smpid = menodes(N,vert,smp)
# smpid describes which boundary simplex, if any, the nodes are 
# attached to. If it is -1, then the node is in the interior
boundary, = (smpid>=0).nonzero()
interior, = (smpid==-1).nonzero()

# create the left-hand-side matrix which is the Laplacian of the basis 
# function for interior nodes and the undifferentiated basis functions 
# for the boundary nodes
A = np.zeros((N,N))
A[interior]  = basis(nodes[interior],nodes,diff=[2,0]) 
A[interior] += basis(nodes[interior],nodes,diff=[0,2]) 
A[boundary,:] = basis(nodes[boundary],nodes)

# create the right-hand-side vector, consisting of the forcing term 
# for the interior nodes and zeros for the boundary nodes
d = np.zeros(N)
d[interior] = forcing(nodes[interior,0],nodes[interior,1]) 
d[boundary] = true_soln(nodes[boundary,0],nodes[boundary,1]) 

# find the RBF coefficients that solve the PDE
coeff = np.linalg.solve(A,d)

# create a collection of interpolation points to evaluate the 
# solution. It is easiest to just call menodes again
itp,dummy = menodes(10000,vert,smp,itr=0)