예제 #1
0
    def interpolate(self, w: ndarray) -> Union[DiscreteField,
                                               Tuple[DiscreteField, ...]]:
        """Interpolate a solution vector to quadrature points.

        Useful when a solution vector is needed in the forms, e.g., when
        evaluating functionals or when solving nonlinear problems.

        Parameters
        ----------
        w
            A solution vector.

        """
        if w.shape[0] != self.N:
            raise ValueError("Input array has wrong size.")

        if isinstance(self.elem, ElementVector):
            # ElementVector shouldn't get split here: workaround
            refs: List[Tuple[ndarray, 'AbstractBasis']] = [(np.array([]),
                                                            self)]
        else:
            refs = self.split(w)
        dfs: List[DiscreteField] = []

        # loop over solution components
        for c in range(len(refs)):
            ref = refs[c][1].basis[0][0]
            if ref.is_zero():
                dfs.append(ref)
                continue
            ref = ref.astuple
            fs = []

            def linear_combination(n, refn):
                """Global discrete function at quadrature points."""
                out = 0. * refn.copy()
                for i in range(self.Nbfun):
                    values = w[self.element_dofs[i]]
                    if self.basis[i][c].is_zero():
                        continue
                    out += np.einsum('...,...j->...j', values,
                                     self.basis[i][c].get(n))
                return out

            # interpolate DiscreteField
            for n in range(len(ref)):
                if ref[n] is not None:
                    fs.append(linear_combination(n, ref[n]))
                else:
                    fs.append(None)

            dfs.append(DiscreteField(*fs))

        if len(dfs) > 1:
            return tuple(dfs)
        return dfs[0]
예제 #2
0
def curl(u: DiscreteField):
    """Curl."""
    if u.is_zero():
        return u
    if u.curl is not None:
        return u.curl
    elif u.grad is not None:
        if u.grad.shape[0] == 2:
            return np.array([u.grad[1], -u.grad[0]])
    raise NotImplementedError
예제 #3
0
def d(u: DiscreteField):
    """Gradient, divergence or curl."""
    if u.is_zero():
        return u
    if u.grad is not None:
        return u.grad
    elif u.div is not None:
        return u.div
    elif u.curl is not None:
        return u.curl
    raise NotImplementedError
예제 #4
0
def div(u: DiscreteField):
    """Divergence."""
    if u.is_zero():
        return u
    if u.div is not None:
        return u.div
    elif u.grad is not None:
        try:
            return np.einsum('ii...', u.grad)
        except ValueError:  # one-dimensional u?
            return u.grad[0]
    raise NotImplementedError
예제 #5
0
    def interpolate(
            self,
            w: ndarray) -> Union[DiscreteField, Tuple[DiscreteField, ...]]:
        """Interpolate a solution vector to quadrature points.

        Useful when a solution vector is needed in the forms, e.g., when
        evaluating functionals or when solving nonlinear problems.

        Parameters
        ----------
        w
            A solution vector.

        """
        if w.shape[0] != self.N:
            raise ValueError("Input array has wrong size.")

        refs = self.basis[0]
        dfs: List[DiscreteField] = []

        # loop over solution components
        for c in range(len(refs)):
            ref = refs[c]
            fs = []

            def linear_combination(n, refn):
                """Global discrete function at quadrature points."""
                out = 0. * refn.copy()
                for i in range(self.Nbfun):
                    values = w[self.element_dofs[i]]
                    out += np.einsum('...,...j->...j', values,
                                     self.basis[i][c][n])
                return out

            # interpolate DiscreteField
            for n in range(len(ref)):
                if ref[n] is not None:
                    fs.append(linear_combination(n, ref[n]))
                else:
                    fs.append(None)

            dfs.append(DiscreteField(*fs))

        if len(dfs) > 1:
            return tuple(dfs)
        return dfs[0]
예제 #6
0
 def mesh_parameters(self) -> DiscreteField:
     return DiscreteField(
         np.abs(self.mapping.detDF(self.X,
                                   self.tind))**(1. / self.mesh.dim()))
