Example #1
0
    def weak_form(self):
        """Return the weak form."""
        from bempp.api.assembly.discrete_boundary_operator import \
            SparseDiscreteBoundaryOperator

        if self._sparse_mat is not None:
            return SparseDiscreteBoundaryOperator(self._sparse_mat)

        backend = parameters['linear_algebra_backend']
        if backend not in ['PETSc', 'uBLAS']:
            parameters['linear_algebra_backend'] = 'PETSc'

        if parameters['linear_algebra_backend'] == 'PETSc':
            mat = as_backend_type(assemble(self._fenics_weak_form)).mat()
            (indptr, indices, data) = mat.getValuesCSR()
            self._sparse_mat = csr_matrix((data, indices, indptr),
                                          shape=mat.size)
        elif parameters['linear_algebra_backend'] == 'uBLAS':
            self._sparse_mat = assemble(self._fenics_weak_form).sparray()
        else:
            raise ValueError(
                "This should not happen! Backend type is %s. " +
                "Default backend should have been set to 'PETSc'.",
                str(parameters['linear_algebra_backend']))

        parameters['linear_algebra_backend'] = backend
        return SparseDiscreteBoundaryOperator(self._sparse_mat)
Example #2
0
    def assemble(self, operator_descriptor, device_interface, precision, *args,
                 **kwargs):
        """Assemble the singular part."""
        from bempp.api.assembly.discrete_boundary_operator import (
            SparseDiscreteBoundaryOperator, )
        from bempp.api.utils.helpers import promote_to_double_precision
        from scipy.sparse import coo_matrix, csr_matrix
        from bempp.api.space.space import return_compatible_representation

        domain, dual_to_range = return_compatible_representation(
            self.domain, self.dual_to_range)
        row_dof_count = dual_to_range.global_dof_count
        col_dof_count = domain.global_dof_count
        row_grid_dofs = dual_to_range.grid_dof_count
        col_grid_dofs = domain.grid_dof_count

        if domain.grid != dual_to_range.grid:
            return SparseDiscreteBoundaryOperator(
                csr_matrix((row_dof_count, col_dof_count), dtype="float64"))

        trial_local2global = domain.local2global.ravel()
        test_local2global = dual_to_range.local2global.ravel()
        trial_multipliers = domain.local_multipliers.ravel()
        test_multipliers = dual_to_range.local_multipliers.ravel()

        rows, cols, values = assemble_singular_part(
            domain.localised_space,
            dual_to_range.localised_space,
            self.parameters,
            operator_descriptor,
            device_interface,
        )
        global_rows = test_local2global[rows]
        global_cols = trial_local2global[cols]
        global_values = values * trial_multipliers[cols] * test_multipliers[
            rows]

        if self.parameters.assembly.always_promote_to_double:
            values = promote_to_double_precision(values)

        mat = coo_matrix(
            (global_values, (global_rows, global_cols)),
            shape=(row_grid_dofs, col_grid_dofs),
        ).tocsr()

        if domain.requires_dof_transformation:
            mat = mat @ domain.dof_transformation

        if dual_to_range.requires_dof_transformation:
            mat = dual_to_range.dof_transformation.T @ mat

        return SparseDiscreteBoundaryOperator(mat)
