Esempio n. 1
0
 def _facesPerCell(self):
     if numerix.MA.is_masked(self.cellFaceIDs):
         facesPerCell = (~numerix.MA.getmask(self.cellFaceIDs)).sum(axis=0)
     else:
         facesPerCell = numerix.empty((self.numberOfCells,), dtype=numerix.INT_DTYPE)
         facesPerCell[:] = self._maxFacesPerCell
     return facesPerCell
Esempio n. 2
0
    def _cellTopology(self):
        """return a map of the topology of each cell of grid"""
        cellTopology = numerix.empty((self.mesh.numberOfCells, ),
                                     dtype=numerix.ubyte)
        cellTopology[:] = self._elementTopology["voxel"]

        return cellTopology
Esempio n. 3
0
 def _facesPerCell(self):
     if numerix.MA.is_masked(self.cellFaceIDs):
         facesPerCell = (~numerix.MA.getmask(self.cellFaceIDs)).sum(axis=0)
     else:
         facesPerCell = numerix.empty((self.numberOfCells,), dtype=numerix.INT_DTYPE)
         facesPerCell[:] = self._maxFacesPerCell
     return facesPerCell
Esempio n. 4
0
    def _unsortedNodesPerFace(self):
        cellFaceVertices = self._cellFaceVertices
        if numerix.MA.is_masked(cellFaceVertices):
            nodesPerFace = (~cellFaceVertices.mask).sum(axis=0)
        else:
            nodesPerFace = numerix.empty(cellFaceVertices.shape[1:], dtype=numerix.INT_DTYPE)
            nodesPerFace[:] = self.faceVertexIDs.shape[0]

        return nodesPerFace
Esempio n. 5
0
    def _unsortedNodesPerFace(self):
        cellFaceVertices = self._cellFaceVertices
        if numerix.MA.is_masked(cellFaceVertices):
            nodesPerFace = (~cellFaceVertices.mask).sum(axis=0)
        else:
            nodesPerFace = numerix.empty(cellFaceVertices.shape[1:], dtype=numerix.INT_DTYPE)
            nodesPerFace[:] = self.faceVertexIDs.shape[0]

        return nodesPerFace
 def _cellTopology(self):
     """return a map of the topology of each cell"""
     cellTopology = numerix.empty((self.mesh.numberOfCells,), dtype=numerix.ubyte)
     
     t = self._elementTopology
     cellTopology[:] = t["polygon"]
     
     facesPerCell = self.mesh._facesPerCell
     cellTopology[facesPerCell == 3] = t["triangle"]
     cellTopology[facesPerCell == 4] = t["quadrangle"]
     
     return cellTopology
Esempio n. 7
0
    def _cellTopology(self):
        """return a map of the topology of each cell"""
        cellTopology = numerix.empty((self.mesh.numberOfCells,), dtype=numerix.ubyte)

        t = self._elementTopology
        cellTopology[:] = t["polygon"]

        facesPerCell = self.mesh._facesPerCell
        cellTopology[facesPerCell == 3] = t["triangle"]
        cellTopology[facesPerCell == 4] = t["quadrangle"]

        return cellTopology
Esempio n. 8
0
 def _getGlobalValue(self, localIDs, globalIDs):
     localValue = self.getValue()
     if self.getMesh().communicator.Nproc > 1:
         if localValue.shape[-1] != 0:
             localValue = localValue[..., localIDs]
         globalIDs = numerix.concatenate(self.getMesh().communicator.allgather(globalIDs))
         
         globalValue = numerix.empty(localValue.shape[:-1] + (max(globalIDs) + 1,), 
                                     dtype=numerix.obj2sctype(localValue))
         globalValue[..., globalIDs] = numerix.concatenate(self.getMesh().communicator.allgather(localValue), axis=-1)
         
         return globalValue
     else:
         return localValue