예제 #7
0
 def global_coordinates(self) -> DiscreteField:
     return DiscreteField(self.mapping.F(self.X, tind=self.tind))
    def __init__(self,
                 mesh: Mesh,
                 elem: Element,
                 mapping: Optional[Mapping] = None,
                 intorder: Optional[int] = None,
                 quadrature: Optional[Tuple[ndarray, ndarray]] = None,
                 facets: Optional[ndarray] = None,
                 _side: int = 0,
                 dofs: Optional[Dofs] = None):
        """Precomputed global basis on boundary facets.

        Parameters
        ----------
        mesh
            An object of type :class:`~skfem.mesh.Mesh`.
        elem
            An object of type :class:`~skfem.element.Element`.
        mapping
            An object of type :class:`skfem.mapping.Mapping`. If `None`, uses
            `mesh.mapping`.
        intorder
            Optional integration order, i.e. the degree of polynomials that are
            integrated exactly by the used quadrature. Not used if `quadrature`
            is specified.
        quadrature
            Optional tuple of quadrature points and weights.
        facets
            Optional subset of facet indices.
        dofs
            Optional :class:`~skfem.assembly.Dofs` object.

        """
        logger.info("Initializing {}({}, {})".format(
            type(self).__name__,
            type(mesh).__name__,
            type(elem).__name__))
        super(BoundaryFacetBasis,
              self).__init__(mesh, elem, mapping, intorder, quadrature,
                             mesh.brefdom, dofs)

        # facets where the basis is evaluated
        if facets is None:
            self.find = np.nonzero(self.mesh.f2t[1] == -1)[0]
        else:
            self.find = facets
        self.tind = self.mesh.f2t[_side, self.find]
        self._side = _side  # for debugging

        # boundary refdom to global facet
        x = self.mapping.G(self.X, find=self.find)
        # global facet to refdom facet
        Y = self.mapping.invF(x, tind=self.tind)

        # construct normal vectors from side=0 always
        Y0 = self.mapping.invF(x, tind=self.mesh.f2t[0, self.find])
        self.normals = DiscreteField(value=self.mapping.normals(
            Y0, self.mesh.f2t[0, self.find], self.find, self.mesh.t2f))

        self.nelems = len(self.find)

        self.basis = [
            self.elem.gbasis(self.mapping, Y, j, tind=self.tind)
            for j in range(self.Nbfun)
        ]

        self.dx = (np.abs(self.mapping.detDG(self.X, find=self.find)) *
                   np.tile(self.W, (self.nelems, 1)))
        logger.info("Initializing finished.")
 def mesh_parameters(self) -> DiscreteField:
     return DiscreteField((np.abs(self.mapping.detDG(self.X, self.find))**(
         1. / (self.mesh.dim() - 1.))
                           ) if self.mesh.dim() != 1 else np.array([0.]))