Example #3
0
    def assemble(self, operator_descriptor, device_interface, precision, *args,
                 **kwargs):
        """Sparse assembly of operators."""
        from bempp.api.utils.helpers import promote_to_double_precision
        from bempp.api.space.space import return_compatible_representation
        from .numba_kernels import select_numba_kernels
        from scipy.sparse import coo_matrix
        from bempp.api.assembly.discrete_boundary_operator import (
            SparseDiscreteBoundaryOperator, )

        domain, dual_to_range = return_compatible_representation(
            self.domain, self.dual_to_range)
        row_grid_dofs = dual_to_range.grid_dof_count
        col_grid_dofs = domain.grid_dof_count

        if domain.grid != dual_to_range.grid:
            raise ValueError(
                "For sparse operators the domain and dual_to_range grids must be identical."
            )

        trial_local2global = domain.local2global.ravel()
        test_local2global = dual_to_range.local2global.ravel()
        trial_multipliers = domain.local_multipliers.ravel()
        test_multipliers = dual_to_range.local_multipliers.ravel()

        numba_assembly_function, numba_kernel_function = select_numba_kernels(
            operator_descriptor, mode="sparse")

        rows, cols, values = assemble_sparse(
            domain.localised_space,
            dual_to_range.localised_space,
            self.parameters,
            operator_descriptor,
            numba_assembly_function,
            numba_kernel_function,
        )
        global_rows = test_local2global[rows]
        global_cols = trial_local2global[cols]
        global_values = values * trial_multipliers[cols] * test_multipliers[
            rows]

        if self.parameters.assembly.always_promote_to_double:
            values = promote_to_double_precision(values)

        mat = coo_matrix(
            (global_values, (global_rows, global_cols)),
            shape=(row_grid_dofs, col_grid_dofs),
        ).tocsr()

        if domain.requires_dof_transformation:
            mat = mat @ domain.dof_transformation

        if dual_to_range.requires_dof_transformation:
            mat = dual_to_range.dof_transformation.T @ mat

        return SparseDiscreteBoundaryOperator(mat)
Example #4
0
    def weak_form(self):
        """Return the weak form."""
        from bempp.api.assembly.discrete_boundary_operator import (
            SparseDiscreteBoundaryOperator, )
        from dolfin import as_backend_type, assemble, parameters
        from scipy.sparse import csr_matrix

        if self._sparse_mat is not None:
            return SparseDiscreteBoundaryOperator(self._sparse_mat)

        backend = parameters["linear_algebra_backend"]
        if backend != "PETSc":
            raise ValueError(
                "Only the PETSc linear algebra backend is supported.")
        mat = as_backend_type(assemble(self._fenics_weak_form)).mat()
        (indptr, indices, data) = mat.getValuesCSR()
        self._sparse_mat = csr_matrix((data, indices, indptr), shape=mat.size)

        return SparseDiscreteBoundaryOperator(self._sparse_mat)
Example #5
0
    def assemble_weak_form(self, parameters):
        """Assemble the local operator and return the assembled operator."""
        #pylint: disable=no-name-in-module
        from bempp.core.assembly.discrete_boundary_operator import \
            convert_to_sparse
        from bempp.api.assembly.discrete_boundary_operator import \
            SparseDiscreteBoundaryOperator

        discrete_operator = SparseDiscreteBoundaryOperator(
            convert_to_sparse(self._impl.assemble_weak_form(parameters)))

        return discrete_operator
Example #6
0
    def weak_form(self):
        """Return the weak form."""
        from bempp.api.assembly.discrete_boundary_operator import (
            SparseDiscreteBoundaryOperator, )
        from dolfinx.fem import assemble_matrix
        from scipy.sparse import csr_matrix

        if self._sparse_mat is None:
            mat = assemble_matrix(self._fenics_weak_form)
            mat.assemble()
            (indptr, indices, data) = mat.getValuesCSR()
            self._sparse_mat = csr_matrix((data, indices, indptr),
                                          shape=mat.size)

        return SparseDiscreteBoundaryOperator(self._sparse_mat)
