def connections(self): p = self.model.pardim # For every object in the model... for node in self.nodes: # Loop over its sections of one lower parametric dimension # That is, for faces, loop over edges, and for volumes, loop over faces for node_sub_idx, sub in enumerate(node.lower_nodes[p - 1]): # The sub-node should have at most one neighbour, excluding the original node neighbours = set(sub.higher_nodes[p]) - {node} assert len(neighbours) <= 1 if not neighbours: continue # Get the neighbour node and its section index to the same sub-node neigh = next(iter(neighbours)) neigh_sub_idx = neigh.lower_nodes[p - 1].index(sub) # Only output if the node has a lower ID than the neighbour, # otherwise we'll get this pair when the reverse pair is found if self.node_ids[node] > self.node_ids[neigh]: continue # Find the actual SplineObjects representing the # sub-node, as it is viewed from the perspective of # both the node and the neighbour, then compute the # orientation mapping between them node_sec_idx = section_from_index(p, p - 1, node_sub_idx) node_sub = node.obj.section(*node_sec_idx) neigh_sec_idx = section_from_index(p, p - 1, neigh_sub_idx) neigh_sub = neigh.obj.section(*neigh_sec_idx) # print('------') # print(node.obj) # print(neigh.obj, self.node_ids[neigh] + 1) orientation = Orientation.compute(node_sub, neigh_sub) # print(orientation.flip, orientation.perm, orientation.ifem_format) yield IFEMConnection( master=self.node_ids[node] + 1, slave=self.node_ids[neigh] + 1, midx=node_sub_idx + 1, sidx=neigh_sub_idx + 1, orient=orientation.ifem_format, )
def face(self, i): """Return the i'th face.""" return self.section(*section_from_index(self.pardim, 2, i))
def edge(self, i): """Return the i'th edge.""" return self.section(*section_from_index(self.pardim, 1, i))
def corner(self, i): """Return the i'th corner.""" return self.section(*section_from_index(self.pardim, 0, i))
def faces(self): """Return all faces owned by this node, as a list of numpy arrays with dtype `face_t`.""" assert self.pardim == 3 assert self.obj.order() == (2, 2, 2) shape = [len(kvec) - 1 for kvec in self.obj.knots()] ncells = np.prod(shape) retval = [] def mkindex(dim, z, a, b): rval = [a, b] if dim != 1 else [b, a] rval.insert(dim, z) return tuple(rval) lower = iter(self.lower_nodes[-1]) for d in range(self.pardim): # Number of faces in one "slice" nperslice = ncells // shape[d] # First, get all internal faces in this direction # The owner (lowest cell index) is guaranteed to be toward the lower end # TODO: We assume a right-hand coordinate system here nfaces = ncells - nperslice faces = np.empty((nfaces, ), dtype=face_t) faces['nodes'][:, 0] = self.cp_numbers[mkindex( d, np.s_[1:-1], np.s_[:-1], np.s_[:-1])].flatten() faces['nodes'][:, 1] = self.cp_numbers[mkindex( d, np.s_[1:-1], np.s_[1:], np.s_[:-1])].flatten() faces['nodes'][:, 2] = self.cp_numbers[mkindex( d, np.s_[1:-1], np.s_[1:], np.s_[1:])].flatten() faces['nodes'][:, 3] = self.cp_numbers[mkindex( d, np.s_[1:-1], np.s_[:-1], np.s_[1:])].flatten() faces['owner'] = self.cell_numbers[mkindex(d, np.s_[:-1], np.s_[:], np.s_[:])].flatten() faces['neighbor'] = self.cell_numbers[mkindex( d, np.s_[1:], np.s_[:], np.s_[:])].flatten() retval.append(faces) # Go through the two boundaries for bdnode, bdindex in zip(islice(lower, 2), (0, -1)): assert bdnode.nhigher in {1, 2} # Faces on an interface are only returned from the owner if bdnode.owner is not self: continue faces = np.empty((nperslice, ), dtype=face_t) faces['nodes'][:, 0] = self.cp_numbers[mkindex( d, bdindex, np.s_[:-1], np.s_[:-1])].flatten() faces['nodes'][:, 1] = self.cp_numbers[mkindex( d, bdindex, np.s_[1:], np.s_[:-1])].flatten() faces['nodes'][:, 2] = self.cp_numbers[mkindex( d, bdindex, np.s_[1:], np.s_[1:])].flatten() faces['nodes'][:, 3] = self.cp_numbers[mkindex( d, bdindex, np.s_[:-1], np.s_[1:])].flatten() faces['owner'] = self.cell_numbers[mkindex( d, bdindex, np.s_[:], np.s_[:])].flatten() faces['name'] = bdnode.name # If we're on the left boundary, the face normal must point in the other direction # NOTE: We copy when swapping here, since we are swapping values which are views into # a mutable array! if bdindex == 0: faces['nodes'][:, 1], faces['nodes'][:, 3] = ( faces['nodes'][:, 3].copy(), faces['nodes'][:, 1].copy()) # If there's a neighbor on the interface we need neighbouring cell numbers if bdnode.nhigher == 1: faces['neighbor'] = -1 else: neighbor = next(c for c in bdnode.higher_nodes[3] if c is not self) # Find out which face the interface is as numbered from the neighbor's perspective nb_index = neighbor.lower_nodes[2].index(bdnode) # Get the spline object on that interface as oriented from the neighbor's perspective nb_sec = section_from_index(3, 2, nb_index) nb_obj = neighbor.obj.section(*nb_sec) # Compute the relative orientation ori = Orientation.compute(bdnode.obj, nb_obj) # Get the neighbor cell numbers from the neighbor's perspective, and map them to our system cellidxs = neighbor.cell_numbers[_section_to_index(nb_sec)] faces['neighbor'] = ori.map_array(cellidxs).flatten() retval.append(faces) for faces in retval: assert ((faces['owner'] < faces['neighbor']) | (faces['neighbor'] == -1)).all() return retval