def test_laplace_single_layer(): """Test dense assembler for the Laplace operators.""" grid = bempp.api.shapes.regular_sphere(2) space = function_space(grid, "DP", 0) op1 = laplace.single_layer(space, space, space, assembler="dense") op2 = laplace.single_layer(space, space, space, assembler="fmm") fun = bempp.api.GridFunction( space, coefficients=np.random.rand(space.global_dof_count) ) assert np.allclose((op1 * fun).coefficients, (op2 * fun).coefficients) bempp.api.clear_fmm_cache()
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 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 _compute_near_field_matrix(self): """Compute the near-field matrix.""" import bempp.api from bempp.api.operators.boundary.laplace import single_layer from bempp.core.near_field_assembler import NearFieldAssembler from scipy.sparse.linalg import aslinearoperator with bempp.api.Timer() as t: near_field_op = NearFieldAssembler( self, bempp.api.default_device(), bempp.api.DEVICE_PRECISION_CPU ).as_linear_operator() bempp.api.log(f"Near field setup time: {t.interval}") singular_interactions = single_layer( self._domain, self._domain, self._dual_to_range, assembler="only_singular_part", ).weak_form() source_op = self._source_transform target_op = self._target_transform self._near_field_matrix = ( target_op @ near_field_op @ source_op + singular_interactions )
def test_laplace_single_layer_p0_p1(default_parameters, helpers, precision, device_interface): """Test dense assembler for the slp with disc. p0/p1 basis.""" from bempp.api.operators.boundary.laplace import single_layer from bempp.api import function_space grid = helpers.load_grid("sphere") space0 = function_space(grid, "DP", 0) space1 = function_space(grid, "DP", 1) discrete_op = single_layer( space1, space1, space0, assembler="dense", precision=precision, device_interface=device_interface, parameters=default_parameters, ).weak_form() expected = helpers.load_npy_data("laplace_single_layer_boundary_p0_dp1") _np.testing.assert_allclose(discrete_op.A, expected, rtol=helpers.default_tolerance(precision))
def laplace_multitrace_scaled(dirichl_space, neumann_space, scaling_factors, operator_assembler): A = bempp.api.BlockedOperator(2, 2) A[0, 0] = scaling_factors[0][0] * (-1.0) * laplace.double_layer( dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) A[0, 1] = scaling_factors[0][1] * laplace.single_layer( neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) A[1, 0] = scaling_factors[1][0] * laplace.hypersingular( dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) A[1, 1] = scaling_factors[1][1] * laplace.adjoint_double_layer( neumann_space, neumann_space, neumann_space, assembler=operator_assembler) return A
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 laplace_slp_small_sphere(small_piecewise_const_space, default_parameters): """The Laplace single layer operator on a small sphere.""" from bempp.api.operators.boundary.laplace import single_layer return single_layer( small_piecewise_const_space, small_piecewise_const_space, small_piecewise_const_space, )
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 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 test_laplace_single_layer(has_exafmm): """Test dense assembler for the Laplace operators.""" if not has_exafmm and not check_for_fmm(): pytest.skip("ExaFMM must be installed to run this test.") grid = bempp.api.shapes.regular_sphere(2) space = function_space(grid, "DP", 0) op1 = laplace.single_layer(space, space, space, assembler="dense") op2 = laplace.single_layer(space, space, space, assembler="fmm") fun = bempp.api.GridFunction(space, coefficients=np.random.rand( space.global_dof_count)) assert np.allclose((op1 * fun).coefficients, (op2 * fun).coefficients) bempp.api.clear_fmm_cache()
def test_laplace_single_layer_evaluator_complex(default_parameters, helpers, precision, device_interface): """Test dense evaluator with complex vector.""" from bempp.api import function_space from bempp.api.operators.boundary.laplace import single_layer grid = helpers.load_grid("sphere") space1 = function_space(grid, "DP", 0) space2 = function_space(grid, "DP", 0) discrete_op = single_layer( space1, space1, space2, assembler="dense_evaluator", parameters=default_parameters, device_interface=device_interface, precision=precision, ).weak_form() mat = single_layer( space1, space1, space2, assembler="dense", parameters=default_parameters, device_interface=device_interface, precision=precision, ).weak_form() x = _np.random.RandomState(0).rand( space1.global_dof_count) + 1j * _np.random.RandomState(0).rand( space1.global_dof_count) actual = discrete_op @ x expected = mat @ x if precision == "single": tol = 2e-4 else: tol = 1e-12 _np.testing.assert_allclose(actual, expected, rtol=tol)
def laplaceMultitrace(dirichl_space, neumann_space): from bempp.api.operators.boundary import laplace A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (-1.0)*laplace.double_layer(dirichl_space, dirichl_space, dirichl_space) A[0, 1] = laplace.single_layer(neumann_space, dirichl_space, dirichl_space) A[1, 0] = laplace.hypersingular(dirichl_space, neumann_space, neumann_space) A[1, 1] = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space) 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 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 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 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 laplace_single_layer_dense_large_benchmark(benchmark, default_parameters): """Benchmark for Laplace assembly on a larger sphere""" from bempp.api.operators.boundary.laplace import single_layer from bempp.api import function_space grid = bempp.api.shapes.regular_sphere(5) space = function_space(grid, "DP", 0) fun = lambda: single_layer( space, space, space, assembler="dense", parameters=default_parameters ).weak_form() benchmark(fun)
def test_slp_hyp_pair_on_dual_grids(self): """SLP and HYP Pair on dual grids.""" 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.laplace import \ single_layer_and_hypersingular_pair, single_layer, hypersingular actual_ops_dual = single_layer_and_hypersingular_pair( self._grid, spaces='dual', stabilization_factor=0, parameters=parameters) dual_space = bempp.api.function_space(self._grid, "DUAL", 0) expected_slp = bempp.api.as_matrix( single_layer(dual_space, dual_space, dual_space, 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, 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, 4)
def laplace_multitrace(dirichl_space, neumann_space, operator_assembler): A = bempp.api.BlockedOperator(2, 2) A[0, 0] = (-1.0) * laplace.double_layer(dirichl_space, dirichl_space, dirichl_space, assembler=operator_assembler) A[0, 1] = laplace.single_layer(neumann_space, dirichl_space, dirichl_space, assembler=operator_assembler) A[1, 0] = laplace.hypersingular(dirichl_space, neumann_space, neumann_space, assembler=operator_assembler) A[1, 1] = laplace.adjoint_double_layer(neumann_space, neumann_space, neumann_space, assembler=operator_assembler) return A
def helmholtz_single_layer_dense_p1_cont_large_benchmark( benchmark, default_parameters): """Helmholtz benchmark with P1 functions on large grid.""" from bempp.api.operators.boundary.helmholtz import single_layer from bempp.api import function_space grid = bempp.api.shapes.regular_sphere(5) space = function_space(grid, "P", 1) wavenumber = 2.5 fun = lambda: single_layer( space, space, space, wavenumber, assembler="dense", parameters=default_parameters, ).weak_form() benchmark(fun)
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 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 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 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
def stern_formulation(dirichl_space_in, neumann_space_in, dirichl_space_ex, neumann_space_ex, ep_in, ep_ex, q, x_q, kappa): # Functions to proyect the carges potential to the boundary with constants def green_func(x, n, domain_index, result): result[:] = np.sum( q / np.linalg.norm(x - x_q, axis=1)) / (4. * np.pi * ep_in) print "\nProjecting charges over surface..." charged_grid_fun = bempp.api.GridFunction(dirichl_space_in, fun=green_func) rhs = np.concatenate([ charged_grid_fun.coefficients, np.zeros(neumann_space_in.global_dof_count), np.zeros(dirichl_space_ex.global_dof_count), np.zeros(neumann_space_ex.global_dof_count) ]) print "Defining operators..." # OPERATOR FOR INTERNAL SURFACE from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz idn_in = sparse.identity(dirichl_space_in, dirichl_space_in, dirichl_space_in) # Ec 1 slp_in = laplace.single_layer(neumann_space_in, dirichl_space_in, dirichl_space_in) dlp_in = laplace.double_layer(dirichl_space_in, dirichl_space_in, dirichl_space_in) # Ec 2 # adj_1T1 = laplace.single_layer(neumann_space_in, dirichl_space_in, dirichl_space_in) # adj_1T1 = laplace.double_layer(dirichl_space_in, dirichl_space_in, dirichl_space_in) slp_2T1 = laplace.single_layer(neumann_space_ex, dirichl_space_in, dirichl_space_in) dlp_2T1 = laplace.double_layer(dirichl_space_ex, dirichl_space_in, dirichl_space_in) # OPERATOR FOR EXTERNAL SURFACE idn_ex = sparse.identity(dirichl_space_ex, dirichl_space_ex, dirichl_space_ex) # Internal Boudary slp_1T2 = laplace.single_layer(neumann_space_in, dirichl_space_ex, dirichl_space_ex) # dlp_1T2 = laplace.double_layer(dirichl_space_in, dirichl_space_ex, dirichl_space_ex) slp_2T2 = laplace.single_layer(neumann_space_ex, dirichl_space_ex, dirichl_space_ex) dlp_2T2 = laplace.double_layer(dirichl_space_ex, dirichl_space_ex, dirichl_space_ex) # External Boundary slp_ex = modified_helmholtz.single_layer(neumann_space_ex, dirichl_space_ex, dirichl_space_ex, kappa) dlp_ex = modified_helmholtz.double_layer(dirichl_space_ex, dirichl_space_ex, dirichl_space_ex, kappa) ep = (ep_in / ep_ex) print "Creating operators..." # Matrix Assemble blocked = bempp.api.BlockedOperator(4, 4) blocked[0, 0] = .5 * idn_in + dlp_in blocked[0, 1] = -slp_in # blocked[0, 2] = 0 # blocked[0, 3] = 0 # Original formulation blocked[1, 0] = .5 * idn_in - dlp_in # dlp_in = dlp_1T1 blocked[1, 1] = ep * slp_in # slp_in = slp_1T1 blocked[1, 2] = dlp_2T1 blocked[1, 3] = -slp_2T1 # blocked[2, 0] = -dlp_1T2 ## eliminar** blocked[2, 1] = ep * slp_1T2 blocked[2, 2] = .5 * idn_ex + dlp_2T2 blocked[2, 3] = -slp_2T2 # blocked[3, 0] = 0 # blocked[3, 1] = 0 blocked[3, 2] = .5 * idn_ex - dlp_ex blocked[3, 3] = slp_ex A = blocked.strong_form() return A, rhs
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
# Para nuestro caso utilizaremos DP-0, es decir, valores constantes por elemento dirichl_space = bempp.api.function_space(grid, "DP", 0) neumann_space = bempp.api.function_space(grid, "DP", 0) dual_to_dir_s = bempp.api.function_space(grid, "DP", 0) # Se crea u_s y su derivada normal du_s en la frontera u_s = bempp.api.GridFunction(dirichl_space, fun=u_s_G) du_s = bempp.api.GridFunction(neumann_space, fun=du_s_G) # Se crean los operadores asociados al sistema, que dependen de los espacios de las soluciones # identity : I : matriz identidad # dlp_in : K_in : Double-Layer operator para la region interior # slp_in : V_in : Single-Layer operator para la region interior # _out : Mismos operadores pero para la región exterior, con k=kappa=0.125 identity = sparse.identity( dirichl_space, dirichl_space, dual_to_dir_s) slp_in = laplace.single_layer(neumann_space, dirichl_space, dual_to_dir_s) dlp_in = laplace.double_layer(dirichl_space, dirichl_space, dual_to_dir_s) slp_out = modified_helmholtz.single_layer(neumann_space, dirichl_space, dual_to_dir_s, k) dlp_out = modified_helmholtz.double_layer(dirichl_space, dirichl_space, dual_to_dir_s, k) # 4.1 Solución armónica --------------------------------------------------------------- # Dada por V_in du_s = (1/2+K_in)u_h = -(1/2+K_in)u_s (BC) sol, info,it_count = bempp.api.linalg.gmres( slp_in, -(dlp_in+0.5*identity)*u_s , return_iteration_count=True, tol=1e-4) print("The linear system for du_h was solved in {0} iterations".format(it_count)) u_h = -u_s du_h = sol
def stern_asc(neumann_space_in, dirichl_space_ex, neumann_space_ex, ep_in, ep_ex, q, x_q, kappa): # Functions to proyect the carges potential to the boundary with constants def d_green_func(x, n, domain_index, result): const = -1. / (4. * np.pi * ep_in) result[:] = const * np.sum(q * np.dot(x - x_q, n) / (np.linalg.norm(x - x_q, axis=1)**3)) print "\nProjecting charges over surface..." charged_grid_fun = bempp.api.GridFunction(neumann_space_in, fun=d_green_func) rhs = np.concatenate([ charged_grid_fun.coefficients, np.zeros(dirichl_space_ex.global_dof_count), np.zeros(neumann_space_ex.global_dof_count) ]) print "Defining operators..." # OPERATORS FOR INTERNAL SURFACE from bempp.api.operators.boundary import sparse, laplace, modified_helmholtz idn_in = sparse.identity(neumann_space_in, neumann_space_in, neumann_space_in) adj_1T1 = laplace.adjoint_double_layer(neumann_space_in, neumann_space_in, neumann_space_in) hyp_2T1 = laplace.hypersingular(dirichl_space_ex, neumann_space_in, neumann_space_in) adj_2T1 = laplace.adjoint_double_layer(neumann_space_ex, neumann_space_in, neumann_space_in) # OPERATORS FOR EXTERNAL SURFACE idn_ex = sparse.identity(dirichl_space_ex, dirichl_space_ex, dirichl_space_ex) slp_1T2 = laplace.single_layer(neumann_space_in, dirichl_space_ex, dirichl_space_ex) dlp_2T2 = laplace.double_layer(dirichl_space_ex, dirichl_space_ex, dirichl_space_ex) slp_2T2 = laplace.single_layer(neumann_space_ex, dirichl_space_ex, dirichl_space_ex) dlp_ex = modified_helmholtz.double_layer(dirichl_space_ex, dirichl_space_ex, dirichl_space_ex, kappa) slp_ex = modified_helmholtz.single_layer(neumann_space_ex, dirichl_space_ex, dirichl_space_ex, kappa) ep = (ep_in / ep_ex) print "Creating operators..." # Matrix Assemble blocked = bempp.api.BlockedOperator(3, 3) blocked[0, 0] = idn_in + (ep - 1.) * adj_1T1 blocked[0, 1] = -hyp_2T1 blocked[0, 2] = -adj_2T1 blocked[1, 0] = ep * slp_1T2 blocked[1, 1] = .5 * idn_ex + dlp_2T2 blocked[1, 2] = -slp_2T2 #blocked[2, 0] = 0 blocked[2, 1] = .5 * idn_ex - dlp_ex blocked[2, 2] = slp_ex A = blocked.weak_form() return A, rhs