Example #7
0
def _matrix_from_integration_pairs(
        assembler,
        all_test_trial_function_pairs,
        dof_map, dof_count, weak_form_lookup):
    """Create a sparse matrix from integration pairs."""
    #pylint: disable=too-many-locals
    import numpy as np
    from scipy.sparse import csc_matrix
    from bempp.api.assembly.discrete_boundary_operator import \
        SparseDiscreteBoundaryOperator

    data = np.zeros(len(all_test_trial_function_pairs),
                    dtype=assembler.dtype)
    row_indices = np.zeros(len(all_test_trial_function_pairs),
                           dtype=np.int)
    col_indices = np.zeros(len(all_test_trial_function_pairs),
                           dtype=np.int)

    for index, (test_index, trial_index) in enumerate(
            all_test_trial_function_pairs):

        row_indices[index] = test_index
        col_indices[index] = trial_index

        # Get local dofs and dof_weights
        test_dofs, test_weights = (dof_map['test'][0][test_index],
                                   dof_map['test'][1][test_index])
        trial_dofs, trial_weights = (dof_map['trial'][0][trial_index],
                                     dof_map['trial'][1][trial_index])

        for i, test_dof in enumerate(test_dofs):
            for j, trial_dof in enumerate(trial_dofs):
                element_pair = (test_dof.entity_index,
                                trial_dof.entity_index)
                weak_form_data = weak_form_lookup.get(element_pair)
                data[index] += (weak_form_data[test_dof.dof_index,
                                               trial_dof.dof_index] *
                                #pylint: disable=no-member
                                np.conj(test_weights[i]) *
                                #pylint: disable=no-member
                                np.conj(trial_weights[j]))

    return SparseDiscreteBoundaryOperator(
        csc_matrix((data, (row_indices, col_indices)),
                   shape=(dof_count['test'], dof_count['trial'])))
Example #8
0
def assemble_singular_part(operator):
    """Assemble the singular part of an integral operator."""
    #pylint: disable=too-many-locals
    from scipy.sparse import csc_matrix
    from bempp.api.assembly.discrete_boundary_operator import \
        SparseDiscreteBoundaryOperator

    test_space = operator.dual_to_range
    trial_space = operator.domain

    test_dof_count = operator.dual_to_range.global_dof_count
    trial_dof_count = operator.domain.global_dof_count

    # If the test and trial grid are different return a zero matrix

    if operator.domain.grid != operator.dual_to_range.grid:
        return SparseDiscreteBoundaryOperator(
            csc_matrix((test_dof_count, trial_dof_count)))

    # Cache the global to local accesses
    test_dof_map = test_space.global_to_local_dofs(range(test_dof_count))
    trial_dof_map = trial_space.global_to_local_dofs(range(trial_dof_count))

    grid = operator.domain.grid

    # Now get adjacent element pairs

    vertex_to_element_matrix = grid.leaf_view.vertex_to_element_matrix
    element_to_element_matrix = vertex_to_element_matrix.transpose().dot(
        vertex_to_element_matrix)

    nonzero_pairs = element_to_element_matrix.nonzero()
    index_pairs = zip(nonzero_pairs[0], nonzero_pairs[1])

    # Now get all pairs of basis functions who partially
    # overlap via adjacent elements

    all_test_trial_function_pairs = []

    for pair in index_pairs:

        test_element = grid.leaf_view.element_from_index(pair[0])
        trial_element = grid.leaf_view.element_from_index(pair[1])

        global_test_dofs = test_space.get_global_dofs(test_element)
        global_trial_dofs = trial_space.get_global_dofs(trial_element)

        for test_dof_index in global_test_dofs:
            if test_dof_index > -1:
                for trial_dof_index in global_trial_dofs:
                    if trial_dof_index > -1:
                        all_test_trial_function_pairs.append(
                            (test_dof_index, trial_dof_index))

    # Remove duplicates
    all_test_trial_function_pairs = list(set(all_test_trial_function_pairs))

    # Now get all integraton element pairs associated

    all_integration_element_pairs = []

    for function_pair in all_test_trial_function_pairs:

        test_local_dofs = test_dof_map[0][function_pair[0]]
        trial_local_dofs = trial_dof_map[0][function_pair[1]]

        for test_dof in test_local_dofs:
            for trial_dof in trial_local_dofs:
                all_integration_element_pairs.append(
                    (test_dof.entity_index, trial_dof.entity_index))

    # Remove duplicates
    all_integration_element_pairs = list(set(all_integration_element_pairs))

    # Now compute all local dof interactions

    assembler = operator.local_assembler

    weak_forms = assembler.evaluate_local_weak_forms(
        all_integration_element_pairs)

    # Create a dictionary

    weak_form_lookup = dict(zip(all_integration_element_pairs, weak_forms))

    # Now need to create the sparse matrix

    return _matrix_from_integration_pairs(
        operator.local_assembler,
        all_test_trial_function_pairs,
        {'test': test_dof_map, 'trial': trial_dof_map},
        {'test': test_dof_count, 'trial': trial_dof_count},
        weak_form_lookup)
