def derivative_ex(dirichl_space, neumann_space, ep_in, ep_ex, kappa, operator_assembler): """ Construct the system matrix and RHS grid functions using derivative formulation with interior values. """ phi_id = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_id = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in dF = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) dP = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) B = 1 / ep * dF - dP F = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) P = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) A = F - P ddF = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) ddP = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) D = 1 / ep * (ddP - ddF) dF0 = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=operator_assembler) dP0 = modified_helmholtz.adjoint_double_layer(neumann_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) C = dF0 - 1.0 / ep * dP0 A_sys = bempp.api.BlockedOperator(2, 2) A_sys[0, 0] = (0.5 * (1.0 + (1.0 / ep)) * phi_id) + B A_sys[0, 1] = -A A_sys[1, 0] = D A_sys[1, 1] = (0.5 * (1.0 + (1.0 / ep)) * dph_id) - C return A_sys
def alpha_beta_single_blocked_operator(dirichl_space, neumann_space, ep_in, ep_ex, kappa, alpha, beta, operator_assembler): dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) slp_in = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) hlp_in = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) adlp_in = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=operator_assembler) dlp_out = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) slp_out = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) hlp_out = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) adlp_out = modified_helmholtz.adjoint_double_layer( neumann_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) phi_identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_identity = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (-0.5 * (1 + alpha)) * phi_identity + (alpha * dlp_out) - dlp_in A[0, 1] = slp_in - ((alpha / ep) * slp_out) A[1, 0] = hlp_in - (beta * hlp_out) A[1, 1] = (-0.5 * (1 + (beta / ep))) * dph_identity + adlp_in - ((beta / ep) * adlp_out) return A
def juffer(dirichl_space, neumann_space, ep_in, ep_ex, kappa, operator_assembler): phi_id = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_id = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in dF = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) dP = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) L1 = (ep * dP) - dF F = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) P = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) L2 = F - P ddF = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) ddP = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) L3 = ddP - ddF dF0 = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=operator_assembler) dP0 = modified_helmholtz.adjoint_double_layer(neumann_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) L4 = dF0 - ((1.0 / ep) * dP0) A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (0.5 * (1.0 + ep) * phi_id) - L1 A[0, 1] = (-1.0) * L2 A[1, 0] = L3 # Sign change due to bempp definition A[1, 1] = (0.5 * (1.0 + (1.0 / ep)) * dph_id) - L4 return A
def discrete_coefficient_projection(space, new_space): """Return a discrete operator that projects coefficients from space into 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
def lu(dirichl_space, neumann_space, ep_in, ep_ex, kappa, operator_assembler): dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) slp_in = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) hlp_in = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) adlp_in = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=operator_assembler) dlp_ex = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) slp_ex = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) hlp_ex = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) adlp_ex = modified_helmholtz.adjoint_double_layer( neumann_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) phi_identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_identity = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (0.5 * (1 + (1.0 / ep))) * phi_identity - dlp_ex + (1.0 / ep) * dlp_in A[0, 1] = slp_ex - slp_in A[1, 0] = (1.0 / ep) * hlp_ex - (1.0 / ep) * hlp_in A[1, 1] = (0.5 * (1 + (1.0 / ep))) * dph_identity + (1.0 / ep) * adlp_ex - adlp_in return A
def test_mass_matrix_of_barycentric_space_agrees_with_non_barycentric_space(self): from bempp.api.operators.boundary.sparse import identity barycentric_ident = identity(self._bary_space, self._bary_space, self._bary_space).weak_form().sparse_operator ident = identity(self._space, self._space, self._space).weak_form().sparse_operator diff = barycentric_ident - ident self.assertAlmostEqual(diff.max(), 0, 15) self.assertAlmostEqual(diff.min(), 0, 15)
def muller_internal(dirichl_space, neumann_space, ep_in, ep_ex, kappa, operator_assembler): dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) slp_in = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) hlp_in = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) adlp_in = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=operator_assembler) dlp_ex = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) slp_ex = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) hlp_ex = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) adlp_ex = modified_helmholtz.adjoint_double_layer( neumann_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) phi_identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_identity = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in A = bempp.api.BlockedOperator(2, 2) A[0, 0] = phi_identity + dlp_in - dlp_ex A[0, 1] = -slp_in + ((1.0 / ep) * slp_ex) A[1, 0] = -hlp_in + (ep * hlp_ex) A[1, 1] = dph_identity - adlp_in + adlp_ex return A
def juffer(dirichl_space, neumann_space, q, x_q, ep_in, ep_ex, kappa): from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz phi_id = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_id = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in dF = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space) dP = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa) L1 = (ep * dP) - dF F = laplace.single_layer(neumann_space, dirichl_space, dirichl_space) P = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa) L2 = F - P ddF = laplace.hypersingular(dirichl_space, neumann_space, neumann_space) ddP = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa) L3 = ddP - ddF dF0 = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space) dP0 = modified_helmholtz.adjoint_double_layer(neumann_space, neumann_space, neumann_space, kappa) L4 = dF0 - ((1.0 / ep) * dP0) A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (0.5 * (1.0 + ep) * phi_id) - L1 A[0, 1] = (-1.0) * L2 A[1, 0] = L3 # Cambio de signo por definicion de bempp A[1, 1] = (0.5 * (1.0 + (1.0 / ep)) * dph_id) - L4 @bempp.api.real_callable def d_green_func(x, n, domain_index, result): nrm = np.sqrt((x[0] - x_q[:, 0])**2 + (x[1] - x_q[:, 1])**2 + (x[2] - x_q[:, 2])**2) const = -1. / (4. * np.pi * ep_in) result[:] = const * np.sum(q * np.dot(x - x_q, n) / (nrm**3)) @bempp.api.real_callable def green_func(x, n, domain_index, result): nrm = np.sqrt((x[0] - x_q[:, 0])**2 + (x[1] - x_q[:, 1])**2 + (x[2] - x_q[:, 2])**2) result[:] = np.sum(q / nrm) / (4. * np.pi * ep_in) rhs_1 = bempp.api.GridFunction(dirichl_space, fun=green_func) rhs_2 = bempp.api.GridFunction(dirichl_space, fun=d_green_func) return A, rhs_1, rhs_2
def _compute_burton_miller(self): from bempp.api.operators.boundary.sparse import identity from bempp.api.operators.boundary.helmholtz import double_layer from bempp.api.operators.boundary.helmholtz import hypersingular from bempp.api.operators.boundary.helmholtz import osrc_ntd space = self._space wavenumber = self._wavenumber if self._id is None: self._id = identity(space, space, space) if self._double_layer is None: self._double_layer = double_layer(space, space, space, wavenumber) if self._hypersingular is None: self._hypersingular = hypersingular(space, space, space, wavenumber, use_slp=True) if self._coupling == 'osrc' and self._osrc is None: self._osrc = osrc_ntd(space, wavenumber) if self._burton_miller_operator is None: if self._coupling == 'osrc': self._burton_miller_operator = ( .5 * self._id - self._double_layer - self._osrc * self._hypersingular) else: self._burton_miller_operator = ( .5 * self._id - self._double_layer - (1j / self._wavenumber) * self._hypersingular)
def direct(dirichl_space, neumann_space, q, x_q, ep_in, ep_out, kappa): from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) slp_in = laplace.single_layer(neumann_space, dirichl_space, dirichl_space) dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space) slp_out = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa) dlp_out = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa) # Matrix Assembly blocked = bempp.api.BlockedOperator(2, 2) blocked[0, 0] = 0.5*identity + dlp_in blocked[0, 1] = -slp_in blocked[1, 0] = 0.5*identity - dlp_out blocked[1, 1] = (ep_in/ep_out)*slp_out #A = blocked.strong_form() A = blocked @bempp.api.real_callable def charges_fun(x, n, domain_index, result): nrm = np.sqrt((x[0]-x_q[:,0])**2 + (x[1]-x_q[:,1])**2 + (x[2]-x_q[:,2])**2) aux = np.sum(q/nrm) result[0] = aux/(4*np.pi*ep_in) @bempp.api.real_callable def zero(x, n, domain_index, result): result[0] = 0 rhs_1 = bempp.api.GridFunction(dirichl_space, fun=charges_fun) rhs_2 = bempp.api.GridFunction(neumann_space, fun=zero) return A, rhs_1, rhs_2
def strong_form(self, mode='simple'): if not self._fill_complete(): raise ValueError("Each row and column must have at least one operator") if mode=='full': discrete_operator = BlockedDiscreteOperator(self._m, self._n) for i in range(self._m): for j in range(self._n): if self._operators[i, j] is not None: discrete_operator[i, j] = self._operators[i, j].strong_form() return discrete_operator elif mode=='simple': from bempp.api import InverseSparseDiscreteBoundaryOperator from bempp.api.operators.boundary.sparse import identity blocked = BlockedDiscreteOperator(self.ndims[0], self.ndims[0]) for i in range(self.ndims[0]): op = None for j in range(self.ndims[1]): if self[i, j] is not None: op = self[i, j] break blocked[i, i] = InverseSparseDiscreteBoundaryOperator( identity(op.range, op.dual_to_range, op.dual_to_range).weak_form()) return blocked * self.weak_form() else: raise ValueError("Unknown value for 'mode'. Allowed values are 'simple' and 'full'")
def projections(self, dual_space=None): """ Compute the vector of projections onto the given dual space. Parameters ---------- dual_space : bempp.api.space.Space A representation of the dual space. If not specified then space == dual_space is assumed (optional). Returns ------- out : np.ndarray A vector of projections onto the dual space. """ from bempp.api.operators.boundary.sparse import identity if dual_space is None: dual_space = self.space ident = identity(self.space, self.space, dual_space).weak_form() return ident * self.coefficients
def _weak_form_impl(self): from bempp.api.operators.boundary.sparse import identity from bempp.api.operators.boundary.sparse import laplace_beltrami from bempp.api import ZeroBoundaryOperator from bempp.api import InverseSparseDiscreteBoundaryOperator import numpy as np space = self._space # Get the operators mass = identity(space, space, space, parameters=self._parameters).weak_form() stiff = laplace_beltrami(space, space, space, parameters=self._parameters).weak_form() # Compute damped wavenumber bbox = self._space.grid.bounding_box rad = np.linalg.norm(bbox[1, :] - bbox[0, :]) / 2 dk = self._wave_number + 1j * 0.4 * self._wave_number ** (1.0 / 3.0) * rad ** (-2.0 / 3.0) # Get the Pade coefficients c0, alpha, beta = _pade_coeffs(self._npade, self._theta) # Now put all operators together term = ZeroBoundaryOperator(space, space, space).weak_form() for i in range(self._npade): term -= (alpha[i] / (dk ** 2) * stiff * InverseSparseDiscreteBoundaryOperator( mass - beta[i] / (dk ** 2) * stiff)) result = 1j * self._wave_number * (c0 * mass + term * mass) return result
def block_diagonal_precon_direct_external(dirichl_space, neumann_space, ep_in, ep_ex, kappa, permuted_rows=False): from scipy.sparse import diags, bmat from scipy.sparse.linalg import aslinearoperator from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz # block-diagonal preconditioner identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) identity_diag = identity.weak_form().to_sparse().diagonal() slp_in_diag = laplace.single_layer( neumann_space, dirichl_space, dirichl_space, assembler="only_diagonal_part").weak_form().get_diagonal() dlp_in_diag = laplace.double_layer( dirichl_space, dirichl_space, dirichl_space, assembler="only_diagonal_part").weak_form().get_diagonal() slp_out_diag = modified_helmholtz.single_layer( neumann_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().get_diagonal() dlp_out_diag = modified_helmholtz.double_layer( neumann_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().get_diagonal() if permuted_rows: diag11 = 0.5 * identity_diag + dlp_in_diag diag12 = -(ep_ex / ep_in) * slp_in_diag diag21 = 0.5 * identity_diag - dlp_out_diag diag22 = slp_out_diag else: diag11 = 0.5 * identity_diag - dlp_out_diag diag12 = slp_out_diag diag21 = 0.5 * identity_diag + dlp_in_diag diag22 = -(ep_ex / ep_in) * slp_in_diag d_aux = 1 / (diag22 - diag21 * diag12 / diag11) diag11_inv = 1 / diag11 + 1 / diag11 * diag12 * d_aux * diag21 / diag11 diag12_inv = -1 / diag11 * diag12 * d_aux diag21_inv = -d_aux * diag21 / diag11 diag22_inv = d_aux block_mat_precond = bmat([[diags(diag11_inv), diags(diag12_inv)], [diags(diag21_inv), diags(diag22_inv)]]).tocsr() return aslinearoperator(block_mat_precond)
def _weak_form_impl(self): from bempp.api.operators.boundary.sparse import identity from .discrete_boundary_operator import InverseSparseDiscreteBoundaryOperator projected_weak_form = self._operator.weak_form() if self._dual_to_range is not None: ident = identity(self._operator.dual_to_range, self._dual_to_range, self._dual_to_range).weak_form() projected_weak_form = ident * InverseSparseDiscreteBoundaryOperator( identity(self._operator.dual_to_range, self._operator.dual_to_range, self._operator.dual_to_range).weak_form()) * projected_weak_form if self._domain is not None: from bempp.api.space.projection import discrete_coefficient_projection projected_weak_form *= discrete_coefficient_projection(self._domain, self._operator.domain) return projected_weak_form
def laplace_beltrami_eigenpairs(space, k=6, tol=1E-5): """Compute k Laplace Beltrami eigenpairs over a given space.""" from scipy.sparse.linalg import eigs from bempp.api.operators.boundary.sparse import \ laplace_beltrami from bempp.api.operators.boundary.sparse import \ identity operator = laplace_beltrami(space, space, space) ident = identity(space, space, space) return eigs(operator, M=ident, sigma=0, tol=tol, k=k)
def direct(dirichl_space, neumann_space, assembler, q, x_q): """ Construct the system matrix and RHS grid functions using direct formulation. """ ep_in = PARAMS.ep_in ep_ex = PARAMS.ep_ex kappa = PARAMS.kappa identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) slp_in = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=assembler) dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=assembler) slp_out = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=assembler) dlp_out = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=assembler) A_sys = bempp.api.BlockedOperator(2, 2) A_sys[0, 0] = 0.5 * identity + dlp_in A_sys[0, 1] = -slp_in A_sys[1, 0] = 0.5 * identity - dlp_out A_sys[1, 1] = (ep_in / ep_ex) * slp_out @bempp.api.callable(vectorized=True) def rhs1_fun(x, n, domain_index, result): import exafmm.laplace as _laplace sources = _laplace.init_sources(x_q, q) targets = _laplace.init_targets(x.T) fmm = _laplace.LaplaceFmm(p=10, ncrit=500, filename='.rhs.tmp') tree = _laplace.setup(sources, targets, fmm) values = _laplace.evaluate(tree, fmm) os.remove('.rhs.tmp') result[:] = values[:, 0] / ep_in @bempp.api.real_callable def rhs2_fun(x, n, domain_index, result): result[0] = 0 rhs1 = bempp.api.GridFunction(dirichl_space, fun=rhs1_fun) rhs2 = bempp.api.GridFunction(neumann_space, fun=rhs2_fun) return A_sys, rhs1, rhs2
def alpha_beta_external(dirichl_space, neumann_space, ep_in, ep_ex, kappa, alpha, beta, operator_assembler): phi_id = sparse.identity(dirichl_space, dirichl_space, dirichl_space) dph_id = sparse.identity(neumann_space, neumann_space, neumann_space) ep = ep_ex / ep_in A_in = laplace_multitrace(dirichl_space, neumann_space, operator_assembler) A_ex = mod_helm_multitrace(dirichl_space, neumann_space, kappa, operator_assembler) D = bempp.api.BlockedOperator(2, 2) D[0, 0] = alpha * phi_id D[0, 1] = 0.0 * phi_id D[1, 0] = 0.0 * phi_id D[1, 1] = beta * dph_id E_1 = bempp.api.BlockedOperator(2, 2) E_1[0, 0] = phi_id E_1[0, 1] = 0.0 * phi_id E_1[1, 0] = 0.0 * phi_id E_1[1, 1] = dph_id * ep F = bempp.api.BlockedOperator(2, 2) F[0, 0] = alpha * phi_id F[0, 1] = 0.0 * phi_id F[1, 0] = 0.0 * phi_id F[1, 1] = dph_id * (beta / ep) Id = bempp.api.BlockedOperator(2, 2) Id[0, 0] = phi_id Id[0, 1] = 0.0 * phi_id Id[1, 0] = 0.0 * phi_id Id[1, 1] = dph_id interior_projector = ((0.5 * Id) + A_in) * E_1 scaled_exterior_projector = D * ((0.5 * Id) - A_ex) A = (((0.5 * Id) + A_in) * E_1) + (D * ((0.5 * Id) - A_ex)) - D - E_1 return A, A_in, A_ex, interior_projector, scaled_exterior_projector
def __init__(self, space, dual_space=None, fun=None, coefficients=None, projections=None, parameters=None): import bempp.api import numpy as np if space is None: raise ValueError("space must not be None.") if parameters is None: parameters = bempp.api.global_parameters if sum([1 for a in [fun, coefficients, projections] if a is not None]) != 1: raise ValueError("Exactly one of 'fun', 'coefficients' or 'projections' must " + "be given.") self._coefficients = None self._space = space self._parameters = parameters if coefficients is not None: self.coefficients = coefficients if fun is not None: from bempp.core.assembly.function_projector import calculate_projection if dual_space is not None: proj_space = dual_space else: proj_space = self.space projections = calculate_projection(parameters, fun, proj_space._impl) if projections is not None: np_proj = 1.0 * np.asarray(projections).squeeze() if np_proj.ndim > 1: raise ValueError("'projections' must be a 1-d array.") from bempp.api.assembly import InverseSparseDiscreteBoundaryOperator if dual_space is not None: proj_space = dual_space else: proj_space = self.space from bempp.api.operators.boundary.sparse import identity inv_ident = InverseSparseDiscreteBoundaryOperator(\ identity(self.space, self.space, proj_space).weak_form()) self._coefficients = inv_ident * projections
def block_diagonal(dirichl_space, neumann_space, A): """ Compute the block-diagonal preconditioner for system matrix A. Suitable for direct formulation. """ ep_in = PARAMS.ep_in ep_ex = PARAMS.ep_ex kappa = PARAMS.kappa identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) identity_diag = identity.weak_form().A.diagonal() slp_in_diag = laplace.single_layer( neumann_space, dirichl_space, dirichl_space, assembler="only_diagonal_part").weak_form().A dlp_in_diag = laplace.double_layer( dirichl_space, dirichl_space, dirichl_space, assembler="only_diagonal_part").weak_form().A slp_out_diag = modified_helmholtz.single_layer( neumann_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().A dlp_out_diag = modified_helmholtz.double_layer( neumann_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().A diag11 = .5 * identity_diag + dlp_in_diag diag12 = -slp_in_diag diag21 = .5 * identity_diag - dlp_out_diag diag22 = (ep_in / ep_ex) * slp_out_diag d_aux = 1 / (diag22 - diag21 * diag12 / diag11) diag11_inv = 1 / diag11 + 1 / diag11 * diag12 * d_aux * diag21 / diag11 diag12_inv = -1 / diag11 * diag12 * d_aux diag21_inv = -d_aux * diag21 / diag11 diag22_inv = d_aux block_mat_precond = bmat([[diags(diag11_inv), diags(diag12_inv)], [diags(diag21_inv), diags(diag22_inv)]]).tocsr() return aslinearoperator(block_mat_precond)
def _weak_form_impl(self): from bempp.api.operators.boundary.sparse import identity from .discrete_boundary_operator import ZeroDiscreteBoundaryOperator from .discrete_boundary_operator import InverseSparseDiscreteBoundaryOperator discrete_op = ZeroDiscreteBoundaryOperator(self.dual_to_range.global_dof_count, self.domain.global_dof_count) test_inverse = InverseSparseDiscreteBoundaryOperator( identity(self._test_local_ops[0].domain, self._kernel_op.domain, self._kernel_op.dual_to_range, parameters=self._parameters).weak_form()) trial_inverse = InverseSparseDiscreteBoundaryOperator(identity(self._kernel_op.domain, self._kernel_op.domain, self._trial_local_ops[0].dual_to_range, parameters=self._parameters).weak_form()) kernel_discrete_op = self._kernel_op.weak_form() for i in range(self._number_of_ops): discrete_op += (self._test_local_ops[i].weak_form() * test_inverse * kernel_discrete_op * trial_inverse * self._trial_local_ops[i].weak_form()) return discrete_op
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()
def _weak_form_impl(self): from bempp.api.operators.boundary.sparse import identity from bempp.api.operators.boundary.sparse import laplace_beltrami from bempp.api import ZeroBoundaryOperator from bempp.api import InverseSparseDiscreteBoundaryOperator space = self._space # Get the operators mass = identity(space, space, space, parameters=self._parameters).weak_form() stiff = laplace_beltrami(space, space, space, parameters=self._parameters).weak_form() # Compute damped wavenumber if self._damped_wavenumber is None: bbox = self._space.grid.bounding_box rad = _np.linalg.norm(bbox[1, :] - bbox[0, :]) / 2 dk = self._wave_number + 1j * 0.4 * \ self._wave_number ** (1.0 / 3.0) * rad ** (-2.0 / 3.0) else: dk = self._damped_wavenumber # Get the Pade coefficients c0, alpha, beta = _pade_coeffs(self._npade, self._theta) # Now put all operators together term = ZeroBoundaryOperator(space, space, space).weak_form() for i in range(self._npade): term -= (alpha[i] / (dk**2) * stiff * InverseSparseDiscreteBoundaryOperator(mass - beta[i] / (dk**2) * stiff)) result = 1. / (1j * self._wave_number) * ( mass * InverseSparseDiscreteBoundaryOperator(mass - 1. / (dk**2) * stiff) * (c0 * mass + term * mass)) return result
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: from bempp.api.operators.boundary.sparse import identity from bempp.api.assembly import InverseSparseDiscreteBoundaryOperator self._range_map = InverseSparseDiscreteBoundaryOperator( \ identity(self.range, self.range, self.dual_to_range).weak_form()) return self._range_map * self.weak_form(recompute)
def direct(dirichl_space, neumann_space, ep_in, ep_out, kappa, operator_assembler, permute_rows=False): identity = sparse.identity(dirichl_space, dirichl_space, dirichl_space) slp_in = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) slp_out = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) dlp_out = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) A = bempp.api.BlockedOperator(2, 2) if permute_rows: #Use permuted rows formulation A[0, 0] = 0.5 * identity - dlp_out A[0, 1] = (ep_in / ep_out) * slp_out A[1, 0] = 0.5 * identity + dlp_in A[1, 1] = -slp_in else: #Normal direct formulation A[0, 0] = 0.5 * identity + dlp_in A[0, 1] = -slp_in A[1, 0] = 0.5 * identity - dlp_out A[1, 1] = (ep_in / ep_out) * slp_out return A
def test_dolfin_p1_identity_equals_bempp_p1_identity(self): import dolfin from bempp.api.fenics_interface import fenics_to_bempp_trace_data from bempp.api.fenics_interface import FenicsOperator mesh = dolfin.UnitCubeMesh(5, 5, 5) V = dolfin.FunctionSpace(mesh, "CG", 1) space, trace_matrix = fenics_to_bempp_trace_data(V) u = dolfin.TestFunction(V) v = dolfin.TrialFunction(V) a = dolfin.inner(u, v) * dolfin.ds fenics_mass = FenicsOperator(a).weak_form().sparse_operator actual = trace_matrix * fenics_mass * trace_matrix.transpose() from bempp.api.operators.boundary import sparse expected = sparse.identity(space, space, space).weak_form().sparse_operator diff = actual - expected self.assertAlmostEqual(np.max(np.abs(diff.data)), 0)