def __init__(self, vertexCoords, faceVertexIDs, cellFaceIDs, communicator=serialComm, _RepresentationClass=_MeshRepresentation, _TopologyClass=_MeshTopology): super(Mesh, self).__init__(communicator=communicator, _RepresentationClass=_RepresentationClass, _TopologyClass=_TopologyClass) """faceVertexIds and cellFacesIds must be padded with minus ones.""" self.vertexCoords = vertexCoords self.faceVertexIDs = MA.masked_values(faceVertexIDs, -1) self.cellFaceIDs = MA.masked_values(cellFaceIDs, -1) self.dim = self.vertexCoords.shape[0] if not hasattr(self, "numberOfFaces"): self.numberOfFaces = self.faceVertexIDs.shape[-1] if not hasattr(self, "numberOfCells"): self.numberOfCells = self.cellFaceIDs.shape[-1] if not hasattr(self, "globalNumberOfCells"): self.globalNumberOfCells = self.numberOfCells if not hasattr(self, "globalNumberOfFaces"): self.globalNumberOfFaces = self.numberOfFaces self.faceCellIDs = self._calcFaceCellIDs() self._setTopology() self._setGeometry(scaleLength=1.)
def __init__(self, vertexCoords, faceVertexIDs, cellFaceIDs, communicator=serialComm, _RepresentationClass=_MeshRepresentation, _TopologyClass=_MeshTopology): super(Mesh, self).__init__(communicator=communicator, _RepresentationClass=_RepresentationClass, _TopologyClass=_TopologyClass) """faceVertexIds and cellFacesIds must be padded with minus ones.""" self.vertexCoords = vertexCoords self.faceVertexIDs = MA.masked_values(faceVertexIDs, -1) self.cellFaceIDs = MA.masked_values(cellFaceIDs, -1) self.dim = self.vertexCoords.shape[0] if not hasattr(self, "numberOfFaces"): self.numberOfFaces = self.faceVertexIDs.shape[-1] if not hasattr(self, "numberOfCells"): self.numberOfCells = self.cellFaceIDs.shape[-1] if not hasattr(self, "globalNumberOfCells"): self.globalNumberOfCells = self.numberOfCells if not hasattr(self, "globalNumberOfFaces"): self.globalNumberOfFaces = self.numberOfFaces self.faceCellIDs = self._calcFaceCellIDs() self._setTopology() self._setGeometry(scaleLength = 1.)
def __init__(self, vertexCoords, faceVertexIDs, cellFaceIDs): """faceVertexIds and cellFacesIds must be padded with minus ones.""" self.vertexCoords = vertexCoords self.faceVertexIDs = MA.masked_values(faceVertexIDs, -1) self.cellFaceIDs = MA.masked_values(cellFaceIDs, -1) _CommonMesh.__init__(self)
def faceCellIDs(self): Hids = numerix.zeros((2, self.nx, self.numberOfHorizontalRows), 'l') indices = numerix.indices((self.nx, self.numberOfHorizontalRows)) Hids[1] = indices[0] + indices[1] * self.nx Hids[0] = Hids[1] - self.nx if self.numberOfHorizontalRows > 0: Hids[0, ..., 0] = Hids[1, ..., 0] Hids[1, ..., 0] = -1 Hids[1, ..., -1] = -1 Vids = numerix.zeros((2, self.numberOfVerticalColumns, self.ny), 'l') indices = numerix.indices((self.numberOfVerticalColumns, self.ny)) Vids[1] = indices[0] + indices[1] * self.nx Vids[0] = Vids[1] - 1 if self.numberOfVerticalColumns > 0: Vids[0, 0] = Vids[1, 0] Vids[1, 0] = -1 Vids[1, -1] = -1 return MA.masked_values(numerix.concatenate( (Hids.reshape( (2, self.numberOfHorizontalFaces), order="FORTRAN"), Vids.reshape( (2, self.numberOfFaces - self.numberOfHorizontalFaces), order="FORTRAN")), axis=1), value=-1)
def faceCellIDs(self): Hids = numerix.zeros((2, self.nx, self.numberOfHorizontalRows), 'l') indices = numerix.indices((self.nx, self.numberOfHorizontalRows)) Hids[1] = indices[0] + indices[1] * self.nx Hids[0] = Hids[1] - self.nx if self.numberOfHorizontalRows > 0: Hids[0, ..., 0] = Hids[1, ..., 0] Hids[1, ..., 0] = -1 Hids[1, ..., -1] = -1 Vids = numerix.zeros((2, self.numberOfVerticalColumns, self.ny), 'l') indices = numerix.indices((self.numberOfVerticalColumns, self.ny)) Vids[1] = indices[0] + indices[1] * self.nx Vids[0] = Vids[1] - 1 if self.numberOfVerticalColumns > 0: Vids[0, 0] = Vids[1, 0] Vids[1, 0] = -1 Vids[1, -1] = -1 return MA.masked_values(numerix.concatenate((Hids.reshape((2, self.numberOfHorizontalFaces), order="FORTRAN"), Vids.reshape((2, self.numberOfFaces - self.numberOfHorizontalFaces), order="FORTRAN")), axis=1), value = -1)
def _getAddedMeshValues(self, other, resolution=1e-2): """Calculate the parameters to define a concatenation of `other` with `self` Parameters ---------- other : ~fipy.meshes.mesh.Mesh The `Mesh` to concatenate with `self` resolution : float How close vertices have to be (relative to the smallest cell-to-cell distance in either mesh) to be considered the same Returns ------- dict (`vertexCoords`, `faceVertexIDs`, `cellFaceIDs`) for the new mesh. """ selfc = self._concatenableMesh otherc = other._concatenableMesh selfNumFaces = selfc.faceVertexIDs.shape[-1] selfNumVertices = selfc.vertexCoords.shape[-1] otherNumFaces = otherc.faceVertexIDs.shape[-1] otherNumVertices = otherc.vertexCoords.shape[-1] ## check dimensions if(selfc.vertexCoords.shape[0] != otherc.vertexCoords.shape[0]): raise MeshAdditionError("Dimensions do not match") ## compute vertex correlates # from fipy.tools.debug import PRINT # PRINT("selfNumFaces", selfNumFaces) # PRINT("otherNumFaces", otherNumVertices) # PRINT("selfNumVertices", selfNumVertices) # PRINT("otherNumVertices", otherNumVertices) # # from fipy.tools.debug import PRINT # from fipy.tools.debug import PRINT # PRINT("otherExt", otherc.exteriorFaces.value) # raw_input() # PRINT("selfExt", selfc.exteriorFaces.value) # # PRINT("self filled", selfc.faceVertexIDs.filled()) # PRINT("othe filled", otherc.faceVertexIDs.filled()) # raw_input() # # PRINT("selfc.faceVertexIDs.filled()\n",selfc.faceVertexIDs.filled()) # PRINT("flat\n",selfc.faceVertexIDs.filled()[..., # selfc.exteriorFaces.value].flatten()) # PRINT("selfc.exteriorFaces.value\n",selfc.exteriorFaces.value) # PRINT("extfaces type", type(selfc.exteriorFaces)) # PRINT("extfaces mesh", selfc.exteriorFaces.mesh) ## only try to match along the operation manifold if hasattr(self, "opManifold"): self_faces = self.opManifold(selfc) else: self_faces = selfc.exteriorFaces.value if hasattr(other, "opManifold"): other_faces = other.opManifold(otherc) else: other_faces = otherc.exteriorFaces.value ## only try to match exterior (X) vertices self_Xvertices = numerix.unique(selfc.faceVertexIDs.filled()[..., self_faces].flatten()) other_Xvertices = numerix.unique(otherc.faceVertexIDs.filled()[..., other_faces].flatten()) self_XvertexCoords = selfc.vertexCoords[..., self_Xvertices] other_XvertexCoords = otherc.vertexCoords[..., other_Xvertices] closest = numerix.nearest(self_XvertexCoords, other_XvertexCoords) # just because they're closest, doesn't mean they're close tmp = self_XvertexCoords[..., closest] - other_XvertexCoords distance = numerix.sqrtDot(tmp, tmp) # only want vertex pairs that are 100x closer than the smallest # cell-to-cell distance close = distance < resolution * min(selfc._cellToCellDistances.min(), otherc._cellToCellDistances.min()) vertexCorrelates = numerix.array((self_Xvertices[closest[close]], other_Xvertices[close])) # warn if meshes don't touch, but allow it if (selfc._numberOfVertices > 0 and otherc._numberOfVertices > 0 and vertexCorrelates.shape[-1] == 0): import warnings warnings.warn("Vertices are not aligned", UserWarning, stacklevel=4) ## compute face correlates # ensure that both sets of faceVertexIDs have the same maximum number of (masked) elements self_faceVertexIDs = selfc.faceVertexIDs other_faceVertexIDs = otherc.faceVertexIDs diff = self_faceVertexIDs.shape[0] - other_faceVertexIDs.shape[0] if diff > 0: other_faceVertexIDs = numerix.append(other_faceVertexIDs, -1 * numerix.ones((diff,) + other_faceVertexIDs.shape[1:], 'l'), axis=0) other_faceVertexIDs = MA.masked_values(other_faceVertexIDs, -1) elif diff < 0: self_faceVertexIDs = numerix.append(self_faceVertexIDs, -1 * numerix.ones((-diff,) + self_faceVertexIDs.shape[1:], 'l'), axis=0) self_faceVertexIDs = MA.masked_values(self_faceVertexIDs, -1) # want self's Faces for which all faceVertexIDs are in vertexCorrelates self_matchingFaces = numerix.in1d(self_faceVertexIDs, vertexCorrelates[0]).reshape(self_faceVertexIDs.shape).all(axis=0).nonzero()[0] # want other's Faces for which all faceVertexIDs are in vertexCorrelates other_matchingFaces = numerix.in1d(other_faceVertexIDs, vertexCorrelates[1]).reshape(other_faceVertexIDs.shape).all(axis=0).nonzero()[0] # map other's Vertex IDs to new Vertex IDs, # accounting for overlaps with self's Vertex IDs vertex_map = numerix.empty(otherNumVertices, dtype=numerix.INT_DTYPE) verticesToAdd = numerix.delete(numerix.arange(otherNumVertices), vertexCorrelates[1]) vertex_map[verticesToAdd] = numerix.arange(otherNumVertices - len(vertexCorrelates[1])) + selfNumVertices vertex_map[vertexCorrelates[1]] = vertexCorrelates[0] # calculate hashes of faceVertexIDs for comparing Faces if self_matchingFaces.shape[-1] == 0: self_faceHash = numerix.empty(self_matchingFaces.shape[:-1] + (0,), dtype="str") else: # sort each of self's Face's vertexIDs for canonical comparison self_faceHash = numerix.sort(self_faceVertexIDs[..., self_matchingFaces], axis=0) # then hash the Faces for comparison (NumPy set operations are only for 1D arrays) self_faceHash = numerix.apply_along_axis(str, axis=0, arr=self_faceHash) face_sort = numerix.argsort(self_faceHash) self_faceHash = self_faceHash[face_sort] self_matchingFaces = self_matchingFaces[face_sort] if other_matchingFaces.shape[-1] == 0: other_faceHash = numerix.empty(other_matchingFaces.shape[:-1] + (0,), dtype="str") else: # convert each of other's Face's vertexIDs to new IDs other_faceHash = vertex_map[other_faceVertexIDs[..., other_matchingFaces]] # sort each of other's Face's vertexIDs for canonical comparison other_faceHash = numerix.sort(other_faceHash, axis=0) # then hash the Faces for comparison (NumPy set operations are only for 1D arrays) other_faceHash = numerix.apply_along_axis(str, axis=0, arr=other_faceHash) face_sort = numerix.argsort(other_faceHash) other_faceHash = other_faceHash[face_sort] other_matchingFaces = other_matchingFaces[face_sort] self_matchingFaces = self_matchingFaces[numerix.in1d(self_faceHash, other_faceHash)] other_matchingFaces = other_matchingFaces[numerix.in1d(other_faceHash, self_faceHash)] faceCorrelates = numerix.array((self_matchingFaces, other_matchingFaces)) # warn if meshes don't touch, but allow it if (selfc.numberOfFaces > 0 and otherc.numberOfFaces > 0 and faceCorrelates.shape[-1] == 0): import warnings warnings.warn("Faces are not aligned", UserWarning, stacklevel=4) # map other's Face IDs to new Face IDs, # accounting for overlaps with self's Face IDs face_map = numerix.empty(otherNumFaces, dtype=numerix.INT_DTYPE) facesToAdd = numerix.delete(numerix.arange(otherNumFaces), faceCorrelates[1]) face_map[facesToAdd] = numerix.arange(otherNumFaces - len(faceCorrelates[1])) + selfNumFaces face_map[faceCorrelates[1]] = faceCorrelates[0] other_faceVertexIDs = vertex_map[otherc.faceVertexIDs[..., facesToAdd]] # ensure that both sets of cellFaceIDs have the same maximum number of (masked) elements self_cellFaceIDs = selfc.cellFaceIDs other_cellFaceIDs = face_map[otherc.cellFaceIDs] diff = self_cellFaceIDs.shape[0] - other_cellFaceIDs.shape[0] if diff > 0: other_cellFaceIDs = numerix.append(other_cellFaceIDs, -1 * numerix.ones((diff,) + other_cellFaceIDs.shape[1:], 'l'), axis=0) other_cellFaceIDs = MA.masked_values(other_cellFaceIDs, -1) elif diff < 0: self_cellFaceIDs = numerix.append(self_cellFaceIDs, -1 * numerix.ones((-diff,) + self_cellFaceIDs.shape[1:], 'l'), axis=0) self_cellFaceIDs = MA.masked_values(self_cellFaceIDs, -1) # concatenate everything and return return { 'vertexCoords': numerix.concatenate((selfc.vertexCoords, otherc.vertexCoords[..., verticesToAdd]), axis=1), 'faceVertexIDs': numerix.concatenate((self_faceVertexIDs, other_faceVertexIDs), axis=1), 'cellFaceIDs': MA.concatenate((self_cellFaceIDs, other_cellFaceIDs), axis=1) }
def _getAddedMeshValues(self, other, smallNumber): """ Returns a `dictionary` with 3 elements: the new mesh vertexCoords, faceVertexIDs, and cellFaceIDs. """ other = other._getConcatenableMesh() selfNumFaces = self.faceVertexIDs.shape[-1] selfNumVertices = self.vertexCoords.shape[-1] otherNumFaces = other.faceVertexIDs.shape[-1] otherNumVertices = other.vertexCoords.shape[-1] ## check dimensions if(self.vertexCoords.shape[0] != other.vertexCoords.shape[0]): raise MeshAdditionError, "Dimensions do not match" ## compute vertex correlates vertexCorrelates = {} for i in range(selfNumVertices): for j in range(otherNumVertices): diff = self.vertexCoords[...,i] - other.vertexCoords[...,j] diff = numerix.array(diff) if (sum(diff ** 2) < smallNumber): vertexCorrelates[j] = i if (self._getNumberOfVertices() > 0 and other._getNumberOfVertices() > 0 and vertexCorrelates == {}): raise MeshAdditionError, "Vertices are not aligned" ## compute face correlates faceCorrelates = {} for i in range(otherNumFaces): ## Seems to be overwriting other.faceVertexIDs with new numpy ## currFace = other.faceVertexIDs[i] ## currFace = other.faceVertexIDs[...,i].copy() ## Changed this again as numpy 1.0.4 seems to have no copy method for ## masked arrays. try: currFace = other.faceVertexIDs[...,i].copy() except: currFace = MA.array(other.faceVertexIDs[...,i], mask=MA.getmask(other.faceVertexIDs[...,i])) keepGoing = 1 currIndex = 0 for item in currFace: if(vertexCorrelates.has_key(item)): currFace[currIndex] = vertexCorrelates[item] currIndex = currIndex + 1 else: keepGoing = 0 if(keepGoing == 1): for j in range(selfNumFaces): if (self._equalExceptOrder(currFace, self.faceVertexIDs[...,j])): faceCorrelates[i] = j if (self._getNumberOfFaces() > 0 and other._getNumberOfFaces() > 0 and faceCorrelates == {}): raise MeshAdditionError, "Faces are not aligned" faceIndicesToAdd = () for i in range(otherNumFaces): if(not faceCorrelates.has_key(i)): faceIndicesToAdd = faceIndicesToAdd + (i,) vertexIndicesToAdd = () for i in range(otherNumVertices): if(not vertexCorrelates.has_key(i)): vertexIndicesToAdd = vertexIndicesToAdd + (i,) ##compute the full face and vertex correlation list a = selfNumFaces for i in faceIndicesToAdd: faceCorrelates[i] = a a = a + 1 b = selfNumVertices for i in vertexIndicesToAdd: vertexCorrelates[i] = b b = b + 1 ## compute what the cells are that we need to add cellsToAdd = numerix.ones((self.cellFaceIDs.shape[0], other.cellFaceIDs.shape[-1])) cellsToAdd = -1 * cellsToAdd for j in range(other.cellFaceIDs.shape[-1]): for i in range(other.cellFaceIDs.shape[0]): cellsToAdd[i, j] = faceCorrelates[other.cellFaceIDs[i, j]] cellsToAdd = MA.masked_values(cellsToAdd, -1) ## compute what the faces are that we need to add facesToAdd = numerix.take(other.faceVertexIDs, faceIndicesToAdd, axis=1) for j in range(facesToAdd.shape[-1]): for i in range(facesToAdd.shape[0]): facesToAdd[i, j] = vertexCorrelates[facesToAdd[i, j]] ## compute what the vertices are that we need to add verticesToAdd = numerix.take(other.vertexCoords, vertexIndicesToAdd, axis=1) return { 'vertexCoords': numerix.concatenate((self.vertexCoords, verticesToAdd), axis=1), 'faceVertexIDs': numerix.concatenate((self.faceVertexIDs, facesToAdd), axis=1), 'cellFaceIDs': MA.concatenate((self.cellFaceIDs, cellsToAdd), axis=1) }
def _getAddedMeshValues(self, other, resolution=1e-2): """Calculate the parameters to define a concatenation of `other` with `self` :Parameters: - `other`: The :class:`~fipy.meshes.numMesh.Mesh` to concatenate with `self` - `resolution`: How close vertices have to be (relative to the smallest cell-to-cell distance in either mesh) to be considered the same :Returns: A `dict` with 3 elements: the new mesh vertexCoords, faceVertexIDs, and cellFaceIDs. """ selfc = self._getConcatenableMesh() other = other._getConcatenableMesh() selfNumFaces = selfc.faceVertexIDs.shape[-1] selfNumVertices = selfc.vertexCoords.shape[-1] otherNumFaces = other.faceVertexIDs.shape[-1] otherNumVertices = other.vertexCoords.shape[-1] ## check dimensions if(selfc.vertexCoords.shape[0] != other.vertexCoords.shape[0]): raise MeshAdditionError, "Dimensions do not match" ## compute vertex correlates ## only try to match exterior (X) vertices self_Xvertices = numerix.unique(selfc._getFaceVertexIDs().filled()[..., selfc.getExteriorFaces().getValue()].flatten()) other_Xvertices = numerix.unique(other._getFaceVertexIDs().filled()[..., other.getExteriorFaces().getValue()].flatten()) self_XvertexCoords = selfc.vertexCoords[..., self_Xvertices] other_XvertexCoords = other.vertexCoords[..., other_Xvertices] # lifted from Mesh._getNearestCellID() other_vertexCoordMap = numerix.resize(other_XvertexCoords, (self_XvertexCoords.shape[-1], other_XvertexCoords.shape[0], other_XvertexCoords.shape[-1])).swapaxes(0,1) tmp = self_XvertexCoords[..., numerix.newaxis] - other_vertexCoordMap closest = numerix.argmin(numerix.dot(tmp, tmp), axis=0) # just because they're closest, doesn't mean they're close tmp = self_XvertexCoords[..., closest] - other_XvertexCoords distance = numerix.sqrtDot(tmp, tmp) # only want vertex pairs that are 100x closer than the smallest # cell-to-cell distance close = distance < resolution * min(selfc._getCellToCellDistances().min(), other._getCellToCellDistances().min()) vertexCorrelates = numerix.array((self_Xvertices[closest[close]], other_Xvertices[close])) # warn if meshes don't touch, but allow it if (selfc._getNumberOfVertices() > 0 and other._getNumberOfVertices() > 0 and vertexCorrelates.shape[-1] == 0): import warnings warnings.warn("Vertices are not aligned", UserWarning, stacklevel=4) ## compute face correlates # ensure that both sets of faceVertexIDs have the same maximum number of (masked) elements self_faceVertexIDs = selfc.faceVertexIDs other_faceVertexIDs = other.faceVertexIDs diff = self_faceVertexIDs.shape[0] - other_faceVertexIDs.shape[0] if diff > 0: other_faceVertexIDs = numerix.append(other_faceVertexIDs, -1 * numerix.ones((diff,) + other_faceVertexIDs.shape[1:]), axis=0) other_faceVertexIDs = MA.masked_values(other_faceVertexIDs, -1) elif diff < 0: self_faceVertexIDs = numerix.append(self_faceVertexIDs, -1 * numerix.ones((-diff,) + self_faceVertexIDs.shape[1:]), axis=0) self_faceVertexIDs = MA.masked_values(self_faceVertexIDs, -1) # want self's Faces for which all faceVertexIDs are in vertexCorrelates self_matchingFaces = numerix.in1d(self_faceVertexIDs, vertexCorrelates[0]).reshape(self_faceVertexIDs.shape).all(axis=0).nonzero()[0] # want other's Faces for which all faceVertexIDs are in vertexCorrelates other_matchingFaces = numerix.in1d(other_faceVertexIDs, vertexCorrelates[1]).reshape(other_faceVertexIDs.shape).all(axis=0).nonzero()[0] # map other's Vertex IDs to new Vertex IDs, # accounting for overlaps with self's Vertex IDs vertex_map = numerix.empty(otherNumVertices, dtype=int) verticesToAdd = numerix.delete(numerix.arange(otherNumVertices), vertexCorrelates[1]) vertex_map[verticesToAdd] = numerix.arange(otherNumVertices - len(vertexCorrelates[1])) + selfNumVertices vertex_map[vertexCorrelates[1]] = vertexCorrelates[0] # calculate hashes of faceVertexIDs for comparing Faces if self_matchingFaces.shape[-1] == 0: self_faceHash = numerix.empty(self_matchingFaces.shape[:-1] + (0,), dtype="str") else: # sort each of self's Face's vertexIDs for canonical comparison self_faceHash = numerix.sort(self_faceVertexIDs[..., self_matchingFaces], axis=0) # then hash the Faces for comparison (NumPy set operations are only for 1D arrays) self_faceHash = numerix.apply_along_axis(str, axis=0, arr=self_faceHash) face_sort = numerix.argsort(self_faceHash) self_faceHash = self_faceHash[face_sort] self_matchingFaces = self_matchingFaces[face_sort] if other_matchingFaces.shape[-1] == 0: other_faceHash = numerix.empty(other_matchingFaces.shape[:-1] + (0,), dtype="str") else: # convert each of other's Face's vertexIDs to new IDs other_faceHash = vertex_map[other_faceVertexIDs[..., other_matchingFaces]] # sort each of other's Face's vertexIDs for canonical comparison other_faceHash = numerix.sort(other_faceHash, axis=0) # then hash the Faces for comparison (NumPy set operations are only for 1D arrays) other_faceHash = numerix.apply_along_axis(str, axis=0, arr=other_faceHash) face_sort = numerix.argsort(other_faceHash) other_faceHash = other_faceHash[face_sort] other_matchingFaces = other_matchingFaces[face_sort] self_matchingFaces = self_matchingFaces[numerix.in1d(self_faceHash, other_faceHash)] other_matchingFaces = other_matchingFaces[numerix.in1d(other_faceHash, self_faceHash)] faceCorrelates = numerix.array((self_matchingFaces, other_matchingFaces)) # warn if meshes don't touch, but allow it if (selfc._getNumberOfFaces() > 0 and other._getNumberOfFaces() > 0 and faceCorrelates.shape[-1] == 0): import warnings warnings.warn("Faces are not aligned", UserWarning, stacklevel=4) # map other's Face IDs to new Face IDs, # accounting for overlaps with self's Face IDs face_map = numerix.empty(otherNumFaces, dtype=int) facesToAdd = numerix.delete(numerix.arange(otherNumFaces), faceCorrelates[1]) face_map[facesToAdd] = numerix.arange(otherNumFaces - len(faceCorrelates[1])) + selfNumFaces face_map[faceCorrelates[1]] = faceCorrelates[0] other_faceVertexIDs = vertex_map[other.faceVertexIDs[..., facesToAdd]] # ensure that both sets of cellFaceIDs have the same maximum number of (masked) elements self_cellFaceIDs = selfc.cellFaceIDs other_cellFaceIDs = face_map[other.cellFaceIDs] diff = self_cellFaceIDs.shape[0] - other_cellFaceIDs.shape[0] if diff > 0: other_cellFaceIDs = numerix.append(other_cellFaceIDs, -1 * numerix.ones((diff,) + other_cellFaceIDs.shape[1:]), axis=0) other_cellFaceIDs = MA.masked_values(other_cellFaceIDs, -1) elif diff < 0: self_cellFaceIDs = numerix.append(self_cellFaceIDs, -1 * numerix.ones((-diff,) + self_cellFaceIDs.shape[1:]), axis=0) self_cellFaceIDs = MA.masked_values(self_cellFaceIDs, -1) # concatenate everything and return return { 'vertexCoords': numerix.concatenate((selfc.vertexCoords, other.vertexCoords[..., verticesToAdd]), axis=1), 'faceVertexIDs': numerix.concatenate((self_faceVertexIDs, other_faceVertexIDs), axis=1), 'cellFaceIDs': MA.concatenate((self_cellFaceIDs, other_cellFaceIDs), axis=1) }
def mp2mesh(self, segs, TairK=293 ): #TODO: adapt to make more time efficient. do it in c++? """ Converts a mappedPlant into a network of 1D grids outputs: creates mesh and stores it in self.mesh fills self.phi => allows for visualization of the mesh with vtk""" self.TairK = TairK nodes = self.get_nodes() #cells = [[bottom 1], [top 1], [bottom 2], [top 2]] #bottom 1 = x_node: link to segment bellow or parent seg bellow #top 1: y_node: link to segment above #bottom 2: x_node: link to child bellow or parent cell above #top 2: y_node: link to child above #only bottom 1 and top 1 are used to define cellCenter for segnum, seg in enumerate(segs): #go through each organ seg = np.array( list(map(lambda x: np.array(x), seg)) ) # converts the list of Vector3d to a numpy array. shape: (num_nodes, 3) if segnum == 0: #basal root bot1 = np.array( [s for s in range(len(seg) - 1)], dtype=np.int64) #nodes put back in oder after growth? top1 = np.array([s for s in range(1, len(seg)) ]) #nodes put back in oder after growth? bot2 = np.full(len(seg) - 1, -1) top2ID = np.array([]) elif np.where(np.all(nodes == seg[0], axis=1))[0][0] == 0: #main stem start = max(top1) + 1 #max val of nde instead of len seg bot1 = np.concatenate( (bot1, np.array([0]), np.array([s + start for s in range(0, len(seg) - 2)], dtype=np.int64) )) #nodes put back in oder after growth? top1 = np.concatenate( (top1, np.array([s + start for s in range(0, len(seg) - 1) ]))) #nodes put back in oder after growth? bot2 = np.concatenate((bot2, np.full(len(seg) - 1, -1))) else: #lateral start = max(top1) + 1 bot1 = np.concatenate( (bot1, np.array([start]), np.array([s + start for s in range(2, len(seg))], dtype=np.int64) )) #nodes put back in oder after growth? top1 = np.concatenate( (top1, np.array([s + start for s in range(2, len(seg) + 1) ]))) #nodes put back in oder after growth? top2ID = np.concatenate((top2ID, [start])) bot2 = np.concatenate( (bot2, [start + 1], np.full(len(seg) - 2, -1))) oldbot1 = np.concatenate([ np.array( list( map( lambda x: np.where(np.all(nodes == np.array(x), axis=1) )[0][0], segs[i])))[:-1] for i in range(len(segs)) ]) oldtop1 = np.concatenate([ np.array( list( map( lambda x: np.where(np.all(nodes == np.array(x), axis=1) )[0][0], segs[i])))[1:] for i in range(len(segs)) ]) oldbot2 = oldbot1[np.where(bot2 >= 0)[0]] newIDS = np.concatenate((bot1, top1, bot2[np.where(bot2 >= 0)[0]])) oldIDS = np.concatenate((oldbot1, oldtop1, oldbot2)) self.new2oldNodeID = dict(zip(newIDS, oldIDS)) oldIDSu = np.array(list(set(oldIDS))) newIDS = [ np.array(list(set(newIDS[np.where(oldIDS == ui)[0]]))) for ui in oldIDSu ] self.old2newNodeID = dict(zip(oldIDSu, newIDS)) self.orgID = np.concatenate([ np.full(len(seg) - 1, segnum) for segnum, seg in enumerate(segs) ]) # organ id for each cell faces = np.array((np.arange(0, max(top1) + 1), ), dtype=np.int64) #index of verticies on each face nodes_x_coord = [nodes[self.new2oldNodeID[ni]][0] for ni in faces[0]] nodes_y_coord = [nodes[self.new2oldNodeID[ni]][1] for ni in faces[0]] nodes_z_coord = [nodes[self.new2oldNodeID[ni]][2] for ni in faces[0]] vertices = np.vstack((nodes_x_coord, nodes_y_coord, nodes_z_coord)) #change how coords are stored top2 = np.full(len(bot1), -1) top2Idx = np.where([ sum(oldbot1 == t1) > 1 for t1 in oldtop1 ])[0] #np.where(oldtop1== b1)#np.concatenate((top2Idx,np.where())) top2[top2Idx] = top2ID bot2[top2Idx + 1] = top2ID + 1 cells = np.vstack((bot1, top1, bot2, top2)) if (not isinstance( self.Px, float)): #get mean rx of the segment (used by GrSink) self.rxCells = np.mean( [[self.Px[self.new2oldNodeID[xi]] for xi in cells[0]], [self.Px[self.new2oldNodeID[xi]] for xi in cells[1]]], axis=0) #rxCell >= rxThrMax -> rxFactor = 1 else: self.rxCells = np.minimum(self.rxThrMax, self.Px) length = np.array([ norm(nodes[self.new2oldNodeID[cells[0][i]]] - nodes[self.new2oldNodeID[cells[1][i]]]) for i in range(len(cells[0])) ]) cells = MA.masked_values(cells, -1) radiiVertices = np.array( [ self.rs.radii[max((self.new2oldNodeID[xi] - 1, 0))] for xi in faces[0] ] ) #radius for each node, seed node take radius of 1st segment of root radiiCells = np.array( [self.rs.radii[self.new2oldNodeID[xi] - 1] for xi in cells[1]]) self.mesh = Mesh1Dmod( radiiVertices=radiiVertices * 1e-2, radiiCells=radiiCells * 1e-2, length=length, vertexCoords=vertices, faceVertexIDs=faces, cellFaceIDs=cells ) #1e-2 to go from radius of segment to radius of phloem #take out radiiCells and length: compute durectly in Mesh1Dmod #store max growth rate and max organ length for computaiton of the CW-limited growth self.orgLength = np.array([ sum(length[np.where(self.orgID == oid)[0]]) for oid in self.orgID ]) organTypes = self.get_organ_types() subTypes = self.get_subtypes() self.orgLengthThr = np.array([ self.rs.organParam[organTypes[self.new2oldNodeID[xi] - 1]] [subTypes[self.new2oldNodeID[xi] - 1] + 2 * (organTypes[self.new2oldNodeID[xi] - 1] == 4)].getParameter( 'lmax') for xi in cells[1] ]) self.maxGrowth = np.array([ self.rs.organParam[organTypes[self.new2oldNodeID[xi] - 1]] [subTypes[self.new2oldNodeID[xi] - 1] + 2 * (organTypes[self.new2oldNodeID[xi] - 1] == 4)].getParameter('r') / (24 * 60 * 60) for xi in cells[1] ]) #maxgrwth rate from cm/d to cm/s self.phi = CellVariablemod(name="solution variable", mesh=self.mesh, value=0., hasOld=True) self.Rm = CellVariablemod(name="solution variable", mesh=self.mesh, value=0., hasOld=True)
def mp2mesh(self, segs, TairK=293): #create an old2newNodeID map? """ Converts a mappedPlant into a network of 1D grids outputs: creates mesh and stores it in self.mesh fills self.phi => allows for visualization of the mesh with vtk""" self.new2oldNodeID = { } #map to get MappedPlant node-ID from grid node-ID self.old2newNodeID = { } #map to get grid node-ID from MappedPlant node-ID self.newCell2organID = {} #for grwth rate evaluation self.organ2oldNodeID = {} #for growth rate evaluation self.organ2newCellID = {} #for growth rate evaluation self.oldNode2organID = {} #for growth rate evaluation self.orgID = np.array([]) self.TairK = TairK vertices = np.array([]) #containes x,y,z coords of each vertex cells = np.array( [[], [], [], []], dtype=np.int64 ) #contains ID of the faces on each cell. here 1D => 1face == 1 vertex #cells = [[bottom 1], [top 1], [bottom 2], [top 2]] #bottom 1 = x_node: link to segment bellow or parent seg bellow #top 1: y_node: link to segment above #bottom 2: x_node: link to child bellow or parent cell above #top 2: y_node: link to child above #only bottom 1 and top 1 are used to define cellCenter nodes = self.get_nodes() newNodeID = 0 organTypes = self.get_organ_types() subTypes = self.get_subtypes() radiiCells = np.array([]) radiiVertices = np.array([]) length = np.array([]) tempOrgLength = np.array([]) newNodeID_prev = -1 nodes_x_coord = np.array( [], dtype=np.float64 ) #np.array([xi[0] for xi in seg], dtype=np.float64) nodes_y_coord = np.array( [], dtype=np.float64 ) # np.array([xi[1] for xi in seg], dtype=np.float64) nodes_z_coord = np.array( [], dtype=np.float64 ) # np.array([xi[2] for xi in seg], dtype=np.float64) self.orgLengthThr = np.array([], dtype=np.float64) self.maxGrowth = np.array([], dtype=np.float64) self.rxCells = np.array([], dtype=np.float64) for segnum, seg in enumerate(segs): #go through each organ length_org = np.array([]) seg = np.array( list(map(lambda x: np.array(x), seg)) ) # converts the list of Vector3d to a numpy array. shape: (num_nodes, 3) for j, n in enumerate(seg): #go through the nodes of the organ oldNodeID = np.where(np.all(nodes == n, axis=1))[0][0] if (oldNodeID == 0 and segnum != 0 ): #do not do it for first node of stem (newnodeId = ) newNodeID_prev = 0 nOld = n continue self.new2oldNodeID[ newNodeID] = oldNodeID #map linking nodes ID between fipy and plant temp = self.old2newNodeID.get( oldNodeID, np.array([], dtype=np.int64) ) #one old node ID might refer ti several new nodes self.old2newNodeID[oldNodeID] = np.append( temp, np.array([newNodeID], dtype=np.int64)) if j > 0: #not first node of organ ot = int(organTypes[oldNodeID - 1]) st = int(subTypes[oldNodeID - 1]) radiiCells = np.concatenate( (radiiCells, [self.rs.radii[oldNodeID - 1]])) self.newCell2organID[ newNodeID] = segnum #map from new ID of y node of segment to organ ID temp = self.organ2newCellID.get( segnum, np.array([], dtype=np.int64)) self.organ2newCellID[segnum] = np.append( temp, np.array([newNodeID], dtype=np.int64)) #store max growth rate and max organ length for computaiton of the CW-limited growth self.orgLengthThr = np.concatenate((self.orgLengthThr, [ self.rs.organParam[ot][st + 2 * (ot == 4)].getParameter('lmax') ])) self.maxGrowth = np.concatenate((self.maxGrowth, [ self.rs.organParam[ot][st + 2 * (ot == 4)].getParameter('r') / (24 * 60 * 60) ])) #maxgrwth rate from cm/d to cm/s if (not isinstance(self.Px, float) ): #get mean rx of the segment (used by GrSink) self.rxCells = np.concatenate( (self.rxCells[self.rxCells < 1], [ np.minimum( self.rxThrMax, np.mean((self.Px[oldNodeID], self.Px[ self.new2oldNodeID[newNodeID_prev]]))) ])) #rxCell >= rxThrMax -> rxFactor = 1 else: self.rxCells = np.minimum(self.rxThrMax, self.Px) length = np.concatenate( (length, [norm(nOld - n) ])) #length of each cell of plant length_org = np.concatenate( (length_org, [norm(nOld - n) ])) #length of cell of the organ if ( segnum == 0 or cells[1][len(cells[1]) - 1] != newNodeID ): #not first cell of lateral stem, lat root or leaf => those cells were already added in previous loop #create cell from curret and previous node cells = np.hstack( (cells, np.array((np.array([newNodeID_prev]), np.array([newNodeID]), np.array([-1]), np.array([-1]))).reshape(4, 1))) elif segnum > 0: #base of organ other tham main root ot = int(organTypes[oldNodeID]) seg_parent = np.where( [self.new2oldNodeID[xi] for xi in cells[1] ] == self.new2oldNodeID[newNodeID])[0][0] #if seg_parent >= 0: #not for base of stem cells[3, seg_parent] = newNodeID #top2 of segment bellow link nodes_x_coord = np.append( nodes_x_coord, n[0] ) #np.array([xi[0] for xi in seg], dtype=np.float64) nodes_y_coord = np.append( nodes_y_coord, n[1] ) # np.array([xi[1] for xi in seg], dtype=np.float64) nodes_z_coord = np.append( nodes_z_coord, n[2] ) # np.array([xi[2] for xi in seg], dtype=np.float64) newNodeID_prev = newNodeID newNodeID += 1 self.new2oldNodeID[newNodeID] = oldNodeID temp = self.old2newNodeID.get(oldNodeID, np.array([], dtype=np.int64)) self.old2newNodeID[oldNodeID] = np.append( temp, np.array([newNodeID], dtype=np.int64)) self.new2oldNodeID[newNodeID] = oldNodeID temp = self.old2newNodeID.get(oldNodeID, np.array([], dtype=np.int64)) self.old2newNodeID[oldNodeID] = np.append( temp, np.array([newNodeID], dtype=np.int64)) seg_parent = np.where( [self.new2oldNodeID[xi] for xi in cells[0] ] == self.new2oldNodeID[newNodeID])[0][0] cells[ 2, seg_parent] = newNodeID #add node to parent seg to link with child branch: bot2 cells = np.hstack( (cells, np.array( (np.array([newNodeID_prev]), np.array([newNodeID + 1]), np.array([newNodeID]), np.array([-1]))).reshape(4, 1))) nodes_x_coord = np.append( nodes_x_coord, n[0]) #np.array([xi[0] for xi in seg], dtype=np.float64) nodes_y_coord = np.append( nodes_y_coord, n[1]) # np.array([xi[1] for xi in seg], dtype=np.float64) nodes_z_coord = np.append( nodes_z_coord, n[2]) # np.array([xi[2] for xi in seg], dtype=np.float64) newNodeID_prev = newNodeID newNodeID += 1 nOld = n self.orgID = np.concatenate( (self.orgID, np.full(len(length_org), segnum))) # organ id for each cell tempOrgLength = np.append(tempOrgLength, sum(length_org)) #length of each organ vertices = np.vstack((nodes_x_coord, nodes_y_coord, nodes_z_coord)) #change how coords are stored self.orgGr = np.full(segnum + 1, 0.) self.orgLength = np.array( [tempOrgLength[self.newCell2organID[xi]] for xi in cells[1]]) self.faces = np.array((np.arange(0, max(cells[1]) + 1), ), dtype=np.int64) #index of verticies on each face cells = MA.masked_values(cells, -1) radiiVertices = np.array( [ self.rs.radii[max((self.new2oldNodeID[xi] - 1, 0))] for xi in self.faces[0] ] ) #radius for each node, seed node take radius of 1st segment of root self.mesh = Mesh1Dmod( radiiVertices=radiiVertices * 1e-2, radiiCells=radiiCells * 1e-2, length=length, vertexCoords=vertices, faceVertexIDs=self.faces, cellFaceIDs=cells ) #1e-2 to go from radius of segment to radius of phloem self.phi = CellVariablemod(name="solution variable", mesh=self.mesh, value=0., hasOld=True)