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)
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)
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)
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)
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
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)
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'])))
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)))
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)