Пример #1
0
    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.)
Пример #2
0
    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.)
Пример #3
0
Файл: mesh.py Проект: regmi/fipy
    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)
Пример #4
0
        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)
Пример #5
0
        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)
Пример #6
0
    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)
            }
Пример #7
0
Файл: mesh.py Проект: regmi/fipy
    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)
            }
Пример #8
0
    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)
            }
Пример #9
0
    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)
Пример #10
0
    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)