예제 #10
0
    def __init__(self,
                 mesh: Mesh,
                 elem: Element,
                 mapping: Optional[Mapping] = None,
                 intorder: Optional[int] = None,
                 quadrature: Optional[Tuple[ndarray, ndarray]] = None,
                 facets: Optional[Any] = None,
                 dofs: Optional[Dofs] = None,
                 side: int = 0):
        """Precomputed global basis on boundary facets.

        Parameters
        ----------
        mesh
            An object of type :class:`~skfem.mesh.Mesh`.
        elem
            An object of type :class:`~skfem.element.Element`.
        mapping
            An object of type :class:`skfem.mapping.Mapping`. If `None`, uses
            `mesh.mapping`.
        intorder
            Optional integration order, i.e. the degree of polynomials that are
            integrated exactly by the used quadrature. Not used if `quadrature`
            is specified.
        quadrature
            Optional tuple of quadrature points and weights.
        facets
            Optional subset of facet indices.
        dofs
            Optional :class:`~skfem.assembly.Dofs` object.

        """
        typestr = ("{}({}, {})".format(type(self).__name__,
                                       type(mesh).__name__,
                                       type(elem).__name__))
        logger.info("Initializing {}".format(typestr))
        super(FacetBasis, self).__init__(
            mesh,
            elem,
            mapping,
            intorder,
            quadrature,
            mesh.brefdom,
            dofs,
        )

        # by default use boundary facets
        if facets is None:
            self.find = np.nonzero(self.mesh.f2t[1] == -1)[0]
        else:
            self.find = mesh.normalize_facets(facets)

        # fix the orientation
        if isinstance(self.find, OrientedBoundary):
            self.tind = self.mesh.f2t[(-1) ** side * self.find.ori - side,
                                      self.find]
            self.tind_normals = self.mesh.f2t[self.find.ori, self.find]
        else:
            self.tind = self.mesh.f2t[side, self.find]
            self.tind_normals = self.mesh.f2t[0, self.find]

        if len(self.find) == 0:
            logger.warning("Initializing {} with no facets.".format(typestr))

        # boundary refdom to global facet
        x = self.mapping.G(self.X, find=self.find)
        # global facet to refdom facet
        Y = self.mapping.invF(x, tind=self.tind)

        # calculate normals
        Y0 = self.mapping.invF(x, tind=self.tind_normals)
        assert self.tind_normals is not None  # satisfy mypy
        self.normals = DiscreteField(
            value=self.mapping.normals(Y0,
                                       self.tind_normals,
                                       self.find,
                                       self.mesh.t2f)
        )

        self.nelems = len(self.find)

        self.basis = [self.elem.gbasis(self.mapping, Y, j, tind=self.tind)
                      for j in range(self.Nbfun)]

        self.dx = (np.abs(self.mapping.detDG(self.X, find=self.find))
                   * np.tile(self.W, (self.nelems, 1)))
        logger.info("Initializing finished.")
예제 #11
0
    def __init__(self,
                 mesh,
                 elem,
                 mapping=None,
                 intorder: int = None,
                 side: int = None,
                 facets: ndarray = None,
                 quadrature: Tuple[ndarray, ndarray] = None):
        """Combine :class:`~skfem.mesh.Mesh` and :class:`~skfem.element.Element`
        into a set of precomputed global basis functions at element facets.

        Parameters
        ----------
        mesh
            An object of type :class:`~skfem.mesh.Mesh`.
        elem
            An object of type :class:`~skfem.element.Element`.
        mapping
            An object of type :class:`skfem.mapping.Mapping`. If `None`, uses
            `mesh.mapping`.
        intorder
            Optional integration order, i.e. the degree of polynomials that are
            integrated exactly by the used quadrature. Not used if `quadrature`
            is specified.
        side
            If 0 or 1, basis functions are evaluated on the interior facets.
            The numbers 0 and 1 refer to the different sides of the facets.
            Side 0 corresponds to the indices `mesh.f2t[0]`. If `None`, basis
            is evaluated only on the exterior facets.
        facets
            Optional subset of facet indices.
        quadrature
            Optional tuple of quadrature points and weights.

        """
        super(FacetBasis, self).__init__(mesh, elem, mapping)

        if quadrature is not None:
            self.X, self.W = quadrature
        else:
            self.X, self.W = get_quadrature(
                self.brefdom,
                intorder if intorder is not None else 2 * self.elem.maxdeg)

        # facets where the basis is evaluated
        if facets is None:
            if side is None:
                self.find = np.nonzero(self.mesh.f2t[1] == -1)[0]
                self.tind = self.mesh.f2t[0, self.find]
            elif hasattr(self.mapping, 'helper_to_orig') and side in [0, 1]:
                self.mapping.side = side
                self.find = self.mapping.helper_to_orig[side]
                self.tind = self.mesh.f2t[0, self.find]
            elif side in [0, 1]:
                self.find = np.nonzero(self.mesh.f2t[1] != -1)[0]
                self.tind = self.mesh.f2t[side, self.find]
            else:
                raise Exception("Parameter 'side' must be either 0 or 1. "
                                "A facet shares only two elements.")
        else:
            self.find = facets
            self.tind = self.mesh.f2t[0, self.find]

        # boundary refdom to global facet
        x = self.mapping.G(self.X, find=self.find)
        # global facet to refdom facet
        Y = self.mapping.invF(x, tind=self.tind)

        # construct normal vectors from side=0 always
        Y0 = self.mapping.invF(x, tind=self.mesh.f2t[0, self.find])
        self.normals = DiscreteField(value=self.mapping.normals(
            Y0, self.mesh.f2t[0, self.find], self.find, self.mesh.t2f))

        self.nelems = len(self.find)

        self.basis = [
            self.elem.gbasis(self.mapping, Y, j, tind=self.tind)
            for j in range(self.Nbfun)
        ]

        self.dx = (np.abs(self.mapping.detDG(self.X, find=self.find)) *
                   np.tile(self.W, (self.nelems, 1)))
