Beispiel #1
0
    def apply(self, fd, u):

        for axis, order in self.derivs.items():
            if self.spac:
                u = fd.diff(u, self.spac[axis], order, axis, coefficients(order, fd.acc))
            else:
                coefs = []
                for i in range(len(self.coords[axis])):
                    coefs.append(coefficients_non_uni(order, fd.acc, self.coords[axis], i))
                u = fd.diff_non_uni(u, self.coords[axis], axis, coefs)

        return u
Beispiel #2
0
    def diff(self, y, h, acc):
        """The core function to take a partial derivative on a uniform grid.

            Central coefficients will be used whenever possible. Backward or forward
            coefficients will be used if not enough points are available on either side,
            i.e. forward coefficients for the low index boundary and backward coefficients
            for the high index boundary.
        """

        dim = self.axis
        coefs = coefficients(self.order, acc)
        deriv = self.order

        try:
            npts = y.shape[dim]
        except AttributeError as err:
            raise ValueError(
                "FinDiff objects can only be applied to arrays or evaluated(!) functions returning arrays") from err

        scheme = "center"
        weights = coefs[scheme]["coefficients"]
        offsets = coefs[scheme]["offsets"]

        num_bndry_points = len(weights) // 2
        ref_slice = slice(num_bndry_points, npts - num_bndry_points, 1)
        off_slices = [self._shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))]

        yd = np.zeros_like(y)

        self._apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

        scheme = "forward"
        weights = coefs[scheme]["coefficients"]
        offsets = coefs[scheme]["offsets"]

        ref_slice = slice(0, num_bndry_points, 1)
        off_slices = [self._shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))]

        self._apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

        scheme = "backward"
        weights = coefs[scheme]["coefficients"]
        offsets = coefs[scheme]["offsets"]

        ref_slice = slice(npts - num_bndry_points, npts, 1)
        off_slices = [self._shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))]

        self._apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

        h_inv = 1. / h ** deriv
        return yd * h_inv
Beispiel #3
0
    def matrix(self, shape, h=None, acc=None):

        if isinstance(h, dict):
            h = h[self.axis]

        acc = self._properties(self.acc, acc, 2)

        ndims = len(shape)
        siz = np.prod(shape)
        long_indices_nd = long_indices_as_ndarray(shape)

        axis, order = self.axis, self.order
        mat = sparse.lil_matrix((siz, siz))
        coeff_dict = coefficients(order, acc)

        for scheme in ['center', 'forward', 'backward']:

            offsets_1d = coeff_dict[scheme]['offsets']
            coeffs = coeff_dict[scheme]['coefficients']

            # translate offsets of given scheme to long format
            offsets_long = []
            for o_1d in offsets_1d:
                o_nd = np.zeros(ndims)
                o_nd[axis] = o_1d
                o_long = to_long_index(o_nd, shape)
                offsets_long.append(o_long)

            # determine points where to evaluate current scheme in long format
            if scheme == 'center':
                multi_slice = [slice(None, None)] * ndims
                multi_slice[axis] = slice(1, -1)
                Is = long_indices_nd[tuple(multi_slice)].reshape(-1)
            elif scheme == 'forward':
                multi_slice = [slice(None, None)] * ndims
                multi_slice[axis] = 0
                Is = long_indices_nd[tuple(multi_slice)].reshape(-1)
            else:
                multi_slice = [slice(None, None)] * ndims
                multi_slice[axis] = -1
                Is = long_indices_nd[tuple(multi_slice)].reshape(-1)

            for o, c in zip(offsets_long, coeffs):
                v = c / h**order
                mat[Is, Is + o] = v

        mat = sparse.csr_matrix(mat)

        return mat
Beispiel #4
0
def _diff_general(y, h, deriv, dim, acc, coefs=None):

    if coefs is None:
        coefs = coefficients(deriv, acc)

    npts = y.shape[dim]

    scheme = "center"
    weights = coefs[scheme]["coefficients"]
    offsets = coefs[scheme]["offsets"]

    nbndry = len(weights) // 2
    ref_slice = slice(nbndry, npts - nbndry, 1)
    off_slices = [
        _shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))
    ]

    yd = np.zeros_like(y)

    _apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

    scheme = "forward"
    weights = coefs[scheme]["coefficients"]
    offsets = coefs[scheme]["offsets"]

    ref_slice = slice(0, nbndry, 1)
    off_slices = [
        _shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))
    ]

    _apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

    scheme = "backward"
    weights = coefs[scheme]["coefficients"]
    offsets = coefs[scheme]["offsets"]

    ref_slice = slice(npts - nbndry, npts, 1)
    off_slices = [
        _shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))
    ]

    _apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

    h_inv = 1. / h**deriv
    return yd * h_inv[dim]
Beispiel #5
0
    def __init__(self, h=[1.], dims=[0], acc=2):
        """Constructor for Finite Difference operator
           
           Parameters:
           ----------
           
           h        array-like
                    The grid spacing along each axis.
           dims     array-like
                    The axes along which to take the derivatives. Multiple values mean higher derivative.
           acc      int
                    The accuracy order of the finite difference scheme.
                            
                            
           Example:
           --------
           
           Suppose f is a four-dimensional array. The second partial derivative with respect to the second axis,
                    
                    \frac{\partial^2 f}{\partial z^2},
                     
           on a grid with equidistant spacing h=[0.1, 0.1, 0.1, 0.1] is given by
           
                FinDiff(h=[0.1, 0.1, 0.1, 0.1], dims=[1, 1])
                
        """

        if not hasattr(h, "__len__"):
            self._h = np.array([h])
        else:
            self._h = np.array(h)

        if not hasattr(dims, "__len__"):
            self._dims = np.array([dims])
        else:
            self._dims = np.array(dims)

        self._acc = acc
        ndims = len(self._h)
        self._derivs = [np.sum(self._dims == i) for i in range(ndims)]
        self._coefs = []
        for i in range(ndims):
            self._coefs.append(coefficients(self._derivs[i], acc))
Beispiel #6
0
    def _diff(self, y, h, deriv, dim, acc, coefs=None):
        """The core function to take a partial derivative on a uniform grid.
        """

        if coefs is None:
            coefs = coefficients(deriv, acc)

        npts = y.shape[dim]

        scheme = "center"
        weights = coefs[scheme]["coefficients"]
        offsets = coefs[scheme]["offsets"]

        nbndry = len(weights) // 2
        ref_slice = slice(nbndry, npts - nbndry, 1)
        off_slices = [self._shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))]

        yd = np.zeros_like(y)

        self._apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

        scheme = "forward"
        weights = coefs[scheme]["coefficients"]
        offsets = coefs[scheme]["offsets"]

        ref_slice = slice(0, nbndry, 1)
        off_slices = [self._shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))]

        self._apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

        scheme = "backward"
        weights = coefs[scheme]["coefficients"]
        offsets = coefs[scheme]["offsets"]

        ref_slice = slice(npts - nbndry, npts, 1)
        off_slices = [self._shift_slice(ref_slice, offsets[k], npts) for k in range(len(offsets))]

        self._apply_to_array(yd, y, weights, off_slices, ref_slice, dim)

        h_inv = 1./h**deriv
        return yd * h_inv
Beispiel #7
0
    def _determine_coefs(self):
        """Calculates the finite difference coefficients for the requested partial derivatives"""

        for axis, partial in self.derivs.items():
            coefs = coefficients(partial["order"], self.acc)
            self.derivs[axis]["coefs"] = coefs