def local_to_global_map(self, bcs, lgmap=None): r"""Return a map from process local dof numbering to global dof numbering. If BCs is provided, mask out those dofs which match the BC nodes.""" # Caching these things is too complicated, since it depends # not just on the bcs, but also the parent space, and anything # this space has been recursively split out from [e.g. inside # fieldsplit] if bcs is None or len(bcs) == 0: return lgmap or self.dof_dset.lgmap for bc in bcs: fs = bc.function_space() while fs.component is not None and fs.parent is not None: fs = fs.parent if fs.topological != self.topological: raise RuntimeError( "DirichletBC defined on a different FunctionSpace!") unblocked = any(bc.function_space().component is not None for bc in bcs) if lgmap is None: lgmap = self.dof_dset.lgmap if unblocked: indices = lgmap.indices.copy() bsize = 1 else: indices = lgmap.block_indices.copy() bsize = lgmap.getBlockSize() assert bsize == self.value_size else: # MatBlock case, LGMap is already unrolled. indices = lgmap.block_indices.copy() bsize = lgmap.getBlockSize() unblocked = True nodes = [] for bc in bcs: if bc.function_space().component is not None: nodes.append(bc.nodes * self.value_size + bc.function_space().component) elif unblocked: tmp = bc.nodes * self.value_size for i in range(self.value_size): nodes.append(tmp + i) else: nodes.append(bc.nodes) nodes = numpy.unique(numpy.concatenate(nodes)) indices[nodes] = -1 return PETSc.LGMap().create(indices, bsize=bsize, comm=lgmap.comm)
def lgmap(self, V, bcs, lgmap=None): assert len(V) == 1, "lgmap should not be called on MixedFunctionSpace" V = V.topological if bcs is None or len(bcs) == 0: return lgmap or V.dof_dset.lgmap # Boundary condition list *must* be collectively ordered already. # Key is a sorted list of bc subdomain, bc method, bc component. bc_key = [] for bc in bcs: fs = bc.function_space() while fs.component is not None and fs.parent is not None: fs = fs.parent if fs.topological != V: raise RuntimeError("DirichletBC defined on a different FunctionSpace!") bc_key.append(bc._cache_key) def key(a): tpl, *rest = a if len(tpl) == 1 and isinstance(tpl[0], str): # tpl = ("some_string", ) return (True, tpl[0], (), tuple(rest)) else: # Ex: # tpl = ((facet_dim, ((1,), (2,), (3,))), # (edge_dim, ((1, 3), (1, 4))), # (vert_dim, ((1, 3, 4), ))) return (False, "", tpl, tuple(rest)) bc_key = tuple(sorted(bc_key, key=key)) node_set = V.node_set key = (node_set, V.value_size, lgmap is None, bc_key) try: return self.map_cache[key] except KeyError: pass unblocked = any(bc.function_space().component is not None for bc in bcs) if lgmap is None: lgmap = V.dof_dset.lgmap if unblocked: indices = lgmap.indices.copy() bsize = 1 else: indices = lgmap.block_indices.copy() bsize = lgmap.getBlockSize() assert bsize == V.value_size else: # MatBlock case, LGMap is already unrolled. indices = lgmap.block_indices.copy() bsize = lgmap.getBlockSize() unblocked = True nodes = [] for bc in bcs: if bc.function_space().component is not None: nodes.append(bc.nodes * V.value_size + bc.function_space().component) elif unblocked: tmp = bc.nodes * V.value_size for i in range(V.value_size): nodes.append(tmp + i) else: nodes.append(bc.nodes) nodes = numpy.unique(numpy.concatenate(nodes)) indices[nodes] = -1 return self.map_cache.setdefault(key, PETSc.LGMap().create(indices, bsize=bsize, comm=lgmap.comm))