def p1_trace(fenics_space): """ Return the P1 trace operator. This function returns a pair (space, trace_matrix), where space is a BEM++ space object and trace_matrix is the corresponding matrix that maps the coefficients of a FEniCS function to its boundary trace coefficients in the corresponding BEM++ space. """ import dolfin #pylint: disable=import-error from bempp.api.fenics_interface.coupling import fenics_space_info from bempp.api import function_space, grid_from_element_data import numpy as np family, degree = fenics_space_info(fenics_space) if not (family == 'Lagrange' and degree == 1): raise ValueError("fenics_space must be a p1 Lagrange space") mesh = fenics_space.mesh() boundary_mesh = dolfin.BoundaryMesh(mesh, "exterior", False) bm_nodes = boundary_mesh.entity_map(0).array().astype(np.int64) bm_coords = boundary_mesh.coordinates() bm_cells = boundary_mesh.cells() bempp_boundary_grid = grid_from_element_data(bm_coords.transpose(), bm_cells.transpose()) # First get trace space space = function_space(bempp_boundary_grid, "P", 1) # Now compute the mapping from FEniCS dofs to BEM++ dofs. # First the BEM++ dofs from the boundary vertices from scipy.sparse import coo_matrix bempp_dofs_from_b_vertices = p1_dof_to_vertex_matrix(space).transpose() # Now FEniCS vertices to boundary dofs b_vertices_from_vertices = coo_matrix( (np.ones(len(bm_nodes)), (np.arange(len(bm_nodes)), bm_nodes)), shape=(len(bm_nodes), mesh.num_vertices()), dtype='float64').tocsc() # Finally FEniCS dofs to vertices. vertices_from_fenics_dofs = coo_matrix( (np.ones(mesh.num_vertices()), (dolfin.dof_to_vertex_map(fenics_space), np.arange(mesh.num_vertices()))), shape=(mesh.num_vertices(), mesh.num_vertices()), dtype='float64').tocsc() # Get trace matrix by multiplication trace_matrix = bempp_dofs_from_b_vertices * \ b_vertices_from_vertices * vertices_from_fenics_dofs # Now return everything return space, trace_matrix
def perturbate(grid, t, kappa_pert=None): P1 = bem.function_space(grid, 'P', 1) grid_funz = bem.GridFunction(P1, fun=Phiz) elements = grid.leaf_view.elements vertices = grid.leaf_view.vertices normals = P1.global_dof_normals x, y, z = vertices vertices[2, :] = z + t * grid_funz.coefficients return bem.grid_from_element_data(vertices, elements)
def result_to_grid(res): ''' Return a BEM++ grid object made from the larf.model.Result ''' arrs = res.array_data_by_name() pts, tri, dom = arrs['vertices'],arrs['elements'],arrs['domains'] assert pts.shape[1] == 3 assert len(tri) == len(dom) pts, tri = make_unique(pts, tri) return bem.grid_from_element_data(pts.T,tri.T,dom)
def boundary_grid_from_fenics_mesh(fenics_mesh): """ Return a boundary grid from a FEniCS Mesh. """ from bempp.api import grid_from_element_data bm = _dolfin.BoundaryMesh(fenics_mesh, "exterior", False) bm_coords = bm.coordinates() bm_cells = bm.cells() bempp_boundary_grid = grid_from_element_data(bm_coords.transpose(),bm_cells.transpose()) return bempp_boundary_grid
def boundary_grid_from_fenics_mesh(fenics_mesh): """ Return a boundary grid from a FEniCS Mesh. """ from bempp.api import grid_from_element_data boundary_mesh = _dolfin.BoundaryMesh(fenics_mesh, "exterior", False) bm_coords = boundary_mesh.coordinates() bm_cells = boundary_mesh.cells() bempp_boundary_grid = grid_from_element_data(bm_coords.transpose(), bm_cells.transpose()) return bempp_boundary_grid
def generic_pn_trace(fenics_space): import dolfin from .coupling import fenics_space_info from bempp.api import function_space, grid_from_element_data, GridFunction from bempp.api.common import global_parameters import numpy as np family,degree = fenics_space_info(fenics_space) if not (family=='Lagrange'): raise ValueError("fenics_space different from Lagrange space not yet tested!") mesh = fenics_space.mesh() bm = dolfin.BoundaryMesh(mesh, "exterior", False) bm_nodes = bm.entity_map(0).array().astype(np.int64) bm_coords = bm.coordinates() bm_cells = bm.cells() bempp_boundary_grid = grid_from_element_data(bm_coords.transpose(), bm_cells.transpose()) # Create compatible trace function space space = function_space(bempp_boundary_grid, "P", degree) # Now compute the mapping from BEM++ dofs to FEniCS dofs from scipy.sparse import coo_matrix parameters = global_parameters() parameters.quadrature.far.single_order = 5 # TODO: use interplolation order accoriding to target space order def FenicsData(x, n, domain_index, result): value = np.empty(1) u_FEM.eval(value, x) result[0] = value u_FEM = dolfin.Function(fenics_space) N = u_FEM.vector().size() u_FEM.vector()[:] = np.arange(N) u_BEM = GridFunction(space, dual_space=space, fun=FenicsData, parameters=parameters) FEM2BEM = np.rint(u_BEM.coefficients).astype(np.int64) if max(abs(FEM2BEM-u_BEM.coefficients)) > 0.1: raise ValueError("interpolation from FEM to BEM space too inaccurate.") NB = len(FEM2BEM) trace_matrix = coo_matrix(( np.ones(NB),(np.arange(NB),FEM2BEM)), shape=(NB,N),dtype='float64').tocsc() # Now return everything return space, trace_matrix
def grid(self): "Return a BEM++ grid object for the scene." points = list() domains = list() triangles = list() point_offset = 0 for domain, mobjs in sorted(self.objects.items()): for mobj in mobjs: for p in mobj.points: points.append(p) for tri in mobj.triangle: triangles.append(point_offset + tri) domains.append(domain) point_offset += len(mobj.points) points, triangles = make_unique(numpy.asarray(points), numpy.asarray(triangles)) return bem.grid_from_element_data(points.T,triangles.T,domains)
def p1_trace(fenics_space): import dolfin from .coupling import fenics_space_info from bempp.api import function_space, grid_from_element_data import numpy as np family, degree = fenics_space_info(fenics_space) if not (family == 'Lagrange' and degree == 1): raise ValueError("fenics_space must be a p1 Lagrange space") mesh = fenics_space.mesh() bm = dolfin.BoundaryMesh(mesh, "exterior", False) bm_nodes = bm.entity_map(0).array().astype(np.int64) bm_coords = bm.coordinates() bm_cells = bm.cells() bempp_boundary_grid = grid_from_element_data(bm_coords.transpose(), bm_cells.transpose()) # First get trace space space = function_space(bempp_boundary_grid, "P", 1) # Now compute the mapping from BEM++ dofs to FEniCS dofs # First the BEM++ dofs to the boundary vertices from scipy.sparse import coo_matrix vertex_indices = np.arange(space.global_dof_count) data = np.ones(space.global_dof_count) bempp_dofs_from_b_vertices = p1_dof_to_vertex_matrix(space).transpose() # Now the boundary vertices to all the vertices b_vertices_from_vertices = coo_matrix(( np.ones(len(bm_nodes)), (np.arange(len(bm_nodes)), bm_nodes)), shape=(len(bm_nodes), mesh.num_vertices()), dtype='float64').tocsc() # Finally the vertices to FEniCS dofs vertices_from_fenics_dofs = coo_matrix(( np.ones(mesh.num_vertices()), (dolfin.dof_to_vertex_map(fenics_space), np.arange(mesh.num_vertices()))), shape=(mesh.num_vertices(), mesh.num_vertices()), dtype='float64').tocsc() # Get trace matrix by multiplication trace_matrix = bempp_dofs_from_b_vertices * b_vertices_from_vertices * vertices_from_fenics_dofs # Now return everything return space, trace_matrix
def test_grid_from_element_data(self): """Test grid generation from element data.""" from bempp.api import grid_from_element_data grid = grid_from_element_data(VERTICES, ELEMENTS) box = grid.bounding_box self.assertTrue(np.all(box == np.array([[0, 0, 0], [1, 1, 0]]))) self.assertEqual(grid.leaf_view.entity_count(0), 2) self.assertEqual(grid.leaf_view.entity_count(2), 4) actual_vertices = grid.leaf_view.vertices actual_elements = grid.leaf_view.elements self.assertEqual(actual_vertices.shape[1], 4) self.assertEqual(actual_elements.shape[1], 2) for vert in VERTICES.T: self.assertIn(vert, actual_vertices.T)
def HCurl_trace(ng_space, boundaries=None): """ Return the lowest oder Nedelec trace operator. This function returns a pair (space, trace_matrix), where space is a BEM++ space object and trace_matrix is the corresponding matrix that maps the coefficients of a NGsolve function to its boundary trace coefficients in the corresponding BEM++ space. """ import ngsolve as ngs from ngbem import surface_mesh_from_ng if (ng_space.type != 'hcurlho' or ng_space.globalorder != 0): raise ValueError("ng_space must be a valid lowest order HCurl space") import ngsolve as ngs from bempp.api import function_space, grid_from_element_data, ALL import bempp.api import numpy as np mesh = ng_space.mesh [bm_coords, bm_cells, domain_indices, bm_nodes] = surface_mesh_from_ng(mesh) bempp_boundary_grid = grid_from_element_data(bm_coords, bm_cells, domain_indices) # First get trace space space = function_space(bempp_boundary_grid, "RT", 0) # Now compute the mapping from NGSolve dofs to BEM++ dofs. bem_elements = list(bempp_boundary_grid.leaf_view.entity_iterator(0)) n_bem = space.global_dof_count n_ng = ng_space.ndof k = 1 print("doing order ", k, "dofs=", space.global_dof_count) nd = 3 ##number of degrees of freedom on the reference element from math import sqrt #setup the lagrange interpolation points for the BEM++ local basis eval_pts = np.asarray([[0.5, 0], [0, 0.5], [0.5, 0.5]]).T local_normals = np.asarray([[0, -1], [-1, 0], [1, 1]]) local_tangentials = np.asarray([[-1, 1], [1, 0], [0, -1]]) #the tangential vectors used by ngsolve ##local_tangentials=np.asarray([[-1,1],[1,0],[0,-1]]); #the tangential vectors used by ngsolve local_bem_to_ng = np.zeros([nd, nd]) #NGSolve and BEM++ use a different reference element. #The map TA x + b does this transformatuib TA = np.asarray([[-1, -1], [1, 0]]) Tb = np.asarray([1, 0]) todo = np.ones([n_bem]) #stores which indices we already visited iis = np.zeros([nd * n_bem], dtype=np.int64) ijs = np.zeros([nd * n_bem], dtype=np.int64) data = np.zeros([nd * n_bem]) elId = 0 idCnt = 0 #on each element, we map from ngsolve to the reference element, #do the local transformation there and then transform back to the global BEM++ dofs for el in ng_space.Elements(ngs.BND): bem_el = bem_elements[elId] ng_dofs = el.dofs bem_global_dofs, bem_weights = space.get_global_dofs(bem_el, dof_weights=True) ngshape = ng_space.GetFE(ngs.ElementId(el)) #evaluate the NGSolve basis in the midpoint of edges times the tangential vectors # this corresponds to the functionals assigned to the Nedelec basis functions, # and most notably gives how the local DOFs are assigned to the edges (including the weights) # local_bem_to_ng should be a permutation matrix up to signs for j in range(0, nd): tx = TA.dot(eval_pts[:, j]) + Tb # transfer to NGSolves reference element tangential = local_tangentials[j] #the tangentials are already stored transformed uj = ngshape.CalcShape(tx[0], tx[1], 0) for l in range(0, nd): local_bem_to_ng[l, j] = np.dot(uj[l, :], tangential) local_ndofs = len(ng_dofs) assert (nd == local_ndofs) bem_global_dofs, bem_weights = space.get_global_dofs(bem_el, dof_weights=True) assert (len(bem_global_dofs) == len(ng_dofs)) for i in range(0, local_ndofs): gbid = bem_global_dofs[i] if (todo[gbid] == 1): ##we havent dealt with this index before for j in range(0, local_ndofs): gngid = ng_dofs[j] iis[idCnt] = gbid ijs[idCnt] = gngid data[idCnt] = bem_weights[i] * local_bem_to_ng[j, i] idCnt += 1 todo[gbid] -= 1 elId += 1 assert (np.count_nonzero(todo) == 0) assert (idCnt == nd * n_bem) # build up the sparse matrix containing our transformation from scipy.sparse import coo_matrix trace_matrix = coo_matrix((data, (iis, ijs)), shape=(space.global_dof_count, ng_space.ndof)) # Now return everything return space, trace_matrix
def p1_trace(ng_space): """ Return the P1 trace operator. This function returns a pair (space, trace_matrix), where space is a BEM++ space object and trace_matrix is the corresponding matrix that maps the coefficients of a NGsolve function to its boundary trace coefficients in the corresponding BEM++ space. """ import ngsolve as ngs if (ng_space.globalorder != 1): raise ValueError("ng_space must be a p1 H1 space") import ngsolve as ngs from bempp.api import function_space, grid_from_element_data import numpy as np mesh = ng_space.mesh [bm_coords, bm_cells, domain_indices, bm_nodes] = surface_mesh_from_ng(mesh) [bm_coords, bm_cells, domain_indices, bm_nodes] = surface_mesh_from_ng(mesh) bempp_boundary_grid = grid_from_element_data(bm_coords, bm_cells, domain_indices) # First get trace space space = function_space(bempp_boundary_grid, "P", 1) # Now compute the mapping from NGSolve dofs to BEM++ dofs. # First the BEM++ dofs from the boundary vertices from scipy.sparse import coo_matrix bempp_dofs_from_b_vertices = p1_dof_to_vertex_matrix(space).transpose() nsv = len(bm_nodes) # Now NGSolve vertices to boundary dofs b_vertices_from_vertices = coo_matrix( (np.ones(nsv), (np.arange(nsv), bm_nodes)), shape=(len(bm_nodes), mesh.nv), dtype='float64').tocsc() # Finally NGSolve dofs to vertices. dofmap = np.zeros([ng_space.ndof], dtype='int64') for el in ng_space.Elements(ngs.BND): dofs = el.dofs vs = el.vertices dofmap[dofs] = [vs[j].nr for j in range(0, len(vs))] vertices_from_ngs_dofs = coo_matrix( (np.ones(mesh.nv), (dofmap, np.arange(mesh.nv))), shape=(mesh.nv, mesh.nv), dtype='float64').tocsc() # Get trace matrix by multiplication trace_matrix = bempp_dofs_from_b_vertices * \ b_vertices_from_vertices * vertices_from_ngs_dofs # Now return everything return space, trace_matrix
def bempp_grid_from_data_set(grid_data_set): """Convert a grid data set to Bempp grid.""" from bempp.api import grid_from_element_data return grid_from_element_data(grid_data_set.grid.vertices, grid_data_set.grid.elements, grid_data_set.grid.domain_indices)