예제 #12
0
    def interpolate(
            self,
            w: ndarray) -> Union[DiscreteField, Tuple[DiscreteField, ...]]:
        """Interpolate a solution vector to quadrature points.

        Useful when a solution vector is needed in the forms, e.g., when
        evaluating functionals or when solving nonlinear problems.

        Parameters
        ----------
        w
            A solution vector.

        """
        if w.shape[0] != self.N:
            raise ValueError("Input array has wrong size.")

        refs = self.basis[0]
        dfs: List[DiscreteField] = []

        # loop over solution components
        for c in range(len(refs)):
            ref = refs[c]
            fs = []

            def linear_combination(n, refn):
                """Global discrete function at quadrature points."""
                out = 0. * refn.copy()
                for i in range(self.Nbfun):
                    values = w[self.element_dofs[i]][:, None]
                    if len(refn.shape) == 2:  # values
                        out += values * self.basis[i][c][n]
                    elif len(refn.shape) == 3:  # derivatives
                        for j in range(out.shape[0]):
                            out[j, :, :] += values * self.basis[i][c][n][j]
                    elif len(refn.shape) == 4:  # second derivatives
                        for j in range(out.shape[0]):
                            for k in range(out.shape[1]):
                                out[j, k, :, :] += \
                                    values * self.basis[i][c][n][j, k]
                    elif len(refn.shape) == 5:  # third derivatives
                        for j in range(out.shape[0]):
                            for k in range(out.shape[1]):
                                for l in range(out.shape[2]):
                                    out[j, k, l, :, :] += \
                                        values * \
                                        self.basis[i][c][-1][n][j, k, l]
                    elif len(refn.shape) == 6:  # fourth derivatives
                        for j in range(out.shape[0]):
                            for k in range(out.shape[1]):
                                for l in range(out.shape[2]):
                                    for m in range(out.shape[3]):
                                        out[j, k, l, m, :, :] += \
                                            values *\
                                            self.basis[i][c][-1][n][j, k, l, m]
                    else:
                        raise ValueError("The requested order of "
                                         "derivatives not supported.")
                return out

            # interpolate first and second derivatives
            for n in range(len(ref) - 1):
                if ref[n] is not None:
                    fs.append(linear_combination(n, ref[n]))
                else:
                    fs.append(None)

            # interpolate high-order derivatives
            fs.append([])

            if ref[-1] is not None:
                for n in range(len(ref[-1])):
                    fs[-1].append(linear_combination(n, ref[-1][n]))

            dfs.append(DiscreteField(*fs))

        if len(dfs) > 1:
            return tuple(dfs)
        return dfs[0]
예제 #13
0
def dddd(u: DiscreteField):
    """Fourth derivative (for :class:`~skfem.element.ElementGlobal`)."""
    if u.is_zero():
        return u
    return u.grad4
예제 #14
0
def dd(u: DiscreteField):
    """Hessian (for :class:`~skfem.element.ElementGlobal`)."""
    if u.is_zero():
        return u
    return u.hess
예제 #15
0
def sym_grad(u: DiscreteField):
    """Symmetric gradient."""
    if u.is_zero():
        return u
    return .5 * (u.grad + transpose(u.grad))
예제 #16
0
 def global_coordinates(self) -> ndarray:
     return DiscreteField(self.mapping.G(self.X, find=self.find))
예제 #17
0
def grad(u: DiscreteField):
    """Gradient."""
    if u.is_zero():
        return u
    return u.grad