Beispiel #1
0
def crop(network, shape, mode='full'):
    r"""
    Removes vertices that lie outside the specifed shape

    Parameters
    ----------
    network : dict
        Dictionary containing ``vert.coords`` and ``edge.conns`` arrays
    shape : array_like
        The [x, y, z] shape of the domain beyond which trimming should be
        applied
    mode : str
        Controls how vertices to be trimmed is determined. Options are:

            * 'full':
                Any vertices lying outside the domain are trimmed
            * 'mixed'
                Vertices with at least one neighbor lying inside the domain
                are kept
    """
    Pdrop = isoutside(network['vert.coords'], shape=shape, thresh=0)
    if mode == 'full':
        network = trim(network=network, pores=np.where(Pdrop)[0])
    elif mode == 'mixed':
        # Find throats connecting internal to external pores
        Ts = np.sum(Pdrop[network['edge.conns']], axis=1) == 1
        # Keep the pores on the ends of these throats
        Pkeep = np.unique(network['edge.conns'][Ts])
        Ps = np.array(list(set(np.where(Pdrop)[0]).difference(set(Pkeep)))).astype(int)
        network = trim(network=network, pores=Ps)
        # Remove throats between these surviving external pores
        Pdrop = isoutside(network['vert.coords'], shape=shape)
        Ts = np.all(Pdrop[network['edge.conns']], axis=1)
        network = trim(network=network, throats=Ts)
        # Lastly label the surviving pores as outside for further processing
        network['vert.outside'] = np.zeros(network['vert.coords'].shape[0], dtype=bool)
        network['vert.outside'][Pdrop] = True
    return network
Beispiel #2
0
    def __init__(self, shape=[1, 1, 1], num_points=None, points=None, **kwargs):
        # Clean-up input points
        points = self._parse_points(shape=shape,
                                    num_points=num_points,
                                    points=points)
        super().__init__(shape=shape, points=points, **kwargs)
        # Initialize network object
        topotools.trim(network=self, pores=self.pores(['voronoi']))
        pop = ['pore.voronoi', 'throat.voronoi', 'throat.interconnect',
               'pore.delaunay', 'throat.delaunay']
        for item in pop:
            del self[item]

        # Trim additional pores that are missed by the parent class's trimming
        Ps = topotools.isoutside(coords=self['pore.coords'], shape=shape)
        topotools.trim(network=self, pores=Ps)
Beispiel #3
0
    def __init__(self, shape=None, num_points=None, **kwargs):
        # Clean-up input points
        points = kwargs.pop('points', None)
        points = self._parse_points(shape=shape,
                                    num_points=num_points,
                                    points=points)
        # Initialize network object
        super().__init__(shape=shape, points=points, **kwargs)
        topotools.trim(network=self, pores=self.pores(['voronoi']))
        pop = ['pore.voronoi', 'throat.voronoi', 'throat.interconnect',
               'pore.delaunay', 'throat.delaunay']
        for item in pop:
            del self[item]

        # Trim additional pores that are missed by the parent class's trimming
        Ps = topotools.isoutside(coords=self['pore.coords'], shape=shape)
        topotools.trim(network=self, pores=Ps)
Beispiel #4
0
    def _trim_external_pores(self, shape):
        r'''
        '''
        # Find all pores within the domain
        Ps = topotools.isoutside(coords=self['pore.coords'], shape=shape)
        self['pore.external'] = False
        self['pore.external'][Ps] = True

        # Find which internal pores are delaunay
        Ps = (~self['pore.external'])*self['pore.delaunay']

        # Find all pores connected to an internal delaunay pore
        Ps = self.find_neighbor_pores(pores=Ps, include_input=True)

        # Mark them all as keepers
        self['pore.keep'] = False
        self['pore.keep'][Ps] = True

        # Trim all bad pores
        topotools.trim(network=self, pores=~self['pore.keep'])

        # Now label boundary pores
        self['pore.boundary'] = False
        self['pore.boundary'] = self['pore.delaunay']*self['pore.external']

        # Label Voronoi pores on boundary
        Ps = self.find_neighbor_pores(pores=self.pores('boundary'))
        Ps = self['pore.voronoi']*self.tomask(pores=Ps)
        self['pore.boundary'][Ps] = True

        # Label Voronoi and interconnect throats on boundary
        self['throat.boundary'] = False
        Ps = self.pores('boundary')
        Ts = self.find_neighbor_throats(pores=Ps, mode='xnor')
        self['throat.boundary'][Ts] = True

        # Trim throats between Delaunay boundary pores
        Ps = self.pores(labels=['boundary', 'delaunay'], mode='xnor')
        Ts = self.find_neighbor_throats(pores=Ps, mode='xnor')
        topotools.trim(network=self, throats=Ts)

        # Move Delaunay boundary pores to centroid of Voronoi facet
        Ps = self.pores(labels=['boundary', 'delaunay'], mode='xnor')
        for P in Ps:
            Ns = self.find_neighbor_pores(pores=P)
            Ns = Ps = self['pore.voronoi']*self.tomask(pores=Ns)
            coords = sp.mean(self['pore.coords'][Ns], axis=0)
            self['pore.coords'][P] = coords

        self['pore.internal'] = ~self['pore.boundary']
        Ps = self.pores('internal')
        Ts = self.find_neighbor_throats(pores=Ps, mode='xnor')
        self['throat.internal'] = False
        self['throat.internal'][Ts] = True

        # Label surface pores and throats between boundary and internal
        Ts = self.throats(['boundary', 'internal'], mode='not')
        self['throat.surface'] = False
        self['throat.surface'][Ts] = True
        surf_pores = self['throat.conns'][Ts].flatten()
        surf_pores = sp.unique(surf_pores[~self['pore.boundary'][surf_pores]])
        self['pore.surface'] = False
        self['pore.surface'][surf_pores] = True
        # Clean-up
        del self['pore.external']
        del self['pore.keep']
Beispiel #5
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