예제 #1
0
    def __init__(self, shape=[1, 1, 1], num_points=None, **kwargs):
        points = kwargs.pop('points', None)
        points = self._parse_points(shape=shape,
                                    num_points=num_points,
                                    points=points)

        # Deal with points that are only 2D...they break tessellations
        if points.shape[1] == 3 and len(sp.unique(points[:, 2])) == 1:
            points = points[:, :2]

        # Perform tessellation
        vor = sptl.Voronoi(points=points)
        self._vor = vor

        # Combine points
        pts_all = sp.vstack((vor.points, vor.vertices))
        Nall = sp.shape(pts_all)[0]

        # Create adjacency matrix in lil format for quick construction
        am = sprs.lil_matrix((Nall, Nall))
        for ridge in vor.ridge_dict.keys():
            # Make Delaunay-to-Delauny connections
            [am.rows[i].extend([ridge[0], ridge[1]]) for i in ridge]
            # Get voronoi vertices for current ridge
            row = vor.ridge_dict[ridge].copy()
            # Index Voronoi vertex numbers by number of delaunay points
            row = [i + vor.npoints for i in row if i > -1]
            # Make Voronoi-to-Delaunay connections
            [am.rows[i].extend(row) for i in ridge]
            # Make Voronoi-to-Voronoi connections
            row.append(row[0])
            [am.rows[row[i]].append(row[i+1]) for i in range(len(row)-1)]

        # Finalize adjacency matrix by assigning data values
        am.data = am.rows  # Values don't matter, only shape, so use 'rows'
        # Convert to COO format for direct acces to row and col
        am = am.tocoo()
        # Extract rows and cols
        conns = sp.vstack((am.row, am.col)).T

        # Convert to sanitized adjacency matrix
        am = topotools.conns_to_am(conns)
        # Finally, retrieve conns back from am
        conns = sp.vstack((am.row, am.col)).T

        # Translate adjacency matrix and points to OpenPNM format
        coords = sp.around(pts_all, decimals=10)
        if coords.shape[1] == 2:  # Make points back into 3D if necessary
            coords = sp.vstack((coords.T, sp.zeros((coords.shape[0], )))).T
        super().__init__(conns=conns, coords=coords, **kwargs)

        # Label all pores and throats by type
        self['pore.delaunay'] = False
        self['pore.delaunay'][0:vor.npoints] = True
        self['pore.voronoi'] = False
        self['pore.voronoi'][vor.npoints:] = True
        # Label throats between Delaunay pores
        self['throat.delaunay'] = False
        Ts = sp.all(self['throat.conns'] < vor.npoints, axis=1)
        self['throat.delaunay'][Ts] = True
        # Label throats between Voronoi pores
        self['throat.voronoi'] = False
        Ts = sp.all(self['throat.conns'] >= vor.npoints, axis=1)
        self['throat.voronoi'][Ts] = True
        # Label throats connecting a Delaunay and a Voronoi pore
        self['throat.interconnect'] = False
        Ts = self.throats(labels=['delaunay', 'voronoi'], mode='not')
        self['throat.interconnect'][Ts] = True

        # Trim all pores that lie outside of the specified domain
        self._trim_external_pores(shape=shape)
        self._label_faces()
예제 #2
0
def voronoi_delaunay_dual(points, shape, crop=False):
    r"""
    Generate a dual Voronoi-Delaunay network from given base points

    Parameters
    ----------
    points : array_like or scalar
        The points to be tessellated.  If a scalar is given a set of points
        of that size is generated.
    shape : array_like
        The size of the domain in which the points lie
    crop : bool, optional (default is ``False``)
        If ``True`` then all points lying beyond the given domain shape will
        be removed

    Returns
    -------
    network : dict
        A dictionary containing 'vert.coords' and 'edge.conns'
    vor : Voronoi object
        The Voronoi tessellation object produced by ``scipy.spatial.Voronoi``
    tri : Delaunay object
        The Delaunay triangulation object produced ``scipy.spatial.Delaunay``

    """
    # Generate a set of base points if number was given
    points = tools.parse_points(points=points, shape=shape)
    mask = ~np.all(points == 0, axis=0)

    # Perform tessellations
    vor = sptl.Voronoi(points=points[:, mask])
    tri = sptl.Delaunay(points=points[:, mask])

    # Combine points
    pts_all = np.vstack((vor.points, vor.vertices))
    Nall = np.shape(pts_all)[0]

    # Create adjacency matrix in lil format for quick construction
    am = sprs.lil_matrix((Nall, Nall))
    for ridge in vor.ridge_dict.keys():
        # Make Delaunay-to-Delaunay connections
        for i in ridge:
            am.rows[i].extend([ridge[0], ridge[1]])
        # Get Voronoi vertices for current ridge
        row = vor.ridge_dict[ridge].copy()
        # Index Voronoi vertex numbers by number of Delaunay points
        row = [i + vor.npoints for i in row if i > -1]
        # Make Voronoi-to-Delaunay connections
        for i in ridge:
            am.rows[i].extend(row)
        # Make Voronoi-to-Voronoi connections
        row.append(row[0])
        for i in range(len(row)-1):
            am.rows[row[i]].append(row[i+1])

    # Finalize adjacency matrix by assigning data values
    am.data = am.rows  # Values don't matter, only shape, so use 'rows'
    # Convert to COO format for direct acces to row and col
    am = am.tocoo()
    # Extract rows and cols
    conns = np.vstack((am.row, am.col)).T

    # Convert to sanitized adjacency matrix
    am = conns_to_am(conns)
    # Finally, retrieve conns back from am
    conns = np.vstack((am.row, am.col)).T

    # Convert coords to 3D by adding col of 0's if necessary
    coords = np.around(pts_all, decimals=10)
    if np.any(mask == False):
        verts = np.zeros([np.shape(coords)[0], 3])
        for i, col in enumerate(np.where(mask)[0]):
            verts[:, col] = coords[:, i]
    else:
        verts = np.copy(coords)

    # Assign coords and conns to network dict
    network = {}
    network['vert.coords'] = verts
    network['edge.conns'] = conns

    # Identify and trim pores outside the domain if requested
    if crop:
        Ps = isoutside(verts, shape=shape)
        network = tools.trim(network=network, vert_ids=np.where(Ps)[0])

    return network, vor, tri