示例#1
0
    def inverse_mass_matrix(self):
        """Return the inverse mass matrix for this space."""
        from bempp.api.assembly.discrete_boundary_operator import (
            InverseSparseDiscreteBoundaryOperator, )

        if self._inverse_mass_matrix is None:
            self._inverse_mass_matrix = InverseSparseDiscreteBoundaryOperator(
                self.mass_matrix())
        return self._inverse_mass_matrix
示例#2
0
def discrete_coefficient_projection(space, new_space):
    """Discrete operator that projects coefficients from space to new_space."""

    from bempp.api.operators.boundary.sparse import identity
    from bempp.api.assembly.discrete_boundary_operator import \
        InverseSparseDiscreteBoundaryOperator

    ident1 = identity(space, new_space, new_space).weak_form()
    ident2 = identity(new_space, new_space, new_space).weak_form()

    return InverseSparseDiscreteBoundaryOperator(ident2) * ident1
示例#3
0
def get_inverse_mass_matrix(domain, dual_to_range):
    """
    Quickly get an inverse mass matrix operator.

    Uses the cached version from a function space if
    possible.
    """
    from bempp.api.assembly.discrete_boundary_operator import (
        InverseSparseDiscreteBoundaryOperator, )

    if domain == dual_to_range:
        return domain.inverse_mass_matrix()
    else:
        return InverseSparseDiscreteBoundaryOperator(
            get_mass_matrix(domain, dual_to_range))
示例#4
0
    def strong_form(self):
        """Return a discrete operator  that maps into the range space."""
        if self._range_map is None:

            # This is the most frequent case and we cache the mass
            # matrix from the space object.
            if self.range == self.dual_to_range:
                self._range_map = self.dual_to_range.inverse_mass_matrix()
            else:
                from bempp.api.assembly.discrete_boundary_operator import (
                    InverseSparseDiscreteBoundaryOperator, )
                from bempp.api.operators.boundary.sparse import identity

                self._range_map = InverseSparseDiscreteBoundaryOperator(
                    identity(self.range, self.range,
                             self.dual_to_range).weak_form())

        return self._range_map * self.weak_form()
示例#5
0
    def strong_form(self):
        """Return a discrete operator that maps into the range space.

        Parameters
        ----------
        recompute : bool
            Usually the strong form is cached. If this parameter is set to
            `true` the strong form is recomputed.
        """
        if self._range_map is None:

            nrows = len(self.range_spaces)

            _range_ops = _np.empty((nrows, nrows), dtype="O")

            for index in range(nrows):

                # This is the most frequent case and we cache the mass
                # matrix from the space object.
                if self.range_spaces[index] == self.dual_to_range_spaces[index]:
                    _range_ops[index, index] = self.dual_to_range_spaces[
                        index
                    ].inverse_mass_matrix()
                else:
                    from bempp.api.operators.boundary.sparse import identity
                    from bempp.api.assembly.discrete_boundary_operator import (
                        InverseSparseDiscreteBoundaryOperator,
                    )

                    _range_ops[index, index] = InverseSparseDiscreteBoundaryOperator(
                        identity(
                            self.range_spaces[index],
                            self.range_spaces[index],
                            self.dual_to_range_spaces[index],
                        ).weak_form()
                    )

            self._range_map = BlockedDiscreteOperator(_range_ops)

        return self._range_map * self.weak_form()
示例#6
0
    def coefficients(self):
        """Return coefficient vector."""
        if self._coefficients is None:
            from bempp.api.operators.boundary.sparse import identity
            from bempp.api.assembly.discrete_boundary_operator import (
                InverseSparseDiscreteBoundaryOperator,
            )

            op = InverseSparseDiscreteBoundaryOperator(
                identity(
                    self.space,
                    self.space,
                    self.dual_space,
                    parameters=self.parameters,
                )
                .weak_form()
                .A.tocsc()
            )
            self._coefficients = op @ self._projections
            self._representation = "primal"

        return self._coefficients
示例#7
0
    def strong_form(self, recompute=False):
        """Return a discrete operator that maps into the range space.

        Parameters
        ----------
        recompute : bool
            Usually the strong form is cached. If this parameter is set to
            `true` the strong form is recomputed.
        """
        if recompute is True:
            self._range_map = None

        if self._range_map is None:

            _range_ops = _np.empty((self.ndims[0], self.ndims[1]), dtype='O')

            for index in range(self.ndims[0]):

                # This is the most frequent case and we cache the mass
                # matrix from the space object.
                if self.range_spaces[index] == \
                        self.dual_to_range_spaces[index]:
                    _range_ops[index, index] = \
                        self.dual_to_range_spaces[index].inverse_mass_matrix()
                else:
                    from bempp.api.operators.boundary.sparse import identity
                    from bempp.api.assembly.discrete_boundary_operator import \
                        InverseSparseDiscreteBoundaryOperator

                    _range_ops[index, index] = \
                        InverseSparseDiscreteBoundaryOperator(
                            identity(
                                self.range_spaces[index],
                                self.range_spaces[index],
                                self.dual_to_range_spaces[index]).weak_form())

            self._range_map = BlockedDiscreteOperator(_range_ops)

        return self._range_map * self.weak_form(recompute)
blocked = BlockedDiscreteOperator(np.array(blocks))


# Next, we solve the system, then split the solution into the parts assosiated with u and λ. For an efficient solve, preconditioning is required.

# In[28]:


from bempp.api.assembly.discrete_boundary_operator import InverseSparseDiscreteBoundaryOperator
from scipy.sparse.linalg import LinearOperator

# Compute the sparse inverse of the Helmholtz operator
# Although it is not a boundary operator we can use
# the SparseInverseDiscreteBoundaryOperator function from
# BEM++ to turn its LU decomposition into a linear operator.
P1 = InverseSparseDiscreteBoundaryOperator(
    blocked[0,0].A.tocsc())

# For the Laplace slp we use a simple mass matrix preconditioner. 
# This is sufficient for smaller low-frequency problems.
P2 = InverseSparseDiscreteBoundaryOperator(
    bempp.api.operators.boundary.sparse.identity(
        bempp_space, bempp_space, bempp_space).weak_form())

# Create a block diagonal preconditioner object using the Scipy LinearOperator class
def apply_prec(x):
    """Apply the block diagonal preconditioner"""
    m1 = P1.shape[0]
    m2 = P2.shape[0]
    n1 = P1.shape[1]
    n2 = P2.shape[1]