Esempio n. 9
0
    def setValue(self, value, unit=None, where=None):
        """
        Set the value of the Variable. Can take a masked array.

            >>> a = Variable((1,2,3))
            >>> a.setValue(5, where=(1, 0, 1))
            >>> print a
            [5 2 5]

            >>> b = Variable((4,5,6))
            >>> a.setValue(b, where=(1, 0, 1))
            >>> print a
            [4 2 6]
            >>> print b
            [4 5 6]
            >>> a.setValue(3)
            >>> print a
            [3 3 3]

            >>> b = numerix.array((3,4,5))
            >>> a.setValue(b)
            >>> a[:] = 1
            >>> print b
            [3 4 5]

            >>> a.setValue((4,5,6), where=(1, 0))
            Traceback (most recent call last):
                ....
            ValueError: shape mismatch: objects cannot be broadcast to a single shape
            
        """
        if where is not None:
            tmp = numerix.empty(numerix.getShape(where), self.getsctype())
            tmp[:] = value
            tmp = numerix.where(where, tmp, self.getValue())
        else:
            if hasattr(value, 'copy'):
                tmp = value.copy()
            else:
                tmp = value

        value = self._makeValue(value=tmp, unit=unit, array=None)

        if numerix.getShape(self.value) == ():
            self.value.itemset(value)
        else:
            self.value[:] = value
            
        self._markFresh()
Esempio n. 10
0
    def __mul__(self, other):
        """
        Multiply a sparse matrix by another sparse matrix

            >>> L1 = _PysparseMatrixFromShape(rows=3, cols=3)
            >>> L1.put([3.,10.,numerix.pi,2.5], [0,0,1,2], [2,1,1,0])
            >>> L2 = _PysparseIdentityMatrix(size=3)
            >>> L2.put([4.38,12357.2,1.1], [2,1,0], [1,0,2])

            >>> tmp = numerix.array(((1.23572000e+05, 2.31400000e+01, 3.00000000e+00),
            ...                      (3.88212887e+04, 3.14159265e+00, 0.00000000e+00),
            ...                      (2.50000000e+00, 0.00000000e+00, 2.75000000e+00)))

            >>> numerix.allclose((L1 * L2).numpyArray, tmp)
            1

        or a sparse matrix by a vector

            >>> tmp = numerix.array((29., 6.28318531, 2.5))
            >>> numerix.allclose(L1 * numerix.array((1,2,3),'d'), tmp)
            1

        or a vector by a sparse matrix

            >>> tmp = numerix.array((7.5, 16.28318531,  3.))
            >>> numerix.allclose(numerix.array((1,2,3),'d') * L1, tmp) ## The multiplication is broken. Numpy is calling __rmul__ for every element instead of with  the whole array.
            1


        """
        N = self.matrix.shape[1]

        if isinstance(other, _PysparseMatrix):
            return _PysparseMatrix(
                matrix=spmatrix.matrixmultiply(self.matrix, other.matrix))
        else:
            shape = numerix.shape(other)
            if shape == ():
                L = spmatrix.ll_mat(N, N, N)
                L.put(other * numerix.ones(N, 'l'))
                return _PysparseMatrix(
                    matrix=spmatrix.matrixmultiply(self.matrix, L))
            elif shape == (N, ):
                y = numerix.empty((self.matrix.shape[0], ))
                self.matrix.matvec(other, y)
                return y
            else:
                raise TypeError
Esempio n. 11
0
    def _getGlobalValue(self, localIDs, globalIDs):
        localValue = self.value
        if self.mesh.communicator.Nproc > 1:
            if localValue.shape[-1] != 0:
                localValue = localValue[..., localIDs]
            globalIDs = numerix.concatenate(
                self.mesh.communicator.allgather(globalIDs))

            globalValue = numerix.empty(localValue.shape[:-1] +
                                        (max(globalIDs) + 1, ),
                                        dtype=numerix.obj2sctype(localValue))
            globalValue[..., globalIDs] = numerix.concatenate(
                self.mesh.communicator.allgather(localValue), axis=-1)

            return globalValue
        else:
            return localValue