def assemble_diagonal(operator):
    """Assemble the singular part of an integral operator."""

    from scipy.sparse import csc_matrix
    from bempp.api.assembly.discrete_boundary_operator import SparseDiscreteBoundaryOperator

    test_space = operator.dual_to_range
    trial_space = operator.domain

    test_dof_count = operator.dual_to_range.global_dof_count
    trial_dof_count = operator.domain.global_dof_count

    # If the test and trial grid are different return a zero matrix

    #if operator.domain.grid != operator.dual_to_range.grid:
    #return SparseDiscreteBoundaryOperator(csc_matrix((test_dof_count, trial_dof_count)))

    grid = operator.domain.grid

    # Now get adjacent element pairs

    vertex_to_element_matrix = grid.leaf_view.vertex_to_element_matrix

    element_to_element_matrix = vertex_to_element_matrix.transpose().dot(
        vertex_to_element_matrix)

    #element_to_element_matrix2 = np.dot(element_to_element_matrix,element_to_element_matrix)
    nonzero_pairs = element_to_element_matrix.nonzero()
    index_pairs = zip(nonzero_pairs[0], nonzero_pairs[1])

    # Now get all pairs of basis functions who partially overlap via adjacent elements

    all_test_trial_function_pairs = []

    for pair in index_pairs:

        test_element = grid.leaf_view.element_from_index(pair[0])
        trial_element = grid.leaf_view.element_from_index(pair[1])

        global_test_dofs = test_space.get_global_dofs(test_element)
        global_trial_dofs = trial_space.get_global_dofs(trial_element)

        #for test_dof_index in global_test_dofs:
        #if test_dof_index > -1:
        #for trial_dof_index in global_trial_dofs:
        #if trial_dof_index > -1:
        #all_test_trial_function_pairs.append((test_dof_index, trial_dof_index))
        for test_dof_index in global_test_dofs:
            #for trial_dof_index in global_trial_dofs:
            if test_dof_index > -1:
                all_test_trial_function_pairs.append(
                    (test_dof_index, test_dof_index))
    # Remove duplicates
    all_test_trial_function_pairs = list(set(all_test_trial_function_pairs))

    # Now get all integraton element pairs associated

    all_integration_element_pairs = []

    for function_pair in all_test_trial_function_pairs:

        local_dofs = test_space.global_to_local_dofs(function_pair)[0]
        test_local_dofs = local_dofs[0]
        trial_local_dofs = local_dofs[1]

        for test_dof in test_local_dofs:
            for trial_dof in trial_local_dofs:
                all_integration_element_pairs.append(
                    (test_dof.entity_index, trial_dof.entity_index))

    # Remove duplicates
    all_integration_element_pairs = list(set(all_integration_element_pairs))

    # Now compute all local dof interactions

    assembler = operator.local_assembler

    weak_forms = assembler.evaluate_local_weak_forms(
        all_integration_element_pairs)

    # Create a dictionary

    weak_form_lookup = dict(zip(all_integration_element_pairs, weak_forms))

    # Now need to create the sparse matrix

    data = np.zeros(len(all_test_trial_function_pairs), dtype=assembler.dtype)
    row_indices = np.zeros(len(all_test_trial_function_pairs), dtype=np.int)
    col_indices = np.zeros(len(all_test_trial_function_pairs), dtype=np.int)

    #import ipdb; ipdb.set_trace()

    for index, (test_index,
                trial_index) in enumerate(all_test_trial_function_pairs):

        row_indices[index] = test_index
        col_indices[index] = trial_index

        # Get local dofs and dof_weights
        local_dofs, weights = test_space.global_to_local_dofs(
            [test_index, trial_index])
        test_dofs, trial_dofs = local_dofs
        test_weights, trial_weights = weights

        for i, test_dof in enumerate(test_dofs):
            for j, trial_dof in enumerate(trial_dofs):
                element_pair = (test_dof.entity_index, trial_dof.entity_index)
                data[index] += (
                    weak_form_lookup[element_pair][test_dof.dof_index,
                                                   trial_dof.dof_index] *
                    np.conj(test_weights[i]) * np.conj(trial_weights[j]))

    return SparseDiscreteBoundaryOperator(
        csc_matrix((data, (row_indices, col_indices)),
                   shape=(test_dof_count, trial_dof_count)))
