def compute_vertex_periodicity(mesh, master, slave, to_master): '''Compute mapping from slave vertices to master vertices''' f = MeshFunction('size_t', mesh, 0, 0) # As a vertex function master.mark(f, 2) slave.mark(f, 3) master_vertices = [v.index() for v in SubsetIterator(f, 2)] slave_vertices = set(v.index() for v in SubsetIterator(f, 3)) assert len(master_vertices) == len(slave_vertices), (len(master_vertices), len(slave_vertices)) x = mesh.coordinates() error, mapping = 0., {} while slave_vertices: s = slave_vertices.pop() xs = x[s] mapped = to_master(xs) # Local to master_vertex_x master_vertex_x = x[master_vertices] dist = np.sqrt(np.sum((master_vertex_x - mapped)**2, axis=1)) mapped_index = np.argmin(dist) # Wrt to vertex numbering m = master_vertices[mapped_index] mapping[s] = m error = max(error, dist[mapped_index]) master_vertices.remove(m) assert not slave_vertices and not master_vertices return error, mapping
def compute_entity_periodicity(tdim, mesh, master, slave, to_master): ''' Compute mapping from slave tdim entities to master tdim entities INPUT: mesh = dolfin.Mesh master = dolfin.SubDomain instance (to mark master vertices) slave = dolfin.SubDomain instance (to mark slave vertices) to_mastar = x (a slave vertex coord) -> a master vertex coord OUTPUT: error = largest distance between master and slave vertex coordinates mapping = dict{slave tdim entity index -> master tdim entity index} ''' assert 0 <= tdim < mesh.topology().dim() error, vertex_mapping = compute_vertex_periodicity(mesh, master, slave, to_master) # Done for vertices if tdim == 0: return error, vertex_mapping # Other entities are established using their definition in terms # of vertex indices f = MeshFunction('size_t', mesh, tdim, 0) master.mark(f, 2) slave.mark(f, 3) master_entities = (e.index() for e in SubsetIterator(f, 2)) slave_entities = (e.index() for e in SubsetIterator(f, 3)) mesh.init(tdim, 0) e2v = mesh.topology()(tdim, 0) # Define in terms of vertices. Invert for look up master_vertices = {tuple(sorted(e2v(e))): e for e in master_entities} # For slave we define via mapped vertices slave_entities = { e: tuple(sorted(vertex_mapping[v] for v in e2v(e))) for e in slave_entities } assert len(master_vertices) == len(slave_entities) mapping = {} while slave_entities: s, vertices = slave_entities.popitem() # Look up the master entity m = master_vertices[vertices] mapping[s] = m master_vertices.pop(vertices) assert not slave_entities and not master_vertices return error, mapping
def load_data(mesh, mesh_f, dim, data): ''' Represent mesh_f over dim entities of mesh as collection of vertices. Can have mesh as mesh function or (h5_file, data_set) ''' try: h5_file, data_set = mesh_f mf = MeshFunction('size_t', mesh, dim, 0) h5_file.read(mf, data_set) except ValueError: mf = mesh_f data_set = '%d dim entites' % mf.dim() # Mapf for encoding entities as vertices mesh.init(dim, 0) e2v = mesh.topology()(dim, 0) tags = set(mf.array()) # Don't encode zero - we initialize to it if 0 in tags: tags.remove(0) info('%s evolves tags %r' % (data_set, tags)) for tag in tags: data[(dim, tag)] = np.array([e2v(e.index()) for e in SubsetIterator(mf, tag)], dtype='uintp') return data
def cell_chi(f, marker=1): ''' Let f be a facet function. Build a DG0 function which is such that cell connected to f == marker are 1 and are 0 otherwise. ''' assert f.mesh().topology().dim() == 2 assert f.dim() == 1 mesh = f.mesh() mesh.init(1, 2) f2c = mesh.topology()(1, 2) V = FunctionSpace(mesh, 'DG', 0) dm = V.dofmap() first, last = dm.ownership_range() n = last - first is_local = lambda i, f=first, l=last: f <= i + f < l chi = Function(V) values = chi.vector().get_local() for facet in SubsetIterator(f, marker): fi = facet.index() for c in f2c(fi): dofs = filter(is_local, dm.cell_dofs(c)) values[dofs] = 1. # Sync chi.vector().set_local(values) as_backend_type(chi.vector()).update_ghost_values() return chi
def compute_vertex_periodicity(mesh, master, slave, to_master): ''' Compute mapping from slave vertices to master vertices INPUT: mesh = dolfin.Mesh master = dolfin.SubDomain instance (to mark master vertices) slave = dolfin.SubDomain instance (to mark slave vertices) to_mastar = x (a slave vertex coord) -> a master vertex coord OUTPUT: error = largest distance between master and slave vertex coordinates mapping = dict{slave vertex index -> master vertex index} ''' f = MeshFunction('size_t', mesh, 0, 0) # As a vertex function master.mark(f, 2) slave.mark(f, 3) master_vertices = [v.index() for v in SubsetIterator(f, 2)] slave_vertices = set(v.index() for v in SubsetIterator(f, 3)) assert len(master_vertices) == len(slave_vertices), (len(master_vertices), len(slave_vertices)) x = mesh.coordinates() error, mapping = 0., {} while slave_vertices: s = slave_vertices.pop() xs = x[s] # Its coord mapped = to_master(xs) # Coord in master domain # Local to master_vertex_x master_vertex_x = x[master_vertices] # Perform search to find closest master vertex dist = np.sqrt(np.sum((master_vertex_x - mapped)**2, axis=1)) mapped_index = np.argmin(dist) # Wrt to vertex numbering m = master_vertices[mapped_index] mapping[s] = m # Do we have a match ? error = max(error, dist[mapped_index]) # Assume we do so no more match possible master_vertices.remove(m) assert not slave_vertices and not master_vertices return error, mapping
def DLT_trace_mat(V, TV, trace_mesh=None, tag_data=None): '''Inject dofs from facets to DLT''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # None means all if tag_data is None: try: marking_function = trace_mesh.marking_function tag_data = (marking_function, set(marking_function.array())) except AttributeError: tag_data = (MeshFunction('size_t', trace_mesh, trace_mesh.topology().dim(), 0), set( (0, ))) trace_mesh_subdomains, tags = tag_data # Init/extract the mapping # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V if TV.num_sub_spaces() == 0: Tdmaps = [TV.dofmap()] else: Tdmaps = [TV.sub(i).dofmap() for i in range(TV.num_sub_spaces())] if V.num_sub_spaces() == 0: dmap = V.dofmap() facet2dofs = [dmap.entity_dofs(mesh, fdim)] else: facet2dofs = [ V.sub(i).dofmap().entity_dofs(mesh, fdim) for i in range(V.num_sub_spaces()) ] assert len(Tdmaps) == len(facet2dofs) # Only look at tagged cells trace_cells = list( itertools.chain(*[ map(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ])) # Rows with petsc_serial_matrix(TV, V) as mat: for Tdmap, facet2dof in zip(Tdmaps, facet2dofs): for trace_cell in trace_cells: trace_dof, = Tdmap.cell_dofs(trace_cell) DLT_dof = facet2dof[mapping[trace_cell]] mat.setValues([trace_dof], [DLT_dof], [1.], PETSc.InsertMode.INSERT_VALUES) return mat
def compute_entity_periodicity(tdim, mesh, master, slave, to_master): '''Mapping from slave entities of tdim to master''' assert 0 <= tdim < mesh.topology().dim() _, vertex_mapping = compute_vertex_periodicity(mesh, master, slave, to_master) # Done for vertices if tdim == 0: return vertex_mapping f = MeshFunction('size_t', mesh, tdim, 0) master.mark(f, 2) slave.mark(f, 3) master_entities = (e.index() for e in SubsetIterator(f, 2)) slave_entities = (e.index() for e in SubsetIterator(f, 3)) mesh.init(tdim, 0) e2v = mesh.topology()(tdim, 0) # Define in terms of vertices. Invert for loopup master_vertices = {tuple(sorted(e2v(e))): e for e in master_entities} # For slave we define via mapped vertices slave_entities = { e: tuple(sorted(vertex_mapping[v] for v in e2v(e))) for e in slave_entities } assert len(master_vertices) == len(slave_entities) mapping = {} while slave_entities: s, vertices = slave_entities.popitem() m = master_vertices[vertices] mapping[s] = m master_vertices.pop(vertices) assert not slave_entities and not master_vertices return mapping
def analyse_connectivity(mesh, edge_f, subdomain): ''' Compute connectivity between vertices of mesh and its edges that are marked by edge function with value of subdomain. ''' # We are only interested in gdim == tdim meshes gdim = mesh.geometry().dim() tdim = mesh.topology().dim() assert gdim == tdim and tdim > 1 # And building 1d in gdim meshes try: edim = edge_f.dim() assert edim == 1 edges = SubsetIterator(edge_f, subdomain) except AttributeError: assert isinstance(edge_f, list) # Recreate edges from list mesh.init(1) edges = (Edge(mesh, index) for index in edge_f) # First compute connectivity edge <--> vertex for edge, vertex on edge_f mesh.init(1, 0) topology = mesh.topology() # Connect between all edge->c of mesh all_edge_vertex_c = topology(1, 0) # Connectivity edge->vertex on interval mesh # Edge function - extract marked # if isinstance(edge_f, MeshFunction): edge_vertex_c = dict( (edge.index(), set(all_edge_vertex_c(edge.index()))) for edge in edges) # Only marked are given in list # else: # edge_vertex_c = dict((edge, set(all_edge_vertex_c(edge))) # for edge in edge_f) assert len(edge_vertex_c), 'No edges with value %d' % subdomain # Connectivity vertex->edge on interval mesh vertex_edge_c = defaultdict(list) for edge, vertices in edge_vertex_c.iteritems(): for vertex in vertices: vertex_edge_c[vertex].append(edge) return edge_vertex_c, vertex_edge_c
def dof_chi(f, V, marker=1): ''' Let f be a an edge function. Build a function in V which is such that all dofs where f == marker are 1 and are 0 otherwise. ''' tdim = f.mesh().topology().dim() assert f.dim() == 1 assert V.mesh().id() == f.mesh().id() assert V.ufl_element().family() == 'Lagrange' mesh = V.mesh() mesh.init(1, tdim) mesh.init(tdim, 1) e2c = mesh.topology()(1, tdim) c2e = mesh.topology()(tdim, 1) dm = V.dofmap() first, last = dm.ownership_range() n = last - first is_local = lambda i, f=first, l=last: f <= i + f < l # Triangle has 3 facets/edges, tet has 6 edges nedges = mesh.ufl_cell().num_edges() edge_dofs = [dm.tabulate_entity_closure_dofs(1, i) for i in range(nedges)] chi = Function(V) values = chi.vector().get_local() for edge in SubsetIterator(f, marker): edgei = edge.index() c = e2c(edgei)[0] # Any cell dofs = dm.cell_dofs(c) local_edge = c2e(c).tolist().index(edgei) dofs = filter(is_local, dofs[edge_dofs[local_edge]]) values[dofs] = 1. # Sync chi.vector().set_local(values) as_backend_type(chi.vector()).update_ghost_values() return chi
def convert(msh_file, h5_file, save_mvc=False): '''Temporary version of convertin from msh to h5''' root, _ = os.path.splitext(msh_file) assert os.path.splitext(msh_file)[1] == '.msh' assert os.path.splitext(h5_file)[1] == '.h5' # Get the xml mesh xml_file = '.'.join([root, 'xml']) subprocess.call(['dolfin-convert %s %s' % (msh_file, xml_file)], shell=True) # Success? assert os.path.exists(xml_file) mesh = Mesh(xml_file) out = HDF5File(mesh.mpi_comm(), h5_file, 'w') out.write(mesh, 'mesh') print('Mesh has %d cells' % mesh.num_cells()) print('Mesh size %g %g' % (mesh.hmin(), mesh.hmax())) # Save ALL data as facet_functions names = ('surfaces', 'volumes') if not save_mvc: for name, region in zip(names, ('facet_region.xml', 'physical_region.xml')): r_xml_file = '_'.join([root, region]) f = MeshFunction('size_t', mesh, r_xml_file) print('%d %s with 1' % (sum(1 for _ in SubsetIterator(f, 1)), name)) out.write(f, name) return True for name, region in zip(names, ('facet_region.xml', 'physical_region.xml')): r_xml_file = '_'.join([root, region]) f = MeshFunction('size_t', mesh, r_xml_file) # With mesh value collection we only store nonzero tags mvc = MeshValueCollection('size_t', mesh, f.dim()) # Fill fill_mvc_from_mf(f, mvc) # And save out.write(mvc, name) return True
def test_tiling(self): tile = UnitSquareMesh(2, 2) mf = MeshFunction('size_t', tile, tile.topology().dim() - 1, 0) CompiledSubDomain('near(x[0], 0.5) || near(x[1], 0.5)').mark(mf, 1) mesh_data = {} mesh_data = load_data(tile, mf, dim=1, data=mesh_data) mesh, mesh_data = TileMesh(tile, shape=(23, 13), mesh_data=mesh_data) f = mf_from_data(mesh, mesh_data)[1] self.assertTrue( np.linalg.norm(mesh.coordinates().min(axis=0) - np.zeros(2)) < 1E-13) self.assertTrue( np.linalg.norm(mesh.coordinates().max(axis=0) - np.array([23., 13.])) < 1E-13) self.assertTrue(23 * 13 * 4 == sum(1 for _ in SubsetIterator(f, 1)))
def load_data(mesh, h5_file, data_set, dim, data): ''' Fill the data dictionary with data_set representing mesh function with dim over mesh read from h5_file according to key spec expected by tiling algorithm. ''' mf = MeshFunction('size_t', mesh, dim, 0) h5_file.read(mf, data_set) # Data to evolve mesh.init(dim, 0) e2v = tile.topology()(dim, 0) tags = set(mf.array()) # Don't evolve zero - we initialize to it if 0 in tags: tags.remove(0) info('%s evolves tags %r' % (data_set, tags)) for tag in tags: data[(dim, tag)] = np.array([e2v(e.index()) for e in SubsetIterator(mf, tag)], dtype='uintp') return data
def cells_of(cell_f, tag): '''Cells of tagged volume''' return list( map(operator.methodcaller('index'), SubsetIterator(cell_f, tag)))
def trace_mat_no_restrict(V, TV, trace_mesh=None, tag_data=None): '''The first cell connected to the facet gets to set the values of TV''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # None means all if tag_data is None: tag_data = (MeshFunction('size_t', trace_mesh, trace_mesh.topology().dim(), 0), set((0, ))) trace_mesh_subdomains, tags = tag_data # Init/extract the mapping try: assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags) except (AssertionError, IndexError): warning('Using non-conforming trace') # So non-conforming matrix returns PETSc.Mat return nonconforming_trace_mat(V, TV) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim + 1) f2c = mesh.topology()(fdim, fdim + 1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions # of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) # Only look at tagged cells trace_cells = itertools.chain(*[ itertools.imap(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ]) # Rows visited_dofs = [False] * TV.dim() # Column values dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(TV, V) as mat: for trace_cell in trace_cells: # We might TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) for local_T, dof_T in enumerate(trace_dofs): if visited_dofs[dof_T]: continue else: visited_dofs[dof_T] = True # Define trace dof TV_dof.dof = local_T # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = TV_dof.eval(V_basis_f) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') # Insert mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) return mat
def trace_mat_one_restrict(V, TV, restriction, normal, trace_mesh=None, tag_data=None): ''' Compute the trace values using +/- restriction. A + plus is the one for which the vector cell.midpoint - facet.midpoint agrees in orientation with the normal on the facet. ''' mesh = V.mesh() fdim = mesh.topology().dim() - 1 if trace_mesh is None: trace_mesh = TV.mesh() # None means all if tag_data is None: tag_data = (MeshFunction('size_t', trace_mesh, trace_mesh.topology().dim(), 0), set((0, ))) trace_mesh_subdomains, tags = tag_data # Only look at tagged cells trace_cells = itertools.chain(*[ itertools.imap(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ]) # Init/extract entity map assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim + 1) f2c = mesh.topology()(fdim, fdim + 1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions # of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) gdim = mesh.geometry().dim() # Rows visited_dofs = [False] * TV.dim() # Column values dof_values = np.zeros(V_basis_f.elm.space_dimension(), dtype='double') with petsc_serial_matrix(TV, V) as mat: for trace_cell in trace_cells: TV_dof.cell = trace_cell trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here facet_cells = f2c(mapping[trace_cell]) assert 0 < len(facet_cells) < 3 # Ignore boundary facets if len(facet_cells) == 1: cell = facet_cells[0] # Search which cell has the right sign else: signs = [] for fcell in facet_cells: t_mp = Cell(trace_mesh, trace_cell).midpoint().array()[:gdim] mp = Cell(mesh, fcell).midpoint().array()[:gdim] sign = '+' if np.inner(mp - t_mp, normal(t_mp)) > 0 else '-' signs.append(sign) cell = facet_cells[signs.index(restriction)] V_basis_f.cell = cell dofs = dmap.cell_dofs(cell) for local_T, dof_T in enumerate(trace_dofs): if visited_dofs[dof_T]: continue else: visited_dofs[dof_T] = True # Define trace dof TV_dof.dof = local_T # Eval at V basis functions for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local dof_values[local] = TV_dof.eval(V_basis_f) # Can fill the matrix now col_indices = np.array(dofs, dtype='int32') # Insert mat.setValues([dof_T], col_indices, dof_values, PETSc.InsertMode.INSERT_VALUES) return mat
print('Area/Volume %.3f, Area(!port)/Volume %.3f' % ((area_port + area_no_port) / volume, area_no_port / volume)) volume = intra + extra print('Area/Volume %.3f, Area(!port)/Volume %.3f' % ((area_port + area_no_port) / volume, area_no_port / volume)) # Mesh size mesh.init(2) mesh.init(2, 0) f2v = mesh.topology()(2, 0) tri_area = lambda x: np.linalg.norm(np.cross(x[0] - x[1], x[0] - x[2]), 2 ) / 2 x = mesh.coordinates() areas = [tri_area(x[f2v(f.index())]) for f in SubsetIterator(surfaces, 1)] min_l = sqrt(4 * np.min(areas) / sqrt(3)) max_l = sqrt(4 * np.max(areas) / sqrt(3)) print('Mesh size %g %g' % (min_l, max_l)) print('Domain sizes %g %g %g' % tuple(np.max(x, axis=0) - np.min(x, axis=0))) File('foo.pvd') << volumes File('bar.pvd') << surfaces map( os.remove, filter(lambda f: any(f.endswith(ext) for ext in ('.xml', '.msh')), os.listdir('.')))
def test_convert_triangle( self): # Disabled because it fails, see FIXME below # test no. 1 from dolfin import Mesh, MPI fname = os.path.join(os.path.dirname(__file__), "data", "triangle") dfname = fname + ".xml" # Read triangle file and convert to a dolfin xml mesh file meshconvert.triangle2xml(fname, dfname) # Read in dolfin mesh and check number of cells and vertices mesh = Mesh(dfname) self.assertEqual(mesh.num_vertices(), 96) self.assertEqual(mesh.num_cells(), 159) # Clean up os.unlink(dfname) # test no. 2 from dolfin import MPI, Mesh, MeshFunction, \ edges, Edge, faces, Face, \ SubsetIterator, facets fname = os.path.join(os.path.dirname(__file__), "data", "test_Triangle_3") dfname = fname + ".xml" dfname0 = fname + ".attr0.xml" # Read triangle file and convert to a dolfin xml mesh file meshconvert.triangle2xml(fname, dfname) # Read in dolfin mesh and check number of cells and vertices mesh = Mesh(dfname) mesh.init() mfun = MeshFunction('double', mesh, dfname0) self.assertEqual(mesh.num_vertices(), 58) self.assertEqual(mesh.num_cells(), 58) # Create a size_t MeshFunction and assign the values based on the # converted Meshfunction cf = MeshFunction("size_t", mesh, mesh.topology().dim()) cf.array()[mfun.array() == 10.0] = 0 cf.array()[mfun.array() == -10.0] = 1 # Meassure total area of cells with 1 and 2 marker add = lambda x, y: x + y area0 = reduce(add, (Face(mesh, cell.index()).area() \ for cell in SubsetIterator(cf, 0)), 0.0) area1 = reduce(add, (Face(mesh, cell.index()).area() \ for cell in SubsetIterator(cf, 1)), 0.0) total_area = reduce(add, (face.area() for face in faces(mesh)), 0.0) # Check that all cells in the two domains are either above or below y=0 self.assertTrue( all(cell.midpoint().y() < 0 for cell in SubsetIterator(cf, 0))) self.assertTrue( all(cell.midpoint().y() > 0 for cell in SubsetIterator(cf, 1))) # Check that the areas add up self.assertAlmostEqual(area0 + area1, total_area) # Measure the edge length of the two edge domains #edge_markers = mesh.domains().facet_domains() edge_markers = mesh.domains().markers(mesh.topology().dim() - 1) self.assertTrue(edge_markers is not None) #length0 = reduce(add, (Edge(mesh, e.index()).length() \ # for e in SubsetIterator(edge_markers, 0)), 0.0) length0, length1 = 0.0, 0.0 for item in list(edge_markers.items()): if item[1] == 0: e = Edge(mesh, int(item[0])) length0 += Edge(mesh, int(item[0])).length() elif item[1] == 1: length1 += Edge(mesh, int(item[0])).length() # Total length of all edges and total length of boundary edges total_length = reduce(add, (e.length() for e in edges(mesh)), 0.0) boundary_length = reduce(add, (Edge(mesh, f.index()).length() \ for f in facets(mesh) if f.exterior()), 0.0) # Check that the edges add up self.assertAlmostEqual(length0 + length1, total_length) self.assertAlmostEqual(length1, boundary_length) # Clean up os.unlink(dfname) os.unlink(dfname0)
def trace_mat_no_restrict(V, TV, trace_mesh=None, tag_data=None): '''The first cell connected to the facet gets to set the values of TV''' mesh = V.mesh() if trace_mesh is None: trace_mesh = TV.mesh() fdim = trace_mesh.topology().dim() # None means all if tag_data is None: try: marking_function = trace_mesh.marking_function tag_data = (marking_function, set(marking_function.array())) except AttributeError: tag_data = (MeshFunction('size_t', trace_mesh, trace_mesh.topology().dim(), 0), set( (0, ))) trace_mesh_subdomains, tags = tag_data # Init/extract the mapping try: assert get_entity_map(mesh, trace_mesh, trace_mesh_subdomains, tags) except (AssertionError, IndexError): warning('Using non-conforming trace') # So non-conforming matrix returns PETSc.Mat return nonconforming_trace_mat(V, TV) if V.ufl_element().family() == 'HDiv Trace': assert V.ufl_element().degree() == 0 # In this case return DLT_trace_mat(V, TV, trace_mesh=trace_mesh, tag_data=tag_data) # We can get it mapping = trace_mesh.parent_entity_map[mesh.id()][ fdim] # Map cell of TV to cells of V mesh.init(fdim, fdim + 1) f2c = mesh.topology()(fdim, fdim + 1) # Facets of V to cell of V # The idea is to evaluate TV's degrees of freedom at basis functions of V Tdmap = TV.dofmap() TV_dof = DegreeOfFreedom(TV) dmap = V.dofmap() V_basis_f = FEBasisFunction(V) # Only look at tagged cells trace_cells = list( itertools.chain(*[ map(operator.methodcaller('index'), SubsetIterator(trace_mesh_subdomains, tag)) for tag in tags ])) ndofs_elm, nbasis_elm = TV_dof.elm.space_dimension( ), V_basis_f.elm.space_dimension() local_values = np.zeros((nbasis_elm, ndofs_elm)) if len(trace_cells) > 10_000: print(f'Trace mat {TV.ufl_element()} -> {V.ufl_element()}') trace_cells = tqdm.tqdm(trace_cells, total=len(trace_cells)) rows, cols, values = [], [], [] # DG spaces don't share rows between cells so we take advantage of # this in special branch if TV.ufl_element().family() == 'Discontinuous Lagrange': for trace_cell in trace_cells: TV_dof.cell = trace_cell # Many rows at once trace_dofs = Tdmap.cell_dofs(trace_cell) # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell # Columns for the rows dofs = dmap.cell_dofs(cell) for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local # Get all rows at once local_values[local][:] = TV_dof.eval_dofs(V_basis_f) # Indices for the filled piece rows_ = np.tile(trace_dofs, nbasis_elm) cols_ = np.repeat(dofs, ndofs_elm) rows.extend(rows_) cols.extend(cols_) values.extend(local_values.flat) # FIXME: Othewise we need to take care of duplicate entrieselse: else: needs_fill = np.ones(TV.dim(), dtype=bool) for trace_cell in trace_cells: TV_dof.cell = trace_cell # Many rows at once trace_dofs = Tdmap.cell_dofs(trace_cell) # Don't add duplicates unseen = needs_fill[trace_dofs] # Some will be true and # For the future needs_fill[trace_dofs[unseen]] = False # Figure out the dofs of V to use here. Does not matter which # cell of the connected ones we pick cell = f2c(mapping[trace_cell])[0] V_basis_f.cell = cell # Columns for the rows dofs = dmap.cell_dofs(cell) for local, dof in enumerate(dofs): # Set which basis foo V_basis_f.dof = local # Get all rows at once local_values[local][:] = TV_dof.eval_dofs(V_basis_f) # Indices for the filled piece rows_ = np.tile(trace_dofs[unseen], nbasis_elm) cols_ = np.repeat(dofs, sum(unseen)) rows.extend(rows_) cols.extend(cols_) values.extend(local_values[:, unseen].flat) mat = csr_matrix((values, (rows, cols)), shape=(TV.dim(), V.dim())) return PETSc.Mat().createAIJ(comm=PETSc.COMM_WORLD, size=mat.shape, csr=(mat.indptr, mat.indices, mat.data))
def deactivate_volumes(cell_f, tag, predicate): '''Tagged cells of cell_f that satisfy the predicate''' return [ cell.index() for cell in SubsetIterator(cell_f, tag) if predicate(cell) ]
def union_mesh(meshes, tol=1E-12): '''Glue together meshes into a big one.''' assert meshes num_meshes = len(meshes) # Nothing to do if num_meshes == 1: return meshes[0] # Recurse if num_meshes > 2: return union_mesh([ union_mesh(meshes[:num_meshes / 2 + 1]), union_mesh(meshes[num_meshes / 2 + 1:]) ]) gdim, = set(m.geometry().dim() for m in meshes) tdim, = set(m.topology().dim() for m in meshes) fdim = tdim - 1 bdries = [MeshFunction('size_t', m, fdim, 0) for m in meshes] [DomainBoundary().mark(bdry, 1) for bdry in bdries] # We are after boundary vertices of both; NOTE that the assumption # here is that the meshes share only the boundary vertices [m.init(fdim) for m in meshes] [m.init(fdim, 0) for m in meshes] bdry_vertices0, bdry_vertices1 = map( list, (set(np.concatenate([f.entities(0) for f in SubsetIterator(bdry, 1)])) for bdry in bdries)) x0, x1 = [m.coordinates() for m in meshes] x1 = x1[bdry_vertices1] shared_vertices = {} while bdry_vertices0: i = bdry_vertices0.pop() x = x0[i] # Try to match it dist = np.linalg.norm(x1 - x, 2, axis=1) imin = np.argmin(dist) if dist[imin] < tol: shared_vertices[bdry_vertices1[imin]] = i x1 = np.delete(x1, imin, axis=0) del bdry_vertices1[imin] mesh0, mesh1 = meshes # We make 0 the master - it adds all its vertices # The other on add all but those that are not shared unshared = list( set(range(mesh1.num_vertices())) - set(shared_vertices.keys())) merge_x = mesh0.coordinates() offset = len(merge_x) # Vertices of the merged mesh merge_x = np.row_stack([merge_x, mesh1.coordinates()[unshared]]) # Mapping for cells from meshes lg1 = {k: v for v, k in enumerate(unshared, offset)} lg1.update(shared_vertices) # Collapse to list _, lg1 = zip(*sorted(lg1.items(), key=lambda v: v[0])) lg1 = np.array(lg1) mapped_cells = np.fromiter((lg1[v] for v in np.concatenate(mesh1.cells())), dtype='uintp').reshape((mesh1.num_cells(), -1)) merged_cells = np.row_stack([mesh0.cells(), mapped_cells]) merged_mesh = make_mesh(coordinates=merge_x, cells=merged_cells, tdim=tdim, gdim=gdim) lg0 = np.arange(mesh0.num_vertices()) # Mapping from leafs if not hasattr(mesh0, 'leafs'): merged_mesh.leafs = [(mesh0.id(), lg0)] else: merged_mesh.leafs = mesh0.leafs if not hasattr(mesh1, 'leafs'): merged_mesh.leafs.append([mesh1.id(), lg1]) else: for id_, map_ in mesh1.leafs: merged_mesh.leafs.append((id_, lg1[map_])) return merged_mesh
def vtk_surface(surfaces, tag, output, value): assert surfaces.dim() == 2 mesh = surfaces.mesh() mesh.init(2, 0) f2v = mesh.topology()(2, 0) ncells = sum(1 for _ in SubsetIterator(surfaces, tag)) nvertices = 3 * ncells x = mesh.coordinates() with open(output, 'w') as f: f.write("<?xml version=\"1.0\"?>\n") f.write( "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n" ) f.write(" <UnstructuredGrid>\n") f.write(" <Piece NumberOfPoints=\"%i\" NumberOfCells=\"%i\">\n" % (nvertices, ncells)) f.write(" <Points>\n") f.write( " <DataArray type=\"Float32\" Name=\"vertices\" NumberOfComponents=\"3\" format=\"ascii\">\n" ) for e in SubsetIterator(surfaces, tag): coords = x[f2v(e.index())] for v in coords: f.write("%g %g %g " % tuple(v)) f.write(" </DataArray>\n") f.write(" </Points>\n") f.write(" <Cells>\n") f.write( " <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n" ) f.write(" ".join(map(str, range(nvertices)))) f.write(" </DataArray>\n") f.write( " <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n" ) f.write(' '.join(map(str, range(0, 3 * ncells, 3)))) f.write(" </DataArray>\n") f.write( " <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n" ) f.write('5 ' * ncells) f.write(' </DataArray>\n') f.write(" </Cells>\n") value = '%d ' % value print value f.write(' <CellData Scalars="tags">\n') f.write( " <DataArray type=\"Float32\" Name=\"tags\" format=\"ascii\">\n" ) f.write(value * ncells) f.write(" </DataArray>\n") f.write(" </CellData>\n") f.write(" </Piece>\n") f.write(" </UnstructuredGrid>\n") f.write("</VTKFile>\n")
def test(path, type='mf'): '''Evolve the tile in (n, n) pattern checking volume/surface properties''' comm = mpi_comm_world() h5 = HDF5File(comm, path, 'r') tile = Mesh() h5.read(tile, 'mesh', False) init_container = lambda type, dim: ( MeshFunction('size_t', tile, dim, 0) if type == 'mf' else MeshValueCollection('size_t', tile, dim)) for n in (2, 4): data = {} checks = {} for dim, name in zip((2, 3), ('surfaces', 'volumes')): # Get the collection collection = init_container(type, dim) h5.read(collection, name) if type == 'mvc': collection = as_meshf(collection) # Data to evolve tile.init(dim, 0) e2v = tile.topology()(dim, 0) # Only want to evolve tag 1 (interfaces) for the facets. data[(dim, 1)] = np.array( [e2v(e.index()) for e in SubsetIterator(collection, 1)], dtype='uintp') if dim == 2: check = lambda m, f: assemble( FacetArea(m) * ds(domain=m, subdomain_data=f, subdomain_id=1) + avg(FacetArea(m)) * dS(domain=m, subdomain_data=f, subdomain_id=1)) else: check = lambda m, f: assemble( CellVolume(m) * dx( domain=m, subdomain_data=f, subdomain_id=1)) checks[ dim] = lambda m, f, t=tile, c=collection, n=n, check=check: abs( check(m, f) - n**2 * check(t, c)) / (n**2 * check(t, c)) t = Timer('x') mesh, mesh_data = TileMesh(tile, (n, n), mesh_data=data) info('\tTiling took %g s. Ncells %d, nvertices %d, \n' % (t.stop(), mesh.num_vertices(), mesh.num_cells())) foos = mf_from_data(mesh, mesh_data) # Mesh Functions from_mf = np.array([checks[dim](mesh, foos[dim]) for dim in (2, 3)]) mvcs = mvc_from_data(mesh, mesh_data) foos = as_meshf(mvcs) # Mesh ValueCollections from_mvc = np.array([checks[dim](mesh, foos[dim]) for dim in (2, 3)]) assert np.linalg.norm(from_mf - from_mvc) < 1E-13 # I ignore shared facets so there is bound to be some error in facets # Volume should match well print from_mf
# ------------------------------------------------------------------- if __name__ == '__main__': from dolfin import (CompiledSubDomain, DomainBoundary, SubsetIterator, UnitSquareMesh, Facet) from xii import EmbeddedMesh mesh = UnitSquareMesh(4, 4) surfaces = MeshFunction('size_t', mesh, 2, 0) CompiledSubDomain('x[0] > 0.5-DOLFIN_EPS').mark(surfaces, 1) # What should be trasfered f = MeshFunction('size_t', mesh, 1, 0) DomainBoundary().mark(f, 1) CompiledSubDomain('near(x[0], 0.5)').mark(f, 1) # Assign funky colors for i, e in enumerate(SubsetIterator(f, 1), 1): f[e] = i ch_mesh = EmbeddedMesh(surfaces, 1) ch_f = transfer_markers(ch_mesh, f) # Every color in child is found in parent and we get the midpoint right p_values, ch_values = list(f.array()), list(ch_f.array()) for ch_value in set(ch_f.array()) - set((0, )): assert ch_value in p_values x = Facet(mesh, p_values.index(ch_value)).midpoint() y = Facet(ch_mesh, ch_values.index(ch_value)).midpoint() assert x.distance(y) < 1E-13