Esempio n. 12
0
    def __mul__(self, other):
        """
        Multiply a sparse matrix by another sparse matrix

            >>> L1 = _PysparseMatrixFromShape(rows=3, cols=3)
            >>> L1.put([3., 10., numerix.pi, 2.5], [0, 0, 1, 2], [2, 1, 1, 0])
            >>> L2 = _PysparseIdentityMatrix(size=3)
            >>> L2.put([4.38, 12357.2, 1.1], [2, 1, 0], [1, 0, 2])

            >>> tmp = numerix.array(((1.23572000e+05, 2.31400000e+01, 3.00000000e+00),
            ...                      (3.88212887e+04, 3.14159265e+00, 0.00000000e+00),
            ...                      (2.50000000e+00, 0.00000000e+00, 2.75000000e+00)))

            >>> numerix.allclose((L1 * L2).numpyArray, tmp)
            1

        or a sparse matrix by a vector

            >>> tmp = numerix.array((29., 6.28318531, 2.5))
            >>> numerix.allclose(L1 * numerix.array((1, 2, 3), 'd'), tmp)
            1

        or a vector by a sparse matrix

            >>> tmp = numerix.array((7.5, 16.28318531,  3.))
            >>> numerix.allclose(numerix.array((1, 2, 3), 'd') * L1, tmp) ## The multiplication is broken. Numpy is calling __rmul__ for every element instead of with  the whole array.
            1


        """
        N = self.matrix.shape[1]

        if isinstance(other, _PysparseMatrix):
            return _PysparseMatrix(matrix=spmatrix.matrixmultiply(self.matrix, other.matrix))
        else:
            shape = numerix.shape(other)
            if shape == ():
                L = spmatrix.ll_mat(N, N, N)
                L.put(other * numerix.ones(N, 'l'))
                return _PysparseMatrix(matrix=spmatrix.matrixmultiply(self.matrix, L))
            elif shape == (N,):
                y = numerix.empty((self.matrix.shape[0],))
                self.matrix.matvec(other, y)
                return y
            else:
                raise TypeError
Esempio n. 13
0
 def _getGlobalValue(self, localIDs, globalIDs):
     from fipy.tools import parallel
     localValue = self.getValue()
     if parallel.Nproc > 1:
         from mpi4py import MPI
         comm = MPI.COMM_WORLD
         if localValue.shape[-1] != 0:
             localValue = localValue[..., localIDs]
         globalIDs = numerix.concatenate(comm.allgather(globalIDs))
         
         globalValue = numerix.empty(localValue.shape[:-1] + (max(globalIDs) + 1,), 
                                     dtype=numerix.obj2sctype(localValue))
         globalValue[..., globalIDs] = numerix.concatenate(comm.allgather(localValue), axis=-1)
         
         return globalValue
     else:
         return localValue
Esempio n. 14
0
    def _maxminparallel_(self, a, axis, default, fn, fnParallel):
        a = a[..., self._localNonOverlappingIDs]

        if numerix.multiply.reduce(a.shape) == 0:
            if axis is None:
                opShape = ()
            else:
                opShape = self.shape[:axis] + self.shape[axis + 1:]

            if len(opShape) == 0:
                nodeVal = default
            else:
                nodeVal = numerix.empty(opShape)
                nodeVal[:] = default
        else:
            nodeVal = fn(axis=axis)

        return fnParallel(nodeVal)
Esempio n. 15
0
 def _maxminparallel_(self, a, axis, default, fn, fnParallel):
     a = a[self._getLocalNonOverlappingIDs()]
     
     if numerix.multiply.reduce(a.shape) == 0:
         if axis is None:
             opShape = ()
         else:
             opShape=self.shape[:axis] + self.shape[axis+1:]
             
         if len(opShape) == 0:
             nodeVal = default
         else:
             nodeVal = numerix.empty(opShape)
             nodeVal[:] = default
     else:
         nodeVal = fn(axis=axis)
     
     return fnParallel(nodeVal)
Esempio n. 16
0
    def _petsc2fipyGhost(self, vec):
        """Convert a PETSc `GhostVec` to a FiPy Variable (form)
        
        Moves the ghosts from the end, as necessary. 
        The return Variable may be coupled/vector and so moving the ghosts
        is a bit subtle.
        
        Given an 8-element `GhostVec` `vj`
        
        ```
        v0 v1 v2 v3 (v4) (v6)   [4, 6]  processor 0
        v4 v5 v6 v7 (v1) (v3)   [1, 3]  processor 1
        ```
        
        where j is the global index and the `[a, b]` are the global ghost
        indices. Elements in () are ghosted

        We end up with the (2x4) FiPy Variable
        
        ```
        v0  v1 (v4)        processor 0
        v2  v3 (v6)
        
           (v1) v4 v4      processor 1
           (v3) v6 v7
        ```
        """
        N = len(self.mesh._globalOverlappingCellIDs)
        M = self.numberOfEquations
        var = numerix.empty((M, N))
        bodies = numerix.array(vec)
        if M > 1:
            bodies = numerix.reshape(bodies, (M, -1))
        var[..., self._bodies] = bodies
        vec.ghostUpdate()
        with vec.localForm() as lf:
            if len(self._ghosts) > 0:
                ids = numerix.arange(-len(self._ghosts), 0)
                ghosts = numerix.reshape(numerix.array(lf)[ids], (M, -1))
                var[..., ~self._bodies] = ghosts

        return var.flatten()