Example #10
0
    def _assemble(self):
        """Assemble the operator."""
        from bempp.api.space.space import return_compatible_representation
        from bempp.api.assembly.discrete_boundary_operator import (
            SparseDiscreteBoundaryOperator, )
        from bempp.api.integration.triangle_gauss import rule
        from scipy.sparse import coo_matrix

        import numpy as _np

        points, weights = rule(self._parameters.quadrature.regular)
        npoints = len(weights)

        comp_trial, comp_test, comp_fun = return_compatible_representation(
            self.domain, self.dual_to_range, self._grid_fun.space)

        grid = comp_trial.grid

        if self._mode == "component":
            op = _np.multiply
        elif self._mode == "inner":
            op = lambda x, y: _np.sum(
                x * y.reshape[:, _np.newaxis, :], axis=0, keepdims=True)

        elements = (set(comp_test.support_elements).intersection(
            set(comp_trial.support_elements)).intersection(
                set(comp_fun.support_elements)))

        elements = _np.flatnonzero(comp_trial.support * comp_test.support *
                                   comp_fun.support)

        number_of_elements = len(elements)
        nshape_trial = comp_trial.shapeset.number_of_shape_functions
        nshape_test = comp_test.shapeset.number_of_shape_functions
        nshape = nshape_trial * nshape_test

        data = _np.zeros(number_of_elements * nshape_trial * nshape_test)

        for index, elem_index in enumerate(elements):
            scale_vals = (self._grid_fun.evaluate(elem_index, points) *
                          weights * grid.integration_elements[index])
            domain_vals = comp_trial.evaluate(elem_index, points)
            trial_vals = op(domain_vals, scale_vals)
            test_vals = _np.conj(comp_test.evaluate(elem_index, points))
            res = _np.tensordot(test_vals, trial_vals, axes=([0, 2], [0, 2]))
            data[nshape * index:nshape * (1 + index)] = res.ravel()

        irange = _np.arange(nshape_test)
        jrange = _np.arange(nshape_trial)

        rows = _np.tile(_np.repeat(irange, nshape_trial),
                        number_of_elements) + _np.repeat(
                            elements * nshape_test, nshape)

        cols = _np.tile(_np.tile(jrange, nshape_test),
                        number_of_elements) + _np.repeat(
                            elements * nshape_trial, nshape)

        new_rows = comp_test.local2global.ravel()[rows]
        new_cols = comp_trial.local2global.ravel()[cols]

        nrows = comp_test.dof_transformation.shape[0]
        ncols = comp_trial.dof_transformation.shape[0]

        mat = coo_matrix((data, (new_rows, new_cols)),
                         shape=(nrows, ncols)).tocsr()

        if comp_trial.requires_dof_transformation:
            mat = mat @ self.domain.dof_transformation

        if comp_test.requires_dof_transformation:
            mat = self.dual_to_range.dof_transformation.T @ mat

        return SparseDiscreteBoundaryOperator(mat)