def test_modified_helmholtz_hypersingular( default_parameters, helpers, precision, device_interface ): """Test dense assembler for the modified Helmholtz hypersingular operator.""" from bempp.api import function_space from bempp.api.operators.boundary.modified_helmholtz import hypersingular grid = helpers.load_grid("sphere") space = function_space(grid, "P", 1) discrete_op = hypersingular( space, space, space, OMEGA, assembler="dense", precision=precision, device_interface=device_interface, parameters=default_parameters, ).weak_form() expected = _np.real( helpers.load_npy_data("modified_helmholtz_hypersingular_boundary") ) _np.testing.assert_allclose( discrete_op.A, expected, rtol=helpers.default_tolerance(precision) )
def test_hypersingular_fails_for_wrong_space(type0, type1): """Expected failure for wrong spaces.""" grid = bempp.api.shapes.regular_sphere(0) space0 = function_space(grid, *type0) space1 = function_space(grid, *type1) with pytest.raises(ValueError): laplace.hypersingular(space0, space1, space1, assembler="dense").weak_form() with pytest.raises(ValueError): helmholtz.hypersingular( space0, space1, space1, 1.5, assembler="dense" ).weak_form() with pytest.raises(ValueError): modified_helmholtz.hypersingular( space0, space1, space1, 1.5, assembler="dense" ).weak_form()
def mod_helm_multitrace_scaled(dirichl_space, neumann_space, kappa, scaling_factors, operator_assembler): A = bempp.api.BlockedOperator(2, 2) A[0, 0] = scaling_factors[0][0] * (-1.0) * modified_helmholtz.double_layer( dirichl_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) A[0, 1] = scaling_factors[0][1] * modified_helmholtz.single_layer( neumann_space, dirichl_space, dirichl_space, kappa, assembler=operator_assembler) A[1, 0] = scaling_factors[1][0] * modified_helmholtz.hypersingular( dirichl_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) A[1, 1] = scaling_factors[1][1] * modified_helmholtz.adjoint_double_layer( neumann_space, neumann_space, neumann_space, kappa, assembler=operator_assembler) return A
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 test_multitrace_hypersingular_agrees_with_standard_hypersingular_lin( self): """Multitrace hyp agrees with standard hyp on linear spaces.""" parameters = bempp.api.common.global_parameters() parameters.assembly.boundary_operator_assembly_type = 'dense' from bempp.api.operators.boundary.modified_helmholtz import \ multitrace_operator, hypersingular multitrace = multitrace_operator( self._grid, WAVE_NUMBER, parameters=parameters) actual = multitrace[1, 0] expected = hypersingular( self._lin_space, self._lin_space, self._lin_space, WAVE_NUMBER, parameters=parameters) mat_expected = bempp.api.as_matrix(expected.weak_form()) mat_actual = bempp.api.as_matrix(actual.weak_form()) diff_norm = np.linalg.norm( mat_expected - mat_actual) / np.linalg.norm(mat_actual) self.assertAlmostEqual(diff_norm, 0, 3)
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 test_compound_hypersingular_agrees_with_standard_hypersingular_operator_lin(self): from bempp.api.operators.boundary.modified_helmholtz import hypersingular import numpy as np parameters = bempp.api.common.global_parameters() parameters.assembly.boundary_operator_assembly_type = 'dense' standard_hypersingular = hypersingular(self._lin_space, self._lin_space, self._lin_space, WAVE_NUMBER, parameters=parameters).weak_form() compound_hypersingular = hypersingular(self._lin_space, self._lin_space, self._lin_space, WAVE_NUMBER, parameters=parameters, use_slp=True).weak_form() mat1 = bempp.api.as_matrix(standard_hypersingular) mat2 = bempp.api.as_matrix(compound_hypersingular) self.assertAlmostEqual(np.linalg.norm(mat1 - mat2) / np.linalg.norm(mat1), 0)
def test_modified_helmholtz_hypersingular_evaluator(default_parameters, helpers, precision, device_interface): """Test dense evaluator for modified Helmholtz hypersingular.""" from bempp.api import function_space from bempp.api.operators.boundary.modified_helmholtz import hypersingular grid = helpers.load_grid("sphere") space = function_space(grid, "P", 1) discrete_op = hypersingular( space, space, space, OMEGA, assembler="dense_evaluator", precision=precision, device_interface=device_interface, parameters=default_parameters, ).weak_form() mat = hypersingular( space, space, space, OMEGA, assembler="dense", precision=precision, device_interface=device_interface, parameters=default_parameters, ).weak_form() x = _np.random.RandomState(0).randn(space.global_dof_count) actual = discrete_op @ x expected = mat @ x if precision == "single": tol = 1e-4 else: tol = 1e-12 _np.testing.assert_allclose(actual, expected, rtol=tol)
def modHelmMultitrace(dirichl_space, neumann_space, kappa): from bempp.api.operators.boundary import modified_helmholtz A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (-1.0)*modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa) A[0, 1] = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa) A[1, 0] = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa) A[1, 1] = modified_helmholtz.adjoint_double_layer(neumann_space, neumann_space, neumann_space, kappa) return A
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 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 test_compound_hyp_agrees_with_standard_hyp_lin(self): """Compount HYP agrees with standard HYP for linear spaces.""" from bempp.api.operators.boundary.modified_helmholtz import \ hypersingular parameters = bempp.api.common.global_parameters() parameters.assembly.boundary_operator_assembly_type = 'dense' standard_hypersingular = hypersingular( self._lin_space, self._lin_space, self._lin_space, WAVE_NUMBER, parameters=parameters, use_slp=False).weak_form() compound_hypersingular = hypersingular( self._lin_space, self._lin_space, self._lin_space, WAVE_NUMBER, parameters=parameters, use_slp=True).weak_form() mat1 = bempp.api.as_matrix(standard_hypersingular) mat2 = bempp.api.as_matrix(compound_hypersingular) self.assertAlmostEqual(np.linalg.norm( mat1 - mat2) / np.linalg.norm(mat1), 0)
def test_slp_hyp_pair_linear_space(self): """SLP and HYP pair on linear spaces.""" lin_space = self._lin_space parameters = bempp.api.common.global_parameters() parameters.assembly.boundary_operator_assembly_type = 'dense' parameters.quadrature.double_singular = 9 parameters.quadrature.near.double_order = 9 parameters.quadrature.medium.double_order = 9 parameters.quadrature.far.double_order = 9 from bempp.api.operators.boundary.modified_helmholtz import \ single_layer_and_hypersingular_pair, single_layer, hypersingular actual_ops_dual = single_layer_and_hypersingular_pair( self._grid, WAVE_NUMBER, spaces='linear', parameters=parameters) expected_slp = bempp.api.as_matrix(single_layer( lin_space, lin_space, lin_space, WAVE_NUMBER, parameters=parameters).weak_form()) actual_slp = bempp.api.as_matrix(actual_ops_dual[0].weak_form()) expected_hyp = bempp.api.as_matrix(hypersingular( lin_space, lin_space, lin_space, WAVE_NUMBER, parameters=parameters).weak_form()) actual_hyp = bempp.api.as_matrix(actual_ops_dual[1].weak_form()) diff_norm_slp = np.linalg.norm( expected_slp - actual_slp) / np.linalg.norm(actual_slp) diff_norm_hyp = np.linalg.norm( expected_hyp - actual_hyp) / np.linalg.norm(actual_hyp) self.assertAlmostEqual(diff_norm_slp, 0, 6) self.assertAlmostEqual(diff_norm_hyp, 0, 6)
def block_diagonal_precon_juffer(dirichl_space, neumann_space, ep_in, ep_ex, kappa): from scipy.sparse import diags, bmat from scipy.sparse.linalg import factorized, LinearOperator from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz phi_id = sparse.identity(dirichl_space, dirichl_space, dirichl_space).weak_form().A.diagonal() dph_id = sparse.identity(neumann_space, neumann_space, neumann_space).weak_form().A.diagonal() ep = ep_ex / ep_in dF = laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler="only_diagonal_part").weak_form().A dP = modified_helmholtz.double_layer( dirichl_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().A L1 = (ep * dP) - dF F = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler="only_diagonal_part").weak_form().A P = modified_helmholtz.single_layer( neumann_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().A L2 = F - P ddF = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler="only_diagonal_part").weak_form().A ddP = modified_helmholtz.hypersingular( dirichl_space, neumann_space, neumann_space, kappa, assembler="only_diagonal_part").weak_form().A L3 = ddP - ddF dF0 = laplace.adjoint_double_layer( neumann_space, neumann_space, neumann_space, assembler="only_diagonal_part").weak_form().A dP0 = modified_helmholtz.adjoint_double_layer( neumann_space, neumann_space, neumann_space, kappa, assembler="only_diagonal_part").weak_form().A L4 = dF0 - ((1.0 / ep) * dP0) diag11 = diags((0.5 * (1.0 + ep) * phi_id) - L1) diag12 = diags((-1.0) * L2) diag21 = diags(L3) diag22 = diags((0.5 * (1.0 + (1.0 / ep)) * dph_id) - L4) block_mat_precond = bmat([[diag11, diag12], [diag21, diag22]]).tocsr() # csr_matrix solve = factorized( block_mat_precond ) # a callable for solving a sparse linear system (treat it as an inverse) precond = LinearOperator(matvec=solve, dtype='float64', shape=block_mat_precond.shape) return precond
def derivative_in(dirichl_space, neumann_space, assembler, q, x_q): """ Construct the system matrix and RHS grid functions using derivative formulation with interior values. """ ep_in = PARAMS.ep_in ep_ex = PARAMS.ep_ex kappa = PARAMS.kappa 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=assembler) dP = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dirichl_space, kappa, assembler=assembler) L1 = (ep * dP) - dF F = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=assembler) P = modified_helmholtz.single_layer(neumann_space, dirichl_space, dirichl_space, kappa, assembler=assembler) L2 = F - P ddF = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=assembler) ddP = modified_helmholtz.hypersingular(dirichl_space, neumann_space, neumann_space, kappa, assembler=assembler) L3 = ddP - ddF dF0 = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=assembler) dP0 = modified_helmholtz.adjoint_double_layer(neumann_space, neumann_space, neumann_space, kappa, assembler=assembler) L4 = dF0 - ((1.0 / ep) * dP0) A_sys = bempp.api.BlockedOperator(2, 2) A_sys[0, 0] = (0.5 * (1.0 + ep) * phi_id) - L1 A_sys[0, 1] = (-1.0) * L2 A_sys[1, 0] = L3 A_sys[1, 1] = (0.5 * (1.0 + (1.0 / ep)) * dph_id) - L4 @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.callable(vectorized=True) def rhs2_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[:] = np.sum(values[:, 1:] * n.T, axis=1) / ep_in rhs1 = bempp.api.GridFunction(dirichl_space, fun=rhs1_fun) rhs2 = bempp.api.GridFunction(neumann_space, fun=rhs2_fun) return A_sys, rhs1, rhs2
def first_kind_external(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) ep = ep_ex / ep_in A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (-1.0 * dlp_ex) - dlp_in A[0, 1] = slp_ex + (ep * slp_in) A[1, 0] = hlp_ex + ((1.0 / ep) * hlp_in) A[1, 1] = adlp_ex + adlp_in calderon_int_scal = bempp.api.BlockedOperator(2, 2) calderon_int_scal[0, 0] = -1.0 * dlp_in calderon_int_scal[0, 1] = ep * slp_in calderon_int_scal[1, 0] = (1.0 / ep) * hlp_in calderon_int_scal[1, 1] = adlp_in calderon_ext = bempp.api.BlockedOperator(2, 2) calderon_ext[0, 0] = -1.0 * dlp_ex calderon_ext[0, 1] = slp_ex calderon_ext[1, 0] = hlp_ex calderon_ext[1, 1] = adlp_ex return A, calderon_int_scal, calderon_ext
def block_diagonal_precon_alpha_beta(dirichl_space, neumann_space, ep_in, ep_ex, kappa, alpha, beta): from scipy.sparse import diags, bmat from scipy.sparse.linalg import factorized, LinearOperator from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz 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 hlp_in_diag = laplace.hypersingular( dirichl_space, neumann_space, neumann_space, assembler="only_diagonal_part").weak_form().A adlp_in_diag = laplace.adjoint_double_layer( neumann_space, neumann_space, neumann_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( dirichl_space, dirichl_space, dirichl_space, kappa, assembler="only_diagonal_part").weak_form().A hlp_out_diag = modified_helmholtz.hypersingular( dirichl_space, neumann_space, neumann_space, kappa, assembler="only_diagonal_part").weak_form().A adlp_out_diag = modified_helmholtz.adjoint_double_layer( neumann_space, neumann_space, neumann_space, kappa, assembler="only_diagonal_part").weak_form().A phi_identity_diag = sparse.identity( dirichl_space, dirichl_space, dirichl_space).weak_form().A.diagonal() dph_identity_diag = sparse.identity( neumann_space, neumann_space, neumann_space).weak_form().A.diagonal() ep = ep_ex / ep_in diag11 = diags((-0.5 * (1 + alpha)) * phi_identity_diag + (alpha * dlp_out_diag) - dlp_in_diag) diag12 = diags(slp_in_diag - ((alpha / ep) * slp_out_diag)) diag21 = diags(hlp_in_diag - (beta * hlp_out_diag)) diag22 = diags((-0.5 * (1 + (beta / ep))) * dph_identity_diag + adlp_in_diag - ((beta / ep) * adlp_out_diag)) block_mat_precond = bmat([[diag11, diag12], [diag21, diag22]]).tocsr() # csr_matrix solve = factorized( block_mat_precond ) # a callable for solving a sparse linear system (treat it as an inverse) precond = LinearOperator(matvec=solve, dtype='float64', shape=block_mat_precond.shape) return precond