Esempio n. 17
0
    def _cellTopology(self):
        """return a map of the topology of each cell"""
        facesPerCell = self.mesh._facesPerCell
        nodesPerFace = self.mesh._nodesPerFace

        def faceCountsMatch(targetCounts):
            if len(targetCounts) > nodesPerFace.shape[0]:
                # pad nodesPerFace with zeros
                paddedNodesPerFace = numerix.zeros((len(targetCounts), nodesPerFace.shape[1]), dtype=numerix.INT_DTYPE)
                paddedNodesPerFace[:nodesPerFace.shape[0],:] = nodesPerFace

                paddedTargetCounts = numerix.array(targetCounts)[..., numerix.newaxis]
            else:
                # pad target face node count with zeros
                paddedTargetCounts = numerix.concatenate((targetCounts,
                                                          [0] * (self.mesh._maxFacesPerCell - len(targetCounts))))
                paddedTargetCounts = paddedTargetCounts[..., numerix.newaxis]

                paddedNodesPerFace = nodesPerFace

            return ((facesPerCell == len(targetCounts))
                    & (paddedNodesPerFace == paddedTargetCounts).all(axis=0))

        cellTopology = numerix.empty((self.mesh.numberOfCells,), dtype=numerix.ubyte)

        t = self._elementTopology

        if self.mesh.dim == 1:
            cellTopology[:] = t["line"]
        elif self.mesh.dim == 2:
            cellTopology[:] = t["polygon"]
            cellTopology[faceCountsMatch([2, 2, 2])] = t["triangle"]
            cellTopology[faceCountsMatch([2, 2, 2, 2])] = t["quadrangle"]
        else:
            cellTopology[:] = t["unknown"]
            cellTopology[faceCountsMatch([3, 3, 3, 3])] = t["tetrahedron"]
            cellTopology[faceCountsMatch([4, 4, 4, 4, 4, 4])] = t["hexahedron"]
            cellTopology[faceCountsMatch([4, 4, 4, 3, 3])] = t["prism"]
            cellTopology[faceCountsMatch([4, 3, 3, 3, 3])] = t["pyramid"]

        return cellTopology
    def _cellTopology(self):
        """return a map of the topology of each cell"""
        facesPerCell = self.mesh._facesPerCell
        nodesPerFace = self.mesh._nodesPerFace
        
        def faceCountsMatch(targetCounts):
            if len(targetCounts) > nodesPerFace.shape[0]:
                # pad nodesPerFace with zeros
                paddedNodesPerFace = numerix.zeros((len(targetCounts), nodesPerFace.shape[1]), dtype=numerix.INT_DTYPE)
                paddedNodesPerFace[:nodesPerFace.shape[0], :] = nodesPerFace
                
                paddedTargetCounts = numerix.array(targetCounts)[..., numerix.newaxis]
            else:
                # pad target face node count with zeros
                paddedTargetCounts = numerix.concatenate((targetCounts,
                                                          [0] * (self.mesh._maxFacesPerCell - len(targetCounts))))
                paddedTargetCounts = paddedTargetCounts[..., numerix.newaxis]
                
                paddedNodesPerFace = nodesPerFace
                
            return ((facesPerCell == len(targetCounts))
                    & (paddedNodesPerFace == paddedTargetCounts).all(axis=0))

        cellTopology = numerix.empty((self.mesh.numberOfCells,), dtype=numerix.ubyte)
        
        t = self._elementTopology
        
        if self.mesh.dim == 1:
            cellTopology[:] = t["line"]
        elif self.mesh.dim == 2:
            cellTopology[:] = t["polygon"]
            cellTopology[faceCountsMatch([2, 2, 2])] = t["triangle"]
            cellTopology[faceCountsMatch([2, 2, 2, 2])] = t["quadrangle"]
        else:
            cellTopology[:] = t["unknown"]
            cellTopology[faceCountsMatch([3, 3, 3, 3])] = t["tetrahedron"]
            cellTopology[faceCountsMatch([4, 4, 4, 4, 4, 4])] = t["hexahedron"]
            cellTopology[faceCountsMatch([4, 4, 4, 3, 3])] = t["prism"]
            cellTopology[faceCountsMatch([4, 3, 3, 3, 3])] = t["pyramid"]
        
        return cellTopology
Esempio n. 19
0
    def _execInline(self, comment=None):
        """
        Gets the stack from _getCstring() which calls _getRepresentation()
        
            >>> (Variable((1,2,3,4)) * Variable((5,6,7,8)))._getCstring()
            '(var0[i] * var1[i])'
            >>> (Variable(((1,2),(3,4))) * Variable(((5,6),(7,8))))._getCstring()
            '(var0[i + j * ni] * var1[i + j * ni])'
            >>> (Variable((1,2)) * Variable((5,6)) * Variable((7,8)))._getCstring()
            '((var00[i] * var01[i]) * var1[i])'

        The following test was implemented due to a problem with
        contiguous arrays.  The `mesh.getCellCenters()[1]` command
        introduces a non-contiguous array into the `Variable` and this
        causes the inline routine to return senseless results.
        
            >>> from fipy import Grid2D, CellVariable
            >>> mesh = Grid2D(dx=1., dy=1., nx=2, ny=2)
            >>> var = CellVariable(mesh=mesh, value=0.)
            >>> Y =  mesh.getCellCenters()[1]
            >>> var.setValue(Y + 1.0)
            >>> print var - Y
            [ 1.  1.  1.  1.]
        """
    
        from fipy.tools import inline
        argDict = {}
        string = self._getCstring(argDict=argDict, freshen=True) + ';'
        
        try:
            shape = self.opShape
        except AttributeError:
            shape = self.shape

        dimensions = len(shape)
            
        if dimensions == 0:
            string = 'result[0] = ' + string
            dim = ()
        else:
            string = 'result' + self._getCIndexString(shape) + ' = ' + string
            ni = self.opShape[-1]
            argDict['ni'] = ni
            if dimensions == 1:
                dim = (ni)
            else:
                nj = self.opShape[-2]
                argDict['nj'] = nj
                if dimensions == 2:
                    dim =(nj,ni)
                elif dimensions == 3:
                    nk = self.opShape[-3]
                    dim = (nk,nj,ni)
                    argDict['nk'] = nk
                else:
                    raise DimensionError, 'Impossible Dimensions'

        ## Following section makes sure that the result array has a
        ## valid typecode. If self.value is None then a typecode is
        ## assigned to the Variable by running the calculation without
        ## inlining. The non-inlined result is thus used the first
        ## time through.

        
        if self.value is None and not hasattr(self, 'typecode'):
            self.canInline = False
            argDict['result'] = self.getValue()
            self.canInline = True
            self.typecode = numerix.obj2sctype(argDict['result'])
        else:
            if self.value is None:
                if self.getsctype() == numerix.bool_:
                    argDict['result'] = numerix.empty(dim, numerix.int8)
                else:
                    argDict['result'] = numerix.empty(dim, self.getsctype())
            else:
                argDict['result'] = self.value

            resultShape = argDict['result'].shape

            if resultShape == ():
                argDict['result'] = numerix.reshape(argDict['result'], (1,))

            inline._runInline(string, converters=None, comment=comment, **argDict)

            if resultShape == ():
                argDict['result'] = numerix.reshape(argDict['result'], resultShape)

        return argDict['result']
Esempio n. 20
0
    def _cellTopology(self):
        """return a map of the topology of each cell of grid"""
        cellTopology = numerix.empty((self.mesh.numberOfCells,), dtype=numerix.ubyte)
        cellTopology[:] = self._elementTopology["line"]

        return cellTopology
Esempio n. 21
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)
            }
Esempio n. 22
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)
            }