0

Is there such a function or easy method? The only functions I have found so far are mesh.vertexCoords and mesh.faceVertexIDs but I couldn't figure quit out if they might help me.

mcghgb
  • 25
  • 1
  • 5
  • 1
    Upwards adjacency info (like from vertex to cells) is usually costly to compute and to store. (Remember that for each node, there can be an arbitrary number of cells, but each cell always has a fixed number of nodes (if the mesh is all-triangle, for example).) I wouldn't be surprised if this information doesn't exist in fipy. One usually doesn't need that info either, so perhaps there's a better way of handling that in your case, too. – Nico Schlömer Jan 10 '20 at 12:37

1 Answers1

3

As the comments suggest, the vertex to cell data shouldn't usually be required in a finite volume scheme. However, the following is a solution for finding the vertex to cell IDs given the cell to vertex IDs. The cell to vertex data is available in FiPy with the mesh._cellVertexIDs array.

The following uses sparse matrices to represent the cell to vertex link and then a transpose to find the vertex to cell links.

from fipy import Grid2D
import numpy as np
from scipy.sparse import coo_matrix
import itertools


def lists_to_numpy(x):
    """List of lists of different length to Numpy array. See
    https://stackoverflow.com/questions/38619143/convert-python-sequence-to-numpy-array-filling-missing-values

    >>> print(lists_to_numpy([[0], [0, 1], [0, 1, 2]]))
    array([[ 0, -1, -1],
           [ 0,  1, -1],
           [ 0,  1,  2]])

    """
    return np.array(list(itertools.zip_longest(*x, fillvalue=-1))).T


def invert_sparse_bool(x, mshape):
    """Invert a sparse bool matrix represented by a 2D array and return as
    inverted 2D array.

    >>> a = numpy.array([[0, 2], [1, 3], [0, 3], [3, 4]])
    >>> print(invert_sparse_bool(a, (4, 5)))
    [[ 0  2 -1]
     [ 1 -1 -1]
     [ 0 -1 -1]
     [ 1  2  3]
     [ 3 -1 -1]]

    """
    arr1 = np.indices(x.shape)[0]
    arr2 = np.stack((arr1, x), axis=-1)
    arr3 = np.reshape(arr2, (-1, 2))
    lists = coo_matrix(
        (np.ones(len(arr3), dtype=int),
         (arr3[:, 0], arr3[:, 1])),
        shape=mshape
    ).tolil().T.rows
    return lists_to_numpy(lists)


m = Grid2D(nx=3, ny=3)

cellVertexIDs = m._cellVertexIDs.swapaxes(0, 1)
vertexCellIDs = invert_sparse_bool(
    cellVertexIDs,
    (m.numberOfCells, m.numberOfVertices)
)

print('cellVertexIDs:', m._cellVertexIDs)
print('vertexCellIDs:', vertexCellIDs)

Note that the m._cellVertexIDs are of shape (maxNumberOfVerticesPerCell, numberOfCells), but it's a little easier to implement when they are reshaped. The new vertexCellIDs array are shaped as (numberOfVertices, maxNumberOfCellsPerVertex). The vertexCellIDs do need a fill value as each vertex won't be connected to the same number of cells.

The output from this is

cellVertexIDs: [[ 1  5  4  0]
 [ 2  6  5  1]
 [ 3  7  6  2]
 [ 5  9  8  4]
 [ 6 10  9  5]
 [ 7 11 10  6]
 [ 9 13 12  8]
 [10 14 13  9]
 [11 15 14 10]]
vertexCellIDs: [[ 0 -1 -1 -1]
 [ 0  1 -1 -1]
 [ 1  2 -1 -1]
 [ 2 -1 -1 -1]
 [ 0  3 -1 -1]
 [ 0  1  3  4]
 [ 1  2  4  5]
 [ 2  5 -1 -1]
 [ 3  6 -1 -1]
 [ 3  4  6  7]
 [ 4  5  7  8]
 [ 5  8 -1 -1]
 [ 6 -1 -1 -1]
 [ 6  7 -1 -1]
 [ 7  8 -1 -1]
 [ 8 -1 -1 -1]]

which makes sense to me for a 3x3 mesh with 9 cells and 16 vertices and an ordered numbering system for both cells and vertices (left to right, bottom to top).

wd15
  • 1,068
  • 5
  • 8