def setup_surface_data(self, region, is_trace=False): """nodes[leconn] == econn""" """nodes are sorted by node number -> same order as region.vertices""" if region.name not in self.surface_data: sd = FESurface('surface_data_%s' % region.name, region, self.efaces, self.econn, self.region) self.surface_data[region.name] = sd if region.name in self.surface_data and is_trace: sd = self.surface_data[region.name] sd.setup_mirror_connectivity(region) return self.surface_data[region.name]
def from_args(region, kind='v', ig=None): """ Create mapping from reference to physical entities in a given region, given the integration kind ('v' or 's'). This mapping can be used to compute the physical quadrature points. Parameters ---------- region : Region instance The region defining the entities. kind : 'v' or 's' The kind of the entities: 'v' - cells, 's' - facets. ig : int, optional The group index. Returns ------- mapping : VolumeMapping or SurfaceMapping instance The requested mapping. """ from sfepy.discrete.fem.domain import FEDomain from sfepy.discrete.iga.domain import IGDomain if isinstance(region.domain, FEDomain): import sfepy.discrete.fem.mappings as mm coors = region.domain.get_mesh_coors() if kind == 's': coors = coors[region.vertices] gel = region.domain.groups[ig].gel conn = region.domain.groups[ig].conn if kind == 'v': cells = region.get_cells(ig) mapping = mm.VolumeMapping(coors, conn[cells], gel=gel) elif kind == 's': from sfepy.discrete.fem.fe_surface import FESurface aux = FESurface('aux', region, gel.get_surface_entities(), conn, ig) mapping = mm.SurfaceMapping(coors, aux.leconn, gel=gel.surface_facet) elif isinstance(region.domain, IGDomain): import sfepy.discrete.iga.mappings as mm mapping = mm.IGMapping(region.domain, region.cells) else: raise ValueError('unknown domain class! (%s)' % type(region.domain)) return mapping
def create_surface_group(self, region): """ Create a new surface group corresponding to `region` if it does not exist yet. Notes ----- Surface groups define surface facet connectivity that is needed for :class:`sfepy.discrete.fem.mappings.SurfaceMapping`. """ groups = self.surface_groups if region.name not in groups: conn, gel = self.get_conn(ret_gel=True) gel_faces = gel.get_surface_entities() name = 'surface_group_%s' % (region.name) surface_group = FESurface(name, region, gel_faces, conn) groups[region.name] = surface_group
def _setup_vertex_dofs(self): """ Setup vertex DOF connectivity. """ if self.node_desc.vertex is None: return 0, None region = self.region remap = prepare_remap(region.vertices, region.n_v_max) n_dof = region.vertices.shape[0] # Remap vertex node connectivity to field-local numbering. conn, gel = self.domain.get_conn(ret_gel=True) faces = gel.get_surface_entities() aux = FESurface('aux', region, faces, conn) self.econn[:, :aux.n_fp] = aux.leconn self.surface_data[region.name] = aux return n_dof, remap
def create_surface_group(self, region): """ Create a new surface group corresponding to `region` if it does not exist yet. Notes ----- Surface groups define surface facet connectivity that is needed for :class:`sfepy.discrete.fem.mappings.SurfaceMapping`. """ for ig in region.igs: groups = self.surface_groups.setdefault(ig, {}) if region.name not in groups: group = self.groups[ig] gel_faces = group.gel.get_surface_entities() name = 'surface_group_%s_%d' % (region.name, ig) surface_group = FESurface(name, region, gel_faces, group.conn, ig) groups[region.name] = surface_group
def _setup_vertex_dofs(self): """ Setup vertex DOF connectivity. """ if self.node_desc.vertex is None: return 0, None region = self.region remap = prepare_remap(region.vertices, region.n_v_max) n_dof = region.vertices.shape[0] ## # Remap vertex node connectivity to field-local numbering. for ig, ap in self.aps.iteritems(): group = self.domain.groups[ig] faces = group.gel.get_surface_entities() aux = FESurface('aux', region, faces, group.conn, ig) ap.econn[:,:aux.n_fp] = aux.leconn ap.surface_data[region.name] = aux return n_dof, remap
def create_task_dof_maps(field, cell_tasks, inter_facets, is_overlap=True, use_expand_dofs=False, save_inter_regions=False, output_dir=None): """ For each task list its inner and interface DOFs of the given field and create PETSc numbering that is consecutive in each subdomain. For each task, the DOF map has the following structure:: [inner, [own_inter1, own_inter2, ...], [overlap_cells1, overlap_cells2, ...], n_task_total, task_offset] The overlapping cells are defined so that the system matrix corresponding to each task can be assembled independently, see [1]. TODO: Some "corner" cells may be added even if not needed - filter them out by using the PETSc DOFs range. When debugging domain partitioning problems, it is advisable to set `save_inter_regions` to True to save the task interfaces as meshes as well as vertex-based markers - to be used only with moderate problems and small numbers of tasks. [1] J. Sistek and F. Cirak. Parallel iterative solution of the incompressible Navier-Stokes equations with application to rotating wings. Submitted for publication, 2015 """ domain = field.domain cmesh = domain.cmesh if use_expand_dofs: id_map = nm.zeros(field.n_nod * field.n_components, dtype=nm.uint32) else: id_map = nm.zeros(field.n_nod, dtype=nm.uint32) def _get_dofs_region(field, region): dofs = field.get_dofs_in_region(region) if use_expand_dofs: dofs = expand_dofs(dofs, field.n_components) return dofs def _get_dofs_conn(field, conn): dofs = nm.unique(conn) if use_expand_dofs: dofs = expand_dofs(dofs, field.n_components) return dofs dof_maps = {} count = 0 inter_count = 0 ocs = nm.zeros(0, dtype=nm.int32) cell_parts = [] for ir, ntasks in ordered_iteritems(inter_facets): cells = nm.where(cell_tasks == ir)[0].astype(nm.int32) cell_parts.append(cells) cregion = Region.from_cells(cells, domain, name='task_%d' % ir) domain.regions.append(cregion) dofs = _get_dofs_region(field, cregion) rdof_map = dof_maps.setdefault(ir, [None, [], [], 0, 0]) inter_dofs = [] for ic, facets in ordered_iteritems(ntasks): cdof_map = dof_maps.setdefault(ic, [None, [], [], 0, 0]) name = 'inter_%d_%d' % (ir, ic) ii = ir region = Region.from_facets(facets, domain, name, parent=cregion.name) region.update_shape() if save_inter_regions: output_dir = output_dir if output_dir is not None else '.' filename = os.path.join(output_dir, '%s.mesh' % name) aux = domain.mesh.from_region(region, domain.mesh, is_surface=True) aux.write(filename, io='auto') mask = nm.zeros((domain.mesh.n_nod, 1), dtype=nm.float64) mask[region.vertices] = 1 out = {name: Struct(name=name, mode='vertex', data=mask)} filename = os.path.join(output_dir, '%s.h5' % name) domain.mesh.write(filename, out=out, io='auto') inter_dofs.append(_get_dofs_region(field, region)) sd = FESurface('surface_data_%s' % region.name, region, field.efaces, field.econn, field.region) econn = sd.get_connectivity() n_facet = econn.shape[0] ii2 = max(int(n_facet / 2), 1) dr = _get_dofs_conn(field, econn[:ii2]) ii = nm.where((id_map[dr] == 0))[0] n_new = len(ii) if n_new: rdof_map[1].append(dr[ii]) rdof_map[3] += n_new id_map[dr[ii]] = 1 inter_count += n_new count += n_new if is_overlap: ovs = cmesh.get_incident(0, region.facets[:ii2], cmesh.tdim - 1) ocs = cmesh.get_incident(cmesh.tdim, ovs, 0) rdof_map[2].append(ocs.astype(nm.int32)) dc = _get_dofs_conn(field, econn[ii2:]) ii = nm.where((id_map[dc] == 0))[0] n_new = len(ii) if n_new: cdof_map[1].append(dc[ii]) cdof_map[3] += n_new id_map[dc[ii]] = 1 inter_count += n_new count += n_new if is_overlap: ovs = cmesh.get_incident(0, region.facets[ii2:], cmesh.tdim - 1) ocs = cmesh.get_incident(cmesh.tdim, ovs, 0) cdof_map[2].append(ocs.astype(nm.int32)) domain.regions.pop() # Remove the cell region. inner_dofs = nm.setdiff1d(dofs, nm.concatenate(inter_dofs)) n_inner = len(inner_dofs) rdof_map[3] += n_inner assert_(nm.all(id_map[inner_dofs] == 0)) id_map[inner_dofs] = 1 count += n_inner rdof_map[0] = inner_dofs offset = 0 overlap_cells = [] for ir, dof_map in ordered_iteritems(dof_maps): n_owned = dof_map[3] i0 = len(dof_map[0]) id_map[dof_map[0]] = nm.arange(offset, offset + i0, dtype=nm.uint32) for aux in dof_map[1]: i1 = len(aux) id_map[aux] = nm.arange(offset + i0, offset + i0 + i1, dtype=nm.uint32) i0 += i1 if len(dof_map[2]): ocs = nm.unique(nm.concatenate(dof_map[2])) else: ocs = nm.zeros(0, dtype=nm.int32) overlap_cells.append(ocs) assert_(i0 == n_owned) dof_map[4] = offset offset += n_owned if not len(dof_maps): dofs = _get_dofs_region(field, field.region) dof_maps[0] = [dofs, [], [], len(dofs), 0] id_map[:] = nm.arange(len(dofs), dtype=nm.uint32) if not len(cell_parts): cell_parts.append(nm.arange(len(cell_tasks), dtype=nm.int32)) if not len(overlap_cells): overlap_cells.append(nm.zeros(0, dtype=nm.int32)) return dof_maps, id_map, cell_parts, overlap_cells
def create_task_dof_maps(field, cell_tasks, inter_facets, is_overlap=True, use_expand_dofs=False, save_inter_regions=False, output_dir=None): """ For each task list its inner and interface DOFs of the given field and create PETSc numbering that is consecutive in each subdomain. For each task, the DOF map has the following structure:: [inner, [own_inter1, own_inter2, ...], [overlap_cells1, overlap_cells2, ...], n_task_total, task_offset] The overlapping cells are defined so that the system matrix corresponding to each task can be assembled independently, see [1]. TODO: Some "corner" cells may be added even if not needed - filter them out by using the PETSc DOFs range. When debugging domain partitioning problems, it is advisable to set `save_inter_regions` to True to save the task interfaces as meshes as well as vertex-based markers - to be used only with moderate problems and small numbers of tasks. [1] J. Sistek and F. Cirak. Parallel iterative solution of the incompressible Navier-Stokes equations with application to rotating wings. Submitted for publication, 2015 """ domain = field.domain cmesh = domain.cmesh if use_expand_dofs: id_map = nm.zeros(field.n_nod * field.n_components, dtype=nm.uint32) else: id_map = nm.zeros(field.n_nod, dtype=nm.uint32) def _get_dofs_region(field, region): dofs = field.get_dofs_in_region(region) if use_expand_dofs: dofs = expand_dofs(dofs, field.n_components) return dofs def _get_dofs_conn(field, conn): dofs = nm.unique(conn) if use_expand_dofs: dofs = expand_dofs(dofs, field.n_components) return dofs dof_maps = {} count = 0 inter_count = 0 ocs = nm.zeros(0, dtype=nm.int32) cell_parts = [] for ir, ntasks in ordered_iteritems(inter_facets): cells = nm.where(cell_tasks == ir)[0].astype(nm.int32) cell_parts.append(cells) cregion = Region.from_cells(cells, domain, name='task_%d' % ir) domain.regions.append(cregion) dofs = _get_dofs_region(field, cregion) rdof_map = dof_maps.setdefault(ir, [None, [], [], 0, 0]) inter_dofs = [] for ic, facets in ordered_iteritems(ntasks): cdof_map = dof_maps.setdefault(ic, [None, [], [], 0, 0]) name = 'inter_%d_%d' % (ir, ic) ii = ir region = Region.from_facets(facets, domain, name, parent=cregion.name) region.update_shape() if save_inter_regions: output_dir = output_dir if output_dir is not None else '.' filename = os.path.join(output_dir, '%s.mesh' % name) aux = domain.mesh.from_region(region, domain.mesh, is_surface=True) aux.write(filename, io='auto') mask = nm.zeros((domain.mesh.n_nod, 1), dtype=nm.float64) mask[region.vertices] = 1 out = {name : Struct(name=name, mode='vertex', data=mask)} filename = os.path.join(output_dir, '%s.h5' % name) domain.mesh.write(filename, out=out, io='auto') inter_dofs.append(_get_dofs_region(field, region)) sd = FESurface('surface_data_%s' % region.name, region, field.efaces, field.econn, field.region) econn = sd.get_connectivity() n_facet = econn.shape[0] ii2 = max(int(n_facet / 2), 1) dr = _get_dofs_conn(field, econn[:ii2]) ii = nm.where((id_map[dr] == 0))[0] n_new = len(ii) if n_new: rdof_map[1].append(dr[ii]) rdof_map[3] += n_new id_map[dr[ii]] = 1 inter_count += n_new count += n_new if is_overlap: ovs = cmesh.get_incident(0, region.facets[:ii2], cmesh.tdim - 1) ocs = cmesh.get_incident(cmesh.tdim, ovs, 0) rdof_map[2].append(ocs.astype(nm.int32)) dc = _get_dofs_conn(field, econn[ii2:]) ii = nm.where((id_map[dc] == 0))[0] n_new = len(ii) if n_new: cdof_map[1].append(dc[ii]) cdof_map[3] += n_new id_map[dc[ii]] = 1 inter_count += n_new count += n_new if is_overlap: ovs = cmesh.get_incident(0, region.facets[ii2:], cmesh.tdim - 1) ocs = cmesh.get_incident(cmesh.tdim, ovs, 0) cdof_map[2].append(ocs.astype(nm.int32)) domain.regions.pop() # Remove the cell region. inner_dofs = nm.setdiff1d(dofs, nm.concatenate(inter_dofs)) n_inner = len(inner_dofs) rdof_map[3] += n_inner assert_(nm.all(id_map[inner_dofs] == 0)) id_map[inner_dofs] = 1 count += n_inner rdof_map[0] = inner_dofs offset = 0 overlap_cells = [] for ir, dof_map in ordered_iteritems(dof_maps): n_owned = dof_map[3] i0 = len(dof_map[0]) id_map[dof_map[0]] = nm.arange(offset, offset + i0, dtype=nm.uint32) for aux in dof_map[1]: i1 = len(aux) id_map[aux] = nm.arange(offset + i0, offset + i0 + i1, dtype=nm.uint32) i0 += i1 if len(dof_map[2]): ocs = nm.unique(nm.concatenate(dof_map[2])) else: ocs = nm.zeros(0, dtype=nm.int32) overlap_cells.append(ocs) assert_(i0 == n_owned) dof_map[4] = offset offset += n_owned if not len(dof_maps): dofs = _get_dofs_region(field, field.region) dof_maps[0] = [dofs, [], [], len(dofs), 0] id_map[:] = nm.arange(len(dofs), dtype=nm.uint32) if not len(cell_parts): cell_parts.append(nm.arange(len(cell_tasks), dtype=nm.int32)) if not len(overlap_cells): overlap_cells.append(nm.zeros(0, dtype=nm.int32)) return dof_maps, id_map, cell_parts, overlap_cells