Esempio n. 1
0
 def test_check_network_health_one_isolated_cluster(self):
     net = op.network.Cubic(shape=[5, 5, 5])
     Ps = net['pore.coords'][:, 2] == 2.5
     Ps = Ps * (net['pore.coords'][:, 1] > 2.5)
     Ts = net.find_neighbor_throats(pores=Ps, mode='exclusive_or')
     trim(network=net, throats=Ts)
     a = net.project.check_network_health()
     assert len(a['disconnected_pores']) == 10
Esempio n. 2
0
 def test_check_network_health_one_isolated_cluster(self):
     net = op.network.Cubic(shape=[5, 5, 5])
     Ps = net['pore.coords'][:, 2] == 2.5
     Ps = Ps*(net['pore.coords'][:, 1] > 2.5)
     Ts = net.find_neighbor_throats(pores=Ps, mode='exclusive_or')
     trim(network=net, throats=Ts)
     a = net.check_network_health()
     assert len(a['disconnected_clusters']) == 2
     assert len(a['trim_pores']) == 10
Esempio n. 3
0
 def __init__(self, shape=[1, 1, 1], points=None, **kwargs):
     # Clean-up input points
     points = self._parse_points(shape=shape, points=points)
     super().__init__(shape=shape, points=points, **kwargs)
     # Initialize network object
     topotools.trim(network=self, pores=self.pores('delaunay'))
     pop = ['pore.delaunay', 'throat.delaunay', 'throat.interconnect']
     for item in pop:
         del self[item]
Esempio n. 4
0
 def test_check_network_health_isolated_pores(self):
     net = op.network.Cubic(shape=[5, 5, 5])
     Ts = net.find_neighbor_throats(pores=0)
     trim(network=net, throats=Ts)
     a = net.check_network_health()
     assert a['isolated_pores'] == np.array([0])
     trim(network=net, pores=a['trim_pores'])
     a = net.check_network_health()
     assert np.size(a['isolated_pores']) == 0
Esempio n. 5
0
    def __init__(self, template, spacing=[1, 1, 1], **kwargs):

        template = sp.atleast_3d(template)
        super().__init__(shape=template.shape, **kwargs)

        coords = sp.unravel_index(range(template.size), template.shape)
        self['pore.template_coords'] = sp.vstack(coords).T
        self['pore.template_indices'] = self.Ps
        self['pore.drop'] = template.flatten() == 0
        topotools.trim(network=self, pores=self.pores('drop'))
        del self['pore.drop']
Esempio n. 6
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('delaunay'))
     pop = ['pore.delaunay', 'throat.delaunay', 'throat.interconnect']
     for item in pop:
         del self[item]
Esempio n. 7
0
    def __init__(self,
                 num_points=None,
                 points=None,
                 shape=[1, 1, 1],
                 fiber_rad=None,
                 resolution=1e-2,
                 name=None,
                 **kwargs):
        super().__init__(name=name)
        shape = np.array(shape)
        if (len(shape) != 3) or np.any(shape == 0):
            raise Exception('Only 3D, rectangular shapes are supported')
        if fiber_rad is None:
            logger.exception(msg='Please initialize class with a fiber_rad')

        net = DelaunayVoronoiDual(project=self,
                                  num_points=num_points,
                                  points=points,
                                  shape=shape,
                                  name=self.name + '_net',
                                  **kwargs)
        net.fiber_rad = fiber_rad
        net.resolution = resolution
        del_geom = DelaunayGeometry(project=self,
                                    network=net,
                                    pores=net.pores('delaunay'),
                                    throats=net.throats('delaunay'),
                                    name=self.name + '_del')
        VoronoiGeometry(project=self,
                        network=net,
                        pores=net.pores('voronoi'),
                        throats=net.throats('voronoi'),
                        name=self.name + '_vor')
        # Tidy up network
        h = net.check_network_health()
        if len(h['trim_pores']) > 0:
            topotools.trim(network=net, pores=h['trim_pores'])
        # Copy the Delaunay throat diameters to the boundary pores
        Ps = net.pores(['delaunay', 'boundary'], mode='xnor')
        map_Ps = del_geom.map_pores(pores=Ps, origin=net)
        all_Ts = net.find_neighbor_throats(pores=Ps, flatten=False)
        for i, Ts in enumerate(all_Ts):
            Ts = np.asarray(Ts)
            Ts = Ts[net['throat.delaunay'][Ts]]
            if len(Ts) > 0:
                map_Ts = del_geom.map_throats(throats=Ts, origin=net)
                td = del_geom['throat.diameter'][map_Ts]
                ta = del_geom['throat.area'][map_Ts]
                del_geom['pore.diameter'][map_Ps[i]] = td
                del_geom['pore.area'][map_Ps[i]] = ta
        del_geom.regenerate_models(propnames=['throat.equivalent_area'])
Esempio n. 8
0
 def test_trim_throats(self):
     np.random.seed(1)
     pn = op.network.Cubic(shape=[2, 2, 2], spacing=5)
     Ps = pn.pores()[:4]
     Ts1 = pn.find_neighbor_throats(pores=Ps, mode='or')
     geo1 = op.geometry.GenericGeometry(network=pn, pores=Ps, throats=Ts1)
     Ps = pn.pores()[4:]
     Ts2 = pn.find_neighbor_throats(pores=Ps, mode='xnor')
     geo2 = op.geometry.GenericGeometry(network=pn, pores=Ps, throats=Ts2)
     geo1['throat.random'] = np.random.random(geo1.Nt)
     geo2['throat.random'] = np.random.random(geo2.Nt)
     trimmers = pn['throat.random'] < 0.25
     topotools.trim(pn, throats=pn.throats()[trimmers])
     assert ~np.any(pn['throat.random'] < 0.25)
Esempio n. 9
0
 def test_trim_throats(self):
     np.random.seed(1)
     pn = op.network.Cubic(shape=[2, 2, 2], spacing=5)
     Ps = pn.pores()[:4]
     Ts1 = pn.find_neighbor_throats(pores=Ps, mode='or')
     geo1 = op.geometry.GenericGeometry(network=pn, pores=Ps, throats=Ts1)
     Ps = pn.pores()[4:]
     Ts2 = pn.find_neighbor_throats(pores=Ps, mode='xnor')
     geo2 = op.geometry.GenericGeometry(network=pn, pores=Ps, throats=Ts2)
     geo1['throat.random'] = np.random.random(geo1.Nt)
     geo2['throat.random'] = np.random.random(geo2.Nt)
     trimmers = pn['throat.random'] < 0.25
     topotools.trim(pn, throats=pn.throats()[trimmers])
     assert ~np.any(pn['throat.random'] < 0.25)
Esempio n. 10
0
 def __init__(self, template, spacing=[1, 1, 1], **kwargs):
     template = np.atleast_3d(template)
     super().__init__(shape=template.shape, spacing=spacing, **kwargs)
     coords = np.unravel_index(range(template.size), template.shape)
     self['pore.template_coords'] = np.vstack(coords).T
     self['pore.template_indices'] = self.Ps
     topotools.trim(network=self, pores=template.flatten() == 0)
     # Add "internal_surface" label to "fake" surface pores!
     ndims = topotools.dimensionality(self).sum()
     max_neighbors = 6 if ndims == 3 else 4
     num_neighbors = np.diff(self.get_adjacency_matrix(fmt="csr").indptr)
     mask_surface = self["pore.surface"]
     mask_internal_surface = (num_neighbors < max_neighbors) & ~mask_surface
     self.set_label("pore.internal_surface", pores=mask_internal_surface)
Esempio n. 11
0
 def test_check_network_health_isolated_pores_and_clusters(self):
     net = op.network.Cubic(shape=[5, 5, 5])
     # Create first isolated cluster
     Ps = net['pore.coords'][:, 2] == 2.5
     Ps = Ps * (net['pore.coords'][:, 1] > 2.5)
     Ts = net.find_neighbor_throats(pores=Ps, mode='exclusive_or')
     trim(network=net, throats=Ts)
     # Create an isolated pore
     Ts = net.find_neighbor_throats(pores=0)
     trim(network=net, throats=Ts)
     a = net.check_network_health()
     # Ensure trim_pores has right length
     assert len(a['disconnected_pores']) == 11
     # Ensure 0 is listed in trim pores
     assert 0 in a['disconnected_pores']
Esempio n. 12
0
 def test_check_network_health_two_isolated_clusters(self):
     net = op.network.Cubic(shape=[5, 5, 5])
     # Create first isolated cluster
     Ps = net['pore.coords'][:, 2] == 2.5
     Ps = Ps*(net['pore.coords'][:, 1] > 2.5)
     Ts = net.find_neighbor_throats(pores=Ps, mode='exclusive_or')
     trim(network=net, throats=Ts)
     # Create a second isolated cluster
     Ps = net['pore.coords'][:, 2] == 3.5
     Ps = Ps*(net['pore.coords'][:, 1] < 2.5)
     Ts = net.find_neighbor_throats(pores=Ps, mode='exclusive_or')
     trim(network=net, throats=Ts)
     a = net.check_network_health()
     assert len(a['disconnected_clusters']) == 3
     assert len(a['trim_pores']) == 20
Esempio n. 13
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)
Esempio n. 14
0
 def __init__(self, shape, num_points=None, **kwargs):
     # Generate Delaunay tessellation from super class, then trim
     super().__init__(shape=shape, num_points=num_points, **kwargs)
     points = self['pore.coords']
     conns = self['throat.conns']
     # Find centroid of each pair of nodes
     c = points[conns]
     m = (c[:, 0, :] + c[:, 1, :]) / 2
     # Find radius of circle connecting each pair of nodes
     r = np.sqrt(np.sum((c[:, 0, :] - c[:, 1, :])**2, axis=1)) / 2
     # Use KD-Tree to find distance to nearest neighbors
     tree = sptl.cKDTree(points)
     n = tree.query(x=m, k=1)[0]
     # Identify throats whose centroid is not near an unconnected node
     g = np.around(n, decimals=5) == np.around(r, decimals=5)
     trim(self, throats=~g)
Esempio n. 15
0
 def __init__(self, shape, num_points=None, **kwargs):
     # Generate Delaunay tessellation from super class, then trim
     super().__init__(shape=shape, num_points=num_points, **kwargs)
     points = self['pore.coords']
     conns = self['throat.conns']
     # Find centroid of each pair of nodes
     c = points[conns]
     m = (c[:, 0, :] + c[:, 1, :])/2
     # Find radius of circle connecting each pair of nodes
     r = sp.sqrt(sp.sum((c[:, 0, :] - c[:, 1, :])**2, axis=1))/2
     # Use KD-Tree to find distance to nearest neighbors
     tree = sptl.cKDTree(points)
     n = tree.query(x=m, k=1)[0]
     # Identify throats whose centroid is not near an unconnected node
     g = sp.around(n, decimals=5) == sp.around(r, decimals=5)
     trim(self, throats=~g)
Esempio n. 16
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)
Esempio n. 17
0
    def __init__(self, template, spacing=[1, 1, 1], **kwargs):

        template = sp.atleast_3d(template)
        if 'shape' in kwargs:
            del kwargs['shape']
            logger.warning('shape argument ignored, inferred from template')
        super().__init__(shape=template.shape, spacing=spacing, **kwargs)

        coords = sp.unravel_index(range(template.size), template.shape)
        self['pore.template_coords'] = sp.vstack(coords).T
        self['pore.template_indices'] = self.Ps
        self['pore.drop'] = template.flatten() == 0
        topotools.trim(network=self, pores=self.pores('drop'))
        del self['pore.drop']
        # remove labels pertaining to surface pores, then redo post-trim
        self.clear(mode='labels')
        self['pore.internal'] = True
        self['throat.internal'] = True
        topotools.find_surface_pores(self)
Esempio n. 18
0
 def test_check_network_health_isolated_pores_and_clusters(self):
     net = op.network.Cubic(shape=[5, 5, 5])
     # Create first isolated cluster
     Ps = net['pore.coords'][:, 2] == 2.5
     Ps = Ps*(net['pore.coords'][:, 1] > 2.5)
     Ts = net.find_neighbor_throats(pores=Ps, mode='exclusive_or')
     trim(network=net, throats=Ts)
     # Create an isolated pore
     Ts = net.find_neighbor_throats(pores=0)
     trim(network=net, throats=Ts)
     a = net.check_network_health()
     # Ensure pore 0 counts as a cluster
     assert len(a['disconnected_clusters']) == 3
     # Ensure trim_pores has right length
     assert len(a['trim_pores']) == 11
     # Ensure 0 is listed in trim pores
     assert 0 in a['trim_pores']
     # Ensure 0 is also listed as an isolated pore
     assert a['isolated_pores'] == 0
Esempio n. 19
0
def make_1D_net(config):
    sub = "GEOMETRY"
    Nunit = config.getint(sub, "nunit_OneD")
    spacing = config.getfloat(sub, "spacing_OneD")
    pos_tabs = config.getint(sub, "pos_tabs")
    neg_tabs = config.getint(sub, "neg_tabs")
    net = op.network.Cubic([Nunit + 2, 2, 1], spacing)
    net["pore.pos_cc"] = net["pore.front"]
    net["pore.neg_cc"] = net["pore.back"]

    T = net.find_neighbor_throats(net.pores("left"), mode="xnor")
    tt.trim(net, throats=T)
    T = net.find_neighbor_throats(net.pores("right"), mode="xnor")
    tt.trim(net, throats=T)
    pos_cc_Ts = net.find_neighbor_throats(net.pores("pos_cc"), mode="xnor")
    neg_cc_Ts = net.find_neighbor_throats(net.pores("neg_cc"), mode="xnor")

    pos_tab_nodes = net.pores()[net["pore.pos_cc"]][pos_tabs]
    neg_tab_nodes = net.pores()[net["pore.neg_cc"]][neg_tabs]

    net["pore.pos_tab"] = False
    net["pore.neg_tab"] = False
    net["pore.pos_tab"][pos_tab_nodes] = True
    net["pore.neg_tab"][neg_tab_nodes] = True
    net["throat.pos_cc"] = False
    net["throat.neg_cc"] = False
    net["throat.pos_cc"][pos_cc_Ts] = True
    net["throat.neg_cc"][neg_cc_Ts] = True
    net["throat.spm_resistor"] = True
    net["throat.spm_resistor"][pos_cc_Ts] = False
    net["throat.spm_resistor"][neg_cc_Ts] = False
    net["throat.spm_resistor_order"] = -1
    net["throat.spm_resistor_order"][net["throat.spm_resistor"]] = np.arange(
        Nunit)
    net["throat.spm_neg_inner"] = net["throat.spm_resistor"]
    net["pore.free_stream"] = False
    del net["pore.left"]
    del net["pore.right"]
    del net["pore.front"]
    del net["pore.back"]
    del net["pore.internal"]
    del net["pore.surface"]
    del net["throat.internal"]
    del net["throat.surface"]

    phase = op.phases.GenericPhase(network=net)

    geo = op.geometry.GenericGeometry(network=net,
                                      pores=net.Ps,
                                      throats=net.Ts)
    op.physics.GenericPhysics(network=net, phase=phase, geometry=geo)

    net["pore.radial_position"] = net["pore.coords"][:, 0]
    net["pore.arc_index"] = np.indices([Nunit + 2, 2, 1])[0].flatten()
    net["pore.region_id"] = -1
    net["pore.cell_id"] = -1
    net["throat.arc_length"] = spacing
    net["throat.electrode_height"] = spacing
    # placeholder
    net["pore.volume"] = 1.0
    net["throat.area"] = 1.0
    net["throat.length"] = 1.0
    plot_topology(net)
    return net.project, np.cumsum(net["throat.arc_length"])
Esempio n. 20
0
    def load(cls, path, prefix, network=None):
        r"""
        Load data from the \'dat\' files located in specified folder.

        Parameters
        ----------
        path : string
            The full path to the folder containing the set of \'dat\' files.

        prefix : string
            The file name prefix on each file. The data files are stored
            as \<prefix\>_node1.dat.

        network : OpenPNM Network Object
            If given then the data will be loaded on it and returned.  If not
            given, a Network will be created and returned.

        Returns
        -------
        An OpenPNM Project containing a GenericNetwork holding all the data

        """
        from pandas import read_table, DataFrame

        net = {}

        # Parse the link1 file
        path = Path(path)
        filename = Path(path.resolve(), prefix + '_link1.dat')
        with open(filename, mode='r') as f:
            link1 = read_table(filepath_or_buffer=f,
                               header=None,
                               skiprows=1,
                               sep=' ',
                               skipinitialspace=True,
                               index_col=0)
        link1.columns = [
            'throat.pore1', 'throat.pore2', 'throat.radius',
            'throat.shape_factor', 'throat.total_length'
        ]
        # Add link1 props to net
        net['throat.conns'] = np.vstack(
            (link1['throat.pore1'] - 1, link1['throat.pore2'] - 1)).T
        net['throat.conns'] = np.sort(net['throat.conns'], axis=1)
        net['throat.radius'] = np.array(link1['throat.radius'])
        net['throat.shape_factor'] = np.array(link1['throat.shape_factor'])
        net['throat.total_length'] = np.array(link1['throat.total_length'])

        filename = Path(path.resolve(), prefix + '_link2.dat')
        with open(filename, mode='r') as f:
            link2 = read_table(filepath_or_buffer=f,
                               header=None,
                               sep=' ',
                               skipinitialspace=True,
                               index_col=0)
        link2.columns = [
            'throat.pore1', 'throat.pore2', 'throat.pore1_length',
            'throat.pore2_length', 'throat.length', 'throat.volume',
            'throat.clay_volume'
        ]
        # Add link2 props to net
        cl_t = np.array(link2['throat.length'])
        net['throat.length'] = cl_t
        net['throat.conduit_lengths.throat'] = cl_t
        net['throat.volume'] = np.array(link2['throat.volume'])
        cl_p1 = np.array(link2['throat.pore1_length'])
        net['throat.conduit_lengths.pore1'] = cl_p1
        cl_p2 = np.array(link2['throat.pore2_length'])
        net['throat.conduit_lengths.pore2'] = cl_p2
        net['throat.clay_volume'] = np.array(link2['throat.clay_volume'])
        # ---------------------------------------------------------------------
        # Parse the node1 file
        filename = Path(path.resolve(), prefix + '_node1.dat')
        with open(filename, mode='r') as f:
            row_0 = f.readline().split()
            num_lines = int(row_0[0])
            array = sp.ndarray([num_lines, 6])
            for i in range(num_lines):
                row = f.readline()\
                       .replace('\t', ' ').replace('\n', ' ').split()
                array[i, :] = row[0:6]
        node1 = DataFrame(array[:, [1, 2, 3, 4]])
        node1.columns = [
            'pore.x_coord', 'pore.y_coord', 'pore.z_coord',
            'pore.coordination_number'
        ]
        # Add node1 props to net
        net['pore.coords'] = np.vstack(
            (node1['pore.x_coord'], node1['pore.y_coord'],
             node1['pore.z_coord'])).T
        # ---------------------------------------------------------------------
        # Parse the node1 file
        filename = Path(path.resolve(), prefix + '_node2.dat')
        with open(filename, mode='r') as f:
            node2 = read_table(filepath_or_buffer=f,
                               header=None,
                               sep=' ',
                               skipinitialspace=True,
                               index_col=0)
        node2.columns = [
            'pore.volume', 'pore.radius', 'pore.shape_factor',
            'pore.clay_volume'
        ]
        # Add node2 props to net
        net['pore.volume'] = np.array(node2['pore.volume'])
        net['pore.radius'] = np.array(node2['pore.radius'])
        net['pore.shape_factor'] = np.array(node2['pore.shape_factor'])
        net['pore.clay_volume'] = np.array(node2['pore.clay_volume'])
        net['throat.area'] = ((net['throat.radius']**2) /
                              (4.0 * net['throat.shape_factor']))
        net['pore.area'] = ((net['pore.radius']**2) /
                            (4.0 * net['pore.shape_factor']))

        if network is None:
            network = GenericNetwork()
        network = cls._update_network(network=network, net=net)

        # Use OpenPNM Tools to clean up network
        # Trim throats connected to 'inlet' or 'outlet' reservoirs
        trim1 = np.where(np.any(net['throat.conns'] == -1, axis=1))[0]
        # Apply 'outlet' label to these pores
        outlets = network['throat.conns'][trim1, 1]
        network['pore.outlets'] = False
        network['pore.outlets'][outlets] = True
        trim2 = np.where(np.any(net['throat.conns'] == -2, axis=1))[0]
        # Apply 'inlet' label to these pores
        inlets = network['throat.conns'][trim2, 1]
        network['pore.inlets'] = False
        network['pore.inlets'][inlets] = True
        # Now trim the throats
        to_trim = np.hstack([trim1, trim2])
        trim(network=network, throats=to_trim)

        return network.project
Esempio n. 21
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']
Esempio n. 22
0
    def load(cls, path, voxel_size=1, project=None):
        r"""
        Load data from a 3DMA-Rock extracted network.  This format consists of
        two files: 'rockname.np2th' and 'rockname.th2pn'.  They should be
        stored together in a folder which is referred to by the path argument.
        These files are binary and therefore not human readable.

        Parameters
        ----------
        path : string
            The location of the 'np2th' and 'th2np' files. This can be an
            absolute path or relative to the current working directory.

        network : OpenPNM Network Object
            If an Network object is recieved, this method will add new data to
            it but NOT overwrite anything that already exists.  This can be
            used to append data from different sources.

        voxel_size : scalar
            The resolution of the image on which 3DMA-Rock was run, in terms of
            the linear length of eac voxel. The default is 1.  This is used to
            scale the voxel counts to actual dimension. It is recommended that
            this value be in SI units [m] to work well with OpenPNM.

        project : OpenPNM Project object
            A GenericNetwork is created and added to the specified Project.
            If no Project is supplied then one will be created and returned.

        """

        net = {}
        path = Path(path)
        path = path.resolve()
        for file in os.listdir(path):
            if file.endswith(".np2th"):
                np2th_file = os.path.join(path, file)
            elif file.endswith(".th2np"):
                th2np_file = os.path.join(path, file)

        with open(np2th_file, mode='rb') as f:
            [Np, Nt] = np.fromfile(file=f, count=2, dtype='u4')
            net['pore.boundary_type'] = sp.ndarray([
                Np,
            ], int)
            net['throat.conns'] = np.ones([Nt, 2], int) * (-1)
            net['pore.coordination'] = sp.ndarray([
                Np,
            ], int)
            net['pore.ID_number'] = sp.ndarray([
                Np,
            ], int)
            for i in range(0, Np):
                ID = np.fromfile(file=f, count=1, dtype='u4')
                net['pore.ID_number'][i] = ID
                net['pore.boundary_type'][i] = np.fromfile(file=f,
                                                           count=1,
                                                           dtype='u1')
                z = np.fromfile(file=f, count=1, dtype='u4')[0]
                net['pore.coordination'][i] = z
                att_pores = np.fromfile(file=f, count=z, dtype='u4')
                att_throats = np.fromfile(file=f, count=z, dtype='u4')
                for j in range(0, len(att_throats)):
                    t = att_throats[j] - 1
                    p = att_pores[j] - 1
                    net['throat.conns'][t] = [i, p]
            net['throat.conns'] = np.sort(net['throat.conns'], axis=1)
            net['pore.volume'] = np.fromfile(file=f, count=Np, dtype='u4')
            nx = np.fromfile(file=f, count=1, dtype='u4')
            nxy = np.fromfile(file=f, count=1, dtype='u4')
            pos = np.fromfile(file=f, count=Np, dtype='u4')
            ny = nxy / nx
            ni = np.mod(pos, nx)
            nj = np.mod(np.floor(pos / nx), ny)
            nk = np.floor(np.floor(pos / nx) / ny)
            net['pore.coords'] = np.array([ni, nj, nk]).T

        with open(th2np_file, mode='rb') as f:
            Nt = np.fromfile(file=f, count=1, dtype='u4')[0]
            net['throat.area'] = np.ones([
                Nt,
            ], dtype=int) * (-1)
            for i in range(0, Nt):
                ID = np.fromfile(file=f, count=1, dtype='u4')
                net['throat.area'][i] = np.fromfile(file=f,
                                                    count=1,
                                                    dtype='f4')
                # numvox = np.fromfile(file=f, count=1, dtype='u4')
                att_pores = np.fromfile(file=f, count=2, dtype='u4')
            nx = np.fromfile(file=f, count=1, dtype='u4')
            nxy = np.fromfile(file=f, count=1, dtype='u4')
            pos = np.fromfile(file=f, count=Nt, dtype='u4')
            ny = nxy / nx
            ni = np.mod(pos, nx)
            nj = np.mod(np.floor(pos / nx), ny)
            nk = np.floor(np.floor(pos / nx) / ny)
            net['throat.coords'] = np.array([ni, nj, nk]).T
            net['pore.internal'] = net['pore.boundary_type'] == 0

        # Convert voxel area and volume to actual dimensions
        net['throat.area'] = (voxel_size**2) * net['throat.area']
        net['pore.volume'] = (voxel_size**3) * net['pore.volume']

        if project is None:
            project = Project(name=path)
        network = GenericNetwork(project=project)
        network = cls._update_network(network=network, net=net)

        # Trim headless throats before returning
        ind = np.where(network['throat.conns'][:, 0] == -1)[0]
        trim(network=network, throats=ind)

        return project
Esempio n. 23
0
    def import_data(cls,
                    path,
                    node_file="throats_cellsThroatsGraph_Nodes.txt",
                    graph_file="throats_cellsThroatsGraph.txt",
                    voxel_size=None):
        r"""
        Loads network data from an iMorph processed image stack

        Parameters
        ----------
        path : string
            The path of the folder where the subfiles are held

        node_file : string
            The file that describes the pores and throats, the
            default iMorph name is: throats_cellsThroatsGraph_Nodes.txt

        graph_file : string
            The file that describes the connectivity of the network, the
            default iMorph name is: throats_cellsThroatsGraph.txt

        voxel_size : float
            Allows the user to define a voxel size different than what is
            contained in the node_file. The value must be in meters.

        Returns
        -------
        project : list
            An OpenPNM project object containing a network and a geometry
            object.  The geometry-related data are automatically placed on the
            geometry object using the ``Imported`` geometry class.
        """
        path = Path(path)
        node_file = os.path.join(path.resolve(), node_file)
        graph_file = os.path.join(path.resolve(), graph_file)
        # Parsing the nodes file
        with open(node_file, "r") as file:
            Np = np.fromstring(file.readline().rsplit("=")[1],
                               sep="\t",
                               dtype=int)[0]
            vox_size = np.fromstring(
                file.readline().rsplit(")")[1],
                sep="\t",
            )[0]

            # Network always recreated to prevent errors
            network = GenericNetwork(Np=Np, Nt=0)

            # Define expected properies
            network["pore.volume"] = np.nan
            scrap_lines = [file.readline() for line in range(4)]
            while True:
                vals = file.readline().split("\t")
                if len(vals) == 1:
                    break
                network["pore.volume"][int(vals[0])] = float(vals[3])
                if "pore." + vals[2] not in network.labels():
                    network["pore." + vals[2]] = False
                network["pore." + vals[2]][int(vals[0])] = True

        if voxel_size is None:
            voxel_size = vox_size * 1.0e-6  # File stores value in microns

        if voxel_size < 0:
            raise Exception("Error - Voxel size must be specfied in " +
                            "the Nodes file or as a keyword argument.")

        # Parsing the graph file
        with open(graph_file, "r") as file:
            # Define expected properties
            network["pore.coords"] = np.zeros((Np, 3)) * np.nan
            network["pore.types"] = np.nan
            network["pore.color"] = np.nan
            network["pore.radius"] = np.nan
            network["pore.dmax"] = np.nan
            network["pore.node_number"] = np.nan
            # Scan file to get pore coordinate data
            scrap_lines = [file.readline() for line in range(3)]
            line = file.readline()
            xmax = 0.0
            ymax = 0.0
            zmax = 0.0
            node_num = 0
            while line != "connectivity table\n":
                vals = np.fromstring(line, sep="\t")
                xmax = vals[1] if vals[1] > xmax else xmax
                ymax = vals[2] if vals[2] > ymax else ymax
                zmax = vals[3] if vals[3] > zmax else zmax
                network["pore.coords"][int(vals[0]), :] = vals[1:4]
                network["pore.types"][int(vals[0])] = vals[4]
                network["pore.color"][int(vals[0])] = vals[5]
                network["pore.radius"][int(vals[0])] = vals[6]
                network["pore.dmax"][int(vals[0])] = vals[7]
                network["pore.node_number"][int(vals[0])] = node_num
                node_num += 1
                line = file.readline()
            # Scan file to get to connectivity data
            scrap_lines.append(file.readline())  # Skip line
            # Create sparse lil array incrementally build adjacency matrix
            lil = sp.sparse.lil_matrix((Np, Np), dtype=int)
            while True:
                vals = np.fromstring(file.readline(), sep="\t", dtype=int)
                if len(vals) <= 1:
                    break
                lil.rows[vals[0]] = vals[2:].tolist()
                lil.data[vals[0]] = np.ones(vals[1]).tolist()

        # Fixing any negative volumes or distances so they are 1 voxel/micron
        network["pore.volume"][np.where(network["pore.volume"] < 0)[0]] = 1.0
        network["pore.radius"][np.where(network["pore.radius"] < 0)[0]] = 1.0
        network["pore.dmax"][np.where(network["pore.dmax"] < 0)[0]] = 1.0

        # Add adjacency matrix to OpenPNM network
        conns = sp.sparse.triu(lil, k=1, format="coo")
        network.update({"throat.all": np.ones(len(conns.col), dtype=bool)})
        network["throat.conns"] = np.vstack([conns.row, conns.col]).T

        network["pore.to_trim"] = False
        network["pore.to_trim"][network.pores("*throat")] = True
        Ts = network.pores("to_trim")
        new_conns = network.find_neighbor_pores(pores=Ts, flatten=False)
        extend(network=network, throat_conns=new_conns, labels="new_conns")
        for item in network.props("pore"):
            item = item.split(".")[1]
            arr = np.ones_like(network["pore." + item])[0]
            arr = np.tile(A=arr, reps=[network.Nt, 1]) * np.nan
            network["throat." + item] = np.squeeze(arr)
            network["throat." +
                    item][network.throats("new_conns")] = network["pore." +
                                                                  item][Ts]
        trim(network=network, pores=Ts)

        # Setting up boundary pores
        x_coord, y_coord, z_coord = np.hsplit(network["pore.coords"], 3)
        network["pore.front_boundary"] = np.ravel(x_coord == 0)
        network["pore.back_boundary"] = np.ravel(x_coord == xmax)
        network["pore.left_boundary"] = np.ravel(y_coord == 0)
        network["pore.right_boundary"] = np.ravel(y_coord == ymax)
        network["pore.bottom_boundary"] = np.ravel(z_coord == 0)
        network["pore.top_boundary"] = np.ravel(z_coord == zmax)

        # Removing any pores that got classified as a boundary pore but
        # Weren't labled a border_cell_face
        ps = np.where(~np.in1d(network.pores("*_boundary"),
                               network.pores("border_cell_face")))[0]
        ps = network.pores("*_boundary")[ps]
        for side in ["front", "back", "left", "right", "top", "bottom"]:
            network["pore." + side + "_boundary"][ps] = False
        # Setting internal label
        network["pore.internal"] = False
        network["pore.internal"][network.pores("*_boundary",
                                               mode="not")] = True

        # Adding props to border cell face throats and from pores
        Ts = np.where(
            network["throat.conns"][:,
                                    1] > network.pores("border_cell_face")[0] -
            1)[0]
        faces = network["throat.conns"][Ts, 1]
        for item in network.props("pore"):
            item = item.split(".")[1]
            network["throat." + item][Ts] = network["pore." + item][faces]
        network["pore.volume"][faces] = 0.0

        # Applying unit conversions
        # TODO: Determine if radius and dmax are indeed microns and not voxels
        network["pore.coords"] = network["pore.coords"] * 1e-6
        network["pore.radius"] = network["pore.radius"] * 1e-6
        network["pore.dmax"] = network["pore.dmax"] * 1e-6
        network["pore.volume"] = network["pore.volume"] * voxel_size**3
        network["throat.coords"] = network["throat.coords"] * 1e-6
        network["throat.radius"] = network["throat.radius"] * 1e-6
        network["throat.dmax"] = network["throat.dmax"] * 1e-6
        network["throat.volume"] = network["throat.volume"] * voxel_size**3

        return network.project
Esempio n. 24
0
    def load(cls, path,
             node_file="throats_cellsThroatsGraph_Nodes.txt",
             graph_file="throats_cellsThroatsGraph.txt",
             network=None, voxel_size=None, return_geometry=False):
        r"""
        Loads network data from an iMorph processed image stack

        Parameters
        ----------
        path : string
            The path of the folder where the subfiles are held

        node_file : string
            The file that describes the pores and throats, the
            default iMorph name is: throats_cellsThroatsGraph_Nodes.txt

        graph_file : string
            The file that describes the connectivity of the network, the
            default iMorph name is: throats_cellsThroatsGraph.txt

        network : OpenPNM Network Object
            The OpenPNM Network onto which the data should be loaded.  If no
            network is supplied then an empty import network is created and
            returned.

        voxel_size : float
            Allows the user to define a voxel size different than what is
            contained in the node_file. The value must be in meters.

        return_geometry : Boolean
            If True, then all geometrical related properties are removed from
            the Network object and added to a GenericGeometry object.  In this
            case the method returns a tuple containing (network, geometry). If
            False (default) then the returned Network will contain all
            properties that were in the original file.  In this case, the user
            can call the ```split_geometry``` method explicitly to perform the
            separation.

        Returns
        -------
        If no Network object is supplied then one will be created and returned.

        If return_geometry is True, then a tuple is returned containing both
        the network and a geometry object.
        """
        #
        path = Path(path)
        node_file = os.path.join(path.resolve(), node_file)
        graph_file = os.path.join(path.resolve(), graph_file)
        # parsing the nodes file
        with open(node_file, 'r') as file:
            Np = sp.fromstring(file.readline().rsplit('=')[1], sep='\t',
                               dtype=int)[0]
            vox_size = sp.fromstring(file.readline().rsplit(')')[1], sep='\t',)[0]

            # network always recreated to prevent errors
            network = GenericNetwork(Np=Np, Nt=0)

            # Define expected properies
            network['pore.volume'] = sp.nan
            scrap_lines = [file.readline() for line in range(4)]
            while True:
                vals = file.readline().split('\t')
                if len(vals) == 1:
                    break
                network['pore.volume'][int(vals[0])] = float(vals[3])
                if 'pore.'+vals[2] not in network.labels():
                    network['pore.'+vals[2]] = False
                network['pore.'+vals[2]][int(vals[0])] = True

        if voxel_size is None:
            voxel_size = vox_size * 1.0E-6  # file stores value in microns

        if voxel_size < 0:
            raise(Exception('Error - Voxel size must be specfied in ' +
                            'the Nodes file or as a keyword argument.'))

        # parsing the graph file
        with open(graph_file, 'r') as file:
            # Define expected properties
            network['pore.coords'] = sp.zeros((Np, 3))*sp.nan
            network['pore.types'] = sp.nan
            network['pore.color'] = sp.nan
            network['pore.radius'] = sp.nan
            network['pore.dmax'] = sp.nan
            network['pore.node_number'] = sp.nan
            # Scan file to get pore coordinate data
            scrap_lines = [file.readline() for line in range(3)]
            line = file.readline()
            xmax = 0.0
            ymax = 0.0
            zmax = 0.0
            node_num = 0
            while line != 'connectivity table\n':
                vals = sp.fromstring(line, sep='\t')
                xmax = vals[1] if vals[1] > xmax else xmax
                ymax = vals[2] if vals[2] > ymax else ymax
                zmax = vals[3] if vals[3] > zmax else zmax
                network['pore.coords'][int(vals[0]), :] = vals[1:4]
                network['pore.types'][int(vals[0])] = vals[4]
                network['pore.color'][int(vals[0])] = vals[5]
                network['pore.radius'][int(vals[0])] = vals[6]
                network['pore.dmax'][int(vals[0])] = vals[7]
                network['pore.node_number'][int(vals[0])] = node_num
                node_num += 1
                line = file.readline()
            # Scan file to get to connectivity data
            scrap_lines.append(file.readline())  # Skip line
            # Create sparse lil array incrementally build adjacency matrix
            lil = sp.sparse.lil_matrix((Np, Np), dtype=int)
            while True:
                vals = sp.fromstring(file.readline(), sep='\t', dtype=int)
                if len(vals) <= 1:
                    break
                lil.rows[vals[0]] = vals[2:]
                lil.data[vals[0]] = sp.ones(vals[1])

        # fixing any negative volumes or distances so they are 1 voxel/micron
        network['pore.volume'][sp.where(network['pore.volume'] < 0)[0]] = 1.0
        network['pore.radius'][sp.where(network['pore.radius'] < 0)[0]] = 1.0
        network['pore.dmax'][sp.where(network['pore.dmax'] < 0)[0]] = 1.0

        # Add adjacency matrix to OpenPNM network
        conns = sp.sparse.triu(lil, k=1, format='coo')
        network.update({'throat.all': sp.ones(len(conns.col), dtype=bool)})
        network['throat.conns'] = sp.vstack([conns.row, conns.col]).T

        network['pore.to_trim'] = False
        network['pore.to_trim'][network.pores('*throat')] = True
        Ts = network.pores('to_trim')
        new_conns = network.find_neighbor_pores(pores=Ts, flatten=False)
        extend(network=network, throat_conns=new_conns, labels='new_conns')
        for item in network.props('pore'):
            item = item.split('.')[1]
            arr = sp.ones_like(network['pore.'+item])[0]
            arr = sp.tile(A=arr, reps=[network.Nt, 1])*sp.nan
            network['throat.'+item] = sp.squeeze(arr)
            network['throat.'+item][network.throats('new_conns')] = \
                network['pore.'+item][Ts]
        trim(network=network, pores=Ts)

        # setting up boundary pores
        x_coord, y_coord, z_coord = sp.hsplit(network['pore.coords'], 3)
        network['pore.front_boundary'] = sp.ravel(x_coord == 0)
        network['pore.back_boundary'] = sp.ravel(x_coord == xmax)
        network['pore.left_boundary'] = sp.ravel(y_coord == 0)
        network['pore.right_boundary'] = sp.ravel(y_coord == ymax)
        network['pore.bottom_boundary'] = sp.ravel(z_coord == 0)
        network['pore.top_boundary'] = sp.ravel(z_coord == zmax)

        # removing any pores that got classified as a boundary pore but
        # weren't labled a border_cell_face
        ps = sp.where(~sp.in1d(network.pores('*_boundary'),
                               network.pores('border_cell_face')))[0]
        ps = network.pores('*_boundary')[ps]
        for side in ['front', 'back', 'left', 'right', 'top', 'bottom']:
            network['pore.'+side+'_boundary'][ps] = False
        # setting internal label
        network['pore.internal'] = False
        network['pore.internal'][network.pores('*_boundary', mode='not')] = True

        # adding props to border cell face throats and from pores
        Ts = sp.where(network['throat.conns'][:, 1] >
                       network.pores('border_cell_face')[0] - 1)[0]
        faces = network['throat.conns'][Ts, 1]
        for item in network.props('pore'):
            item = item.split('.')[1]
            network['throat.'+item][Ts] = network['pore.'+item][faces]
        network['pore.volume'][faces] = 0.0

        # applying unit conversions
        # TODO: Determine if radius and dmax are indeed microns and not voxels
        network['pore.coords'] = network['pore.coords'] * 1e-6
        network['pore.radius'] = network['pore.radius'] * 1e-6
        network['pore.dmax'] = network['pore.dmax'] * 1e-6
        network['pore.volume'] = network['pore.volume'] * voxel_size**3
        network['throat.coords'] = network['throat.coords'] * 1e-6
        network['throat.radius'] = network['throat.radius'] * 1e-6
        network['throat.dmax'] = network['throat.dmax'] * 1e-6
        network['throat.volume'] = network['throat.volume'] * voxel_size**3

        return network.project
Esempio n. 25
0
    def load(cls, path, prefix, network=None):
        r"""
        Load data from the \'dat\' files located in specified folder.

        Parameters
        ----------
        path : string
            The full path to the folder containing the set of \'dat\' files.

        prefix : string
            The file name prefix on each file. The data files are stored
            as \<prefix\>_node1.dat.

        network : OpenPNM Network Object
            If given then the data will be loaded on it and returned.  If not
            given, a Network will be created and returned.

        Returns
        -------
        An OpenPNM Project containing a GenericNetwork holding all the data

        """
        net = {}

        # ---------------------------------------------------------------------
        # Parse the link1 file
        path = Path(path)
        filename = Path(path.resolve(), prefix+'_link1.dat')
        with open(filename, mode='r') as f:
            link1 = pd.read_table(filepath_or_buffer=f,
                                  header=None,
                                  skiprows=1,
                                  sep=' ',
                                  skipinitialspace=True,
                                  index_col=0)
        link1.columns = ['throat.pore1', 'throat.pore2', 'throat.radius',
                         'throat.shape_factor', 'throat.total_length']
        # Add link1 props to net
        net['throat.conns'] = sp.vstack((link1['throat.pore1']-1,
                                         link1['throat.pore2']-1)).T
        net['throat.conns'] = sp.sort(net['throat.conns'], axis=1)
        net['throat.radius'] = sp.array(link1['throat.radius'])
        net['throat.shape_factor'] = sp.array(link1['throat.shape_factor'])
        net['throat.total_length'] = sp.array(link1['throat.total_length'])
        # ---------------------------------------------------------------------
        filename = Path(path.resolve(), prefix+'_link2.dat')
        with open(filename, mode='r') as f:
            link2 = pd.read_table(filepath_or_buffer=f,
                                  header=None,
                                  sep=' ',
                                  skipinitialspace=True,
                                  index_col=0)
        link2.columns = ['throat.pore1', 'throat.pore2',
                         'throat.pore1_length', 'throat.pore2_length',
                         'throat.length', 'throat.volume',
                         'throat.clay_volume']
        # Add link2 props to net
        cl_t = sp.array(link2['throat.length'])
        net['throat.length'] = cl_t
        net['throat.conduit_lengths.throat'] = cl_t
        net['throat.volume'] = sp.array(link2['throat.volume'])
        cl_p1 = sp.array(link2['throat.pore1_length'])
        net['throat.conduit_lengths.pore1'] = cl_p1
        cl_p2 = sp.array(link2['throat.pore2_length'])
        net['throat.conduit_lengths.pore2'] = cl_p2
        net['throat.clay_volume'] = sp.array(link2['throat.clay_volume'])
        # ---------------------------------------------------------------------
        # Parse the node1 file
        filename = Path(path.resolve(), prefix+'_node1.dat')
        with open(filename, mode='r') as f:
            row_0 = f.readline().split()
            num_lines = int(row_0[0])
            array = sp.ndarray([num_lines, 6])
            for i in range(num_lines):
                row = f.readline()\
                       .replace('\t', ' ').replace('\n', ' ').split()
                array[i, :] = row[0:6]
        node1 = pd.DataFrame(array[:, [1, 2, 3, 4]])
        node1.columns = ['pore.x_coord', 'pore.y_coord', 'pore.z_coord',
                         'pore.coordination_number']
        # Add node1 props to net
        net['pore.coords'] = sp.vstack((node1['pore.x_coord'],
                                        node1['pore.y_coord'],
                                        node1['pore.z_coord'])).T
        # ---------------------------------------------------------------------
        # Parse the node1 file
        filename = Path(path.resolve(), prefix+'_node2.dat')
        with open(filename, mode='r') as f:
            node2 = pd.read_table(filepath_or_buffer=f,
                                  header=None,
                                  sep=' ',
                                  skipinitialspace=True,
                                  index_col=0)
        node2.columns = ['pore.volume', 'pore.radius', 'pore.shape_factor',
                         'pore.clay_volume']
        # Add node2 props to net
        net['pore.volume'] = sp.array(node2['pore.volume'])
        net['pore.radius'] = sp.array(node2['pore.radius'])
        net['pore.shape_factor'] = sp.array(node2['pore.shape_factor'])
        net['pore.clay_volume'] = sp.array(node2['pore.clay_volume'])
        net['throat.area'] = ((net['throat.radius']**2) /
                              (4.0*net['throat.shape_factor']))
        net['pore.area'] = ((net['pore.radius']**2) /
                            (4.0*net['pore.shape_factor']))

        if network is None:
            network = GenericNetwork()
        network = cls._update_network(network=network, net=net)

        # Use OpenPNM Tools to clean up network
        # Trim throats connected to 'inlet' or 'outlet' reservoirs
        trim1 = sp.where(sp.any(net['throat.conns'] == -1, axis=1))[0]
        # Apply 'outlet' label to these pores
        outlets = network['throat.conns'][trim1, 1]
        network['pore.outlets'] = False
        network['pore.outlets'][outlets] = True
        trim2 = sp.where(sp.any(net['throat.conns'] == -2, axis=1))[0]
        # Apply 'inlet' label to these pores
        inlets = network['throat.conns'][trim2, 1]
        network['pore.inlets'] = False
        network['pore.inlets'][inlets] = True
        # Now trim the throats
        to_trim = sp.hstack([trim1, trim2])
        trim(network=network, throats=to_trim)

        return network.project
Esempio n. 26
0
    def __init__(self,
                 shape,
                 spacing=1.0,
                 length=1.0,
                 psd_params={'distribution': 'norm',
                             'loc': None,
                             'scale': None},
                 name=None,
                 settings={},
                 **kwargs):
        super().__init__(name=name)
        self.settings.update(defsets)
        self.settings.update(settings)

        if isinstance(shape, int):
            shape = sp.array([shape, shape, 2])
        elif len(shape) == 2:
            shape = sp.concatenate((sp.array(shape), [2]))
        else:
            raise Exception('shape not understood, must be int ' +
                            ' or list of 2 ints')

        if isinstance(spacing, float) or isinstance(spacing, int):
            spacing = float(spacing)
            self.settings['spacing'] = spacing
            spacing = sp.array([spacing, spacing, length])
        else:
            raise Exception('spacing not understood, must be float')

        net = Cubic(shape=shape, spacing=spacing, project=self, **kwargs)
        Ps_top = net.pores('top')
        Ps_bot = net.pores('bottom')
        Ts = net.find_connecting_throat(P1=Ps_top, P2=Ps_bot)
        Ts = net.tomask(throats=Ts)
        trim(network=net, throats=~Ts)

        geom = GenericGeometry(network=net, pores=net.Ps, throats=net.Ts)

        geom.add_model(propname='throat.seed',
                       model=mods.geometry.throat_seed.random)
        if psd_params['loc'] is None:
            psd_params['loc'] = spacing[0]/2
        if psd_params['scale'] is None:
            psd_params['scale'] = spacing[0]/10
        if psd_params['distribution'] in ['norm', 'normal', 'gaussian']:
            geom.add_model(propname='throat.size_distribution',
                           seeds='throat.seed',
                           model=mods.geometry.throat_size.normal,
                           loc=psd_params['loc'], scale=psd_params['scale'])
        elif psd_params['distribution'] in ['weibull']:
            geom.add_model(propname='throat.size_distribution',
                           seeds='throat.seed',
                           model=mods.geometry.throat_size.weibull,
                           loc=psd_params['loc'],
                           scale=psd_params['scale'],
                           shape=psd_params['shape'])
        else:
            temp = psd_params.copy()
            func = getattr(spst, temp.pop('distribution'))
            psd = func.freeze(**temp)
            geom.add_model(propname='throat.size_distribution',
                           seeds='throat.seed',
                           model=mods.geometry.throat_size.generic_distribution,
                           func=psd)

        if sp.any(geom['throat.size_distribution'] < 0):
            logger.warning('Given size distribution produced negative ' +
                           'throat diameters...these will be set to 0')
        geom.add_model(propname='throat.diameter',
                       model=mods.misc.clip,
                       prop='throat.size_distribution',
                       xmin=1e-12, xmax=sp.inf)

        if self.settings['adjust_psd'] is None:
            if geom['throat.size_distribution'].max() > spacing[0]:
                logger.warning('Given size distribution produced throats ' +
                               'larger than the spacing.')

        elif self.settings['adjust_psd'] == 'clip':
            geom.add_model(propname='throat.diameter',
                           model=mods.misc.clip,
                           prop='throat.size_distribution',
                           xmin=1e-12, xmax=spacing[0])
            if geom['throat.size_distribution'].max() > spacing[0]:
                logger.warning('Given size distribution produced throats ' +
                               'larger than the spacing...tube diameters ' +
                               'will be clipped between 0 and given spacing')

        elif self.settings['adjust_psd'] == 'normalize':
            tmin = max(1e-12, geom['throat.size_distribution'].min())
            geom.add_model(propname='throat.diameter',
                           model=mods.misc.normalize,
                           prop='throat.size_distribution',
                           xmin=tmin, xmax=spacing[0])
            if geom['throat.size_distribution'].max() > spacing[0]:
                logger.warning('Given size distribution produced throats ' +
                               'larger than the spacing...tube diameters ' +
                               'will be normalized to fit given spacing')
        else:
            logger.warning('Settings not understood, ignoring')

        geom.add_model(propname='pore.diameter',
                       model=mods.geometry.pore_size.from_neighbor_throats,
                       throat_prop='throat.diameter', mode='max')
        geom.add_model(propname='pore.diameter',
                       model=mods.misc.constant, value=0.0)
        geom.add_model(propname='throat.length',
                       model=mods.geometry.throat_length.ctc)
        geom.add_model(propname='throat.area',
                       model=mods.geometry.throat_area.cylinder)
        geom.add_model(propname='pore.area',
                       model=mods.misc.from_neighbor_throats,
                       throat_prop='throat.area')
        geom.add_model(propname='pore.volume',
                       model=mods.misc.constant, value=0.0)
        geom.add_model(propname='throat.volume',
                       model=mods.geometry.throat_volume.cylinder)

        geom.regenerate_models()

        # Now create a generic phase with physics models on it
        phase = GenericPhase(network=net)
        m = mods.physics.hydraulic_conductance.classic_hagen_poiseuille
        phase.add_model(propname='throat.hydraulic_conductance',
                        model=m, regen_mode='deferred')
        m = mods.physics.diffusive_conductance.classic_ordinary_diffusion
        phase.add_model(propname='throat.diffusive_conductance',
                        model=m, regen_mode='deferred')
        m = mods.physics.diffusive_conductance.classic_ordinary_diffusion
        phase.add_model(propname='throat.entry_pressure',
                        model=m, regen_mode='deferred')
Esempio n. 27
0
    def load(cls, path, voxel_size=1, project=None):
        r"""
        Load data from a 3DMA-Rock extracted network.  This format consists of
        two files: 'rockname.np2th' and 'rockname.th2pn'.  They should be
        stored together in a folder which is referred to by the path argument.
        These files are binary and therefore not human readable.

        Parameters
        ----------
        path : string
            The location of the 'np2th' and 'th2np' files. This can be an
            absolute path or relative to the current working directory.

        network : OpenPNM Network Object
            If an Network object is recieved, this method will add new data to
            it but NOT overwrite anything that already exists.  This can be
            used to append data from different sources.

        voxel_size : scalar
            The resolution of the image on which 3DMA-Rock was run, in terms of
            the linear length of eac voxel. The default is 1.  This is used to
            scale the voxel counts to actual dimension. It is recommended that
            this value be in SI units [m] to work well with OpenPNM.

        project : OpenPNM Project object
            A GenericNetwork is created and added to the specified Project.
            If no Project is supplied then one will be created and returned.

        """

        net = {}
        path = Path(path)
        path = path.resolve()
        for file in os.listdir(path):
            if file.endswith(".np2th"):
                np2th_file = os.path.join(path, file)
            elif file.endswith(".th2np"):
                th2np_file = os.path.join(path, file)

        with open(np2th_file, mode='rb') as f:
            [Np, Nt] = sp.fromfile(file=f, count=2, dtype='u4')
            net['pore.boundary_type'] = sp.ndarray([Np, ], int)
            net['throat.conns'] = sp.ones([Nt, 2], int)*(-1)
            net['pore.coordination'] = sp.ndarray([Np, ], int)
            net['pore.ID_number'] = sp.ndarray([Np, ], int)
            for i in range(0, Np):
                ID = sp.fromfile(file=f, count=1, dtype='u4')
                net['pore.ID_number'][i] = ID
                net['pore.boundary_type'][i] = sp.fromfile(file=f, count=1,
                                                           dtype='u1')
                z = sp.fromfile(file=f, count=1, dtype='u4')[0]
                net['pore.coordination'][i] = z
                att_pores = sp.fromfile(file=f, count=z, dtype='u4')
                att_throats = sp.fromfile(file=f, count=z, dtype='u4')
                for j in range(0, len(att_throats)):
                    t = att_throats[j] - 1
                    p = att_pores[j] - 1
                    net['throat.conns'][t] = [i, p]
            net['throat.conns'] = sp.sort(net['throat.conns'], axis=1)
            net['pore.volume'] = sp.fromfile(file=f, count=Np, dtype='u4')
            nx = sp.fromfile(file=f, count=1, dtype='u4')
            nxy = sp.fromfile(file=f, count=1, dtype='u4')
            pos = sp.fromfile(file=f, count=Np, dtype='u4')
            ny = nxy/nx
            ni = sp.mod(pos, nx)
            nj = sp.mod(sp.floor(pos/nx), ny)
            nk = sp.floor(sp.floor(pos/nx)/ny)
            net['pore.coords'] = sp.array([ni, nj, nk]).T

        with open(th2np_file, mode='rb') as f:
            Nt = sp.fromfile(file=f, count=1, dtype='u4')[0]
            net['throat.area'] = sp.ones([Nt, ], dtype=int)*(-1)
            for i in range(0, Nt):
                ID = sp.fromfile(file=f, count=1, dtype='u4')
                net['throat.area'][i] = sp.fromfile(file=f, count=1,
                                                    dtype='f4')
                numvox = sp.fromfile(file=f, count=1, dtype='u4')
                att_pores = sp.fromfile(file=f, count=2, dtype='u4')
            nx = sp.fromfile(file=f, count=1, dtype='u4')
            nxy = sp.fromfile(file=f, count=1, dtype='u4')
            pos = sp.fromfile(file=f, count=Nt, dtype='u4')
            ny = nxy/nx
            ni = sp.mod(pos, nx)
            nj = sp.mod(sp.floor(pos/nx), ny)
            nk = sp.floor(sp.floor(pos/nx)/ny)
            net['throat.coords'] = sp.array([ni, nj, nk]).T
            net['pore.internal'] = net['pore.boundary_type'] == 0

        # Convert voxel area and volume to actual dimensions
        net['throat.area'] = (voxel_size**2)*net['throat.area']
        net['pore.volume'] = (voxel_size**3)*net['pore.volume']

        if project is None:
            project = Project(name=path)
        network = GenericNetwork(project=project)
        network = cls._update_network(network=network, net=net)

        # Trim headless throats before returning
        ind = sp.where(network['throat.conns'][:, 0] == -1)[0]
        trim(network=network, throats=ind)

        return project
Esempio n. 28
0
    def load(cls,
             path,
             node_file="throats_cellsThroatsGraph_Nodes.txt",
             graph_file="throats_cellsThroatsGraph.txt",
             network=None,
             voxel_size=None,
             return_geometry=False):
        r"""
        Loads network data from an iMorph processed image stack

        Parameters
        ----------
        path : string
            The path of the folder where the subfiles are held

        node_file : string
            The file that describes the pores and throats, the
            default iMorph name is: throats_cellsThroatsGraph_Nodes.txt

        graph_file : string
            The file that describes the connectivity of the network, the
            default iMorph name is: throats_cellsThroatsGraph.txt

        network : OpenPNM Network Object
            The OpenPNM Network onto which the data should be loaded.  If no
            network is supplied then an empty import network is created and
            returned.

        voxel_size : float
            Allows the user to define a voxel size different than what is
            contained in the node_file. The value must be in meters.

        return_geometry : Boolean
            If True, then all geometrical related properties are removed from
            the Network object and added to a GenericGeometry object.  In this
            case the method returns a tuple containing (network, geometry). If
            False (default) then the returned Network will contain all
            properties that were in the original file.  In this case, the user
            can call the ```split_geometry``` method explicitly to perform the
            separation.

        Returns
        -------
        If no Network object is supplied then one will be created and returned.

        If return_geometry is True, then a tuple is returned containing both
        the network and a geometry object.
        """
        #
        path = Path(path)
        node_file = os.path.join(path.resolve(), node_file)
        graph_file = os.path.join(path.resolve(), graph_file)
        # parsing the nodes file
        with open(node_file, 'r') as file:
            Np = sp.fromstring(file.readline().rsplit('=')[1],
                               sep='\t',
                               dtype=int)[0]
            vox_size = sp.fromstring(
                file.readline().rsplit(')')[1],
                sep='\t',
            )[0]

            # network always recreated to prevent errors
            network = GenericNetwork(Np=Np, Nt=0)

            # Define expected properies
            network['pore.volume'] = sp.nan
            scrap_lines = [file.readline() for line in range(4)]
            while True:
                vals = file.readline().split('\t')
                if len(vals) == 1:
                    break
                network['pore.volume'][int(vals[0])] = float(vals[3])
                if 'pore.' + vals[2] not in network.labels():
                    network['pore.' + vals[2]] = False
                network['pore.' + vals[2]][int(vals[0])] = True

        if voxel_size is None:
            voxel_size = vox_size * 1.0E-6  # file stores value in microns

        if voxel_size < 0:
            raise (Exception('Error - Voxel size must be specfied in ' +
                             'the Nodes file or as a keyword argument.'))

        # parsing the graph file
        with open(graph_file, 'r') as file:
            # Define expected properties
            network['pore.coords'] = sp.zeros((Np, 3)) * sp.nan
            network['pore.types'] = sp.nan
            network['pore.color'] = sp.nan
            network['pore.radius'] = sp.nan
            network['pore.dmax'] = sp.nan
            network['pore.node_number'] = sp.nan
            # Scan file to get pore coordinate data
            scrap_lines = [file.readline() for line in range(3)]
            line = file.readline()
            xmax = 0.0
            ymax = 0.0
            zmax = 0.0
            node_num = 0
            while line != 'connectivity table\n':
                vals = sp.fromstring(line, sep='\t')
                xmax = vals[1] if vals[1] > xmax else xmax
                ymax = vals[2] if vals[2] > ymax else ymax
                zmax = vals[3] if vals[3] > zmax else zmax
                network['pore.coords'][int(vals[0]), :] = vals[1:4]
                network['pore.types'][int(vals[0])] = vals[4]
                network['pore.color'][int(vals[0])] = vals[5]
                network['pore.radius'][int(vals[0])] = vals[6]
                network['pore.dmax'][int(vals[0])] = vals[7]
                network['pore.node_number'][int(vals[0])] = node_num
                node_num += 1
                line = file.readline()
            # Scan file to get to connectivity data
            scrap_lines.append(file.readline())  # Skip line
            # Create sparse lil array incrementally build adjacency matrix
            lil = sp.sparse.lil_matrix((Np, Np), dtype=int)
            while True:
                vals = sp.fromstring(file.readline(), sep='\t', dtype=int)
                if len(vals) <= 1:
                    break
                lil.rows[vals[0]] = vals[2:]
                lil.data[vals[0]] = sp.ones(vals[1])

        # fixing any negative volumes or distances so they are 1 voxel/micron
        network['pore.volume'][sp.where(network['pore.volume'] < 0)[0]] = 1.0
        network['pore.radius'][sp.where(network['pore.radius'] < 0)[0]] = 1.0
        network['pore.dmax'][sp.where(network['pore.dmax'] < 0)[0]] = 1.0

        # Add adjacency matrix to OpenPNM network
        conns = sp.sparse.triu(lil, k=1, format='coo')
        network.update({'throat.all': sp.ones(len(conns.col), dtype=bool)})
        network['throat.conns'] = sp.vstack([conns.row, conns.col]).T

        network['pore.to_trim'] = False
        network['pore.to_trim'][network.pores('*throat')] = True
        Ts = network.pores('to_trim')
        new_conns = network.find_neighbor_pores(pores=Ts, flatten=False)
        extend(network=network, throat_conns=new_conns, labels='new_conns')
        for item in network.props('pore'):
            item = item.split('.')[1]
            arr = sp.ones_like(network['pore.' + item])[0]
            arr = sp.tile(A=arr, reps=[network.Nt, 1]) * sp.nan
            network['throat.' + item] = sp.squeeze(arr)
            network['throat.'+item][network.throats('new_conns')] = \
                network['pore.'+item][Ts]
        trim(network=network, pores=Ts)

        # setting up boundary pores
        x_coord, y_coord, z_coord = sp.hsplit(network['pore.coords'], 3)
        network['pore.front_boundary'] = sp.ravel(x_coord == 0)
        network['pore.back_boundary'] = sp.ravel(x_coord == xmax)
        network['pore.left_boundary'] = sp.ravel(y_coord == 0)
        network['pore.right_boundary'] = sp.ravel(y_coord == ymax)
        network['pore.bottom_boundary'] = sp.ravel(z_coord == 0)
        network['pore.top_boundary'] = sp.ravel(z_coord == zmax)

        # removing any pores that got classified as a boundary pore but
        # weren't labled a border_cell_face
        ps = sp.where(~sp.in1d(network.pores('*_boundary'),
                               network.pores('border_cell_face')))[0]
        ps = network.pores('*_boundary')[ps]
        for side in ['front', 'back', 'left', 'right', 'top', 'bottom']:
            network['pore.' + side + '_boundary'][ps] = False
        # setting internal label
        network['pore.internal'] = False
        network['pore.internal'][network.pores('*_boundary',
                                               mode='not')] = True

        # adding props to border cell face throats and from pores
        Ts = sp.where(
            network['throat.conns'][:,
                                    1] > network.pores('border_cell_face')[0] -
            1)[0]
        faces = network['throat.conns'][Ts, 1]
        for item in network.props('pore'):
            item = item.split('.')[1]
            network['throat.' + item][Ts] = network['pore.' + item][faces]
        network['pore.volume'][faces] = 0.0

        # applying unit conversions
        # TODO: Determine if radius and dmax are indeed microns and not voxels
        network['pore.coords'] = network['pore.coords'] * 1e-6
        network['pore.radius'] = network['pore.radius'] * 1e-6
        network['pore.dmax'] = network['pore.dmax'] * 1e-6
        network['pore.volume'] = network['pore.volume'] * voxel_size**3
        network['throat.coords'] = network['throat.coords'] * 1e-6
        network['throat.radius'] = network['throat.radius'] * 1e-6
        network['throat.dmax'] = network['throat.dmax'] * 1e-6
        network['throat.volume'] = network['throat.volume'] * voxel_size**3

        return network.project
Esempio n. 29
0
    def __init__(self,
                 shape,
                 spacing=1.0,
                 length=1.0,
                 psd_params={
                     'distribution': 'norm',
                     'loc': None,
                     'scale': None
                 },
                 name=None,
                 settings={},
                 **kwargs):
        super().__init__(name=name)
        self.settings.update(defsets)
        self.settings.update(settings)

        if isinstance(shape, int):
            shape = sp.array([shape, shape, 2])
        elif len(shape) == 2:
            shape = sp.concatenate((sp.array(shape), [2]))
        else:
            raise Exception('shape not understood, must be int ' +
                            ' or list of 2 ints')

        if isinstance(spacing, float) or isinstance(spacing, int):
            spacing = float(spacing)
            self.settings['spacing'] = spacing
            spacing = sp.array([spacing, spacing, length])
        else:
            raise Exception('spacing not understood, must be float')

        net = Cubic(shape=shape, spacing=spacing, project=self, **kwargs)
        Ps_top = net.pores('top')
        Ps_bot = net.pores('bottom')
        Ts = net.find_connecting_throat(P1=Ps_top, P2=Ps_bot)
        Ts = net.tomask(throats=Ts)
        trim(network=net, throats=~Ts)

        geom = GenericGeometry(network=net, pores=net.Ps, throats=net.Ts)

        geom.add_model(propname='throat.seed',
                       model=mods.geometry.throat_seed.random)
        if psd_params['loc'] is None:
            psd_params['loc'] = spacing[0] / 2
        if psd_params['scale'] is None:
            psd_params['scale'] = spacing[0] / 10
        if psd_params['distribution'] in ['norm', 'normal', 'gaussian']:
            geom.add_model(propname='throat.size_distribution',
                           seeds='throat.seed',
                           model=mods.geometry.throat_size.normal,
                           loc=psd_params['loc'],
                           scale=psd_params['scale'])
        elif psd_params['distribution'] in ['weibull']:
            geom.add_model(propname='throat.size_distribution',
                           seeds='throat.seed',
                           model=mods.geometry.throat_size.weibull,
                           loc=psd_params['loc'],
                           scale=psd_params['scale'],
                           shape=psd_params['shape'])
        else:
            temp = psd_params.copy()
            func = getattr(spst, temp.pop('distribution'))
            psd = func.freeze(**temp)
            geom.add_model(
                propname='throat.size_distribution',
                seeds='throat.seed',
                model=mods.geometry.throat_size.generic_distribution,
                func=psd)

        if sp.any(geom['throat.size_distribution'] < 0):
            logger.warning('Given size distribution produced negative ' +
                           'throat diameters...these will be set to 0')
        geom.add_model(propname='throat.diameter',
                       model=mods.misc.clip,
                       prop='throat.size_distribution',
                       xmin=1e-12,
                       xmax=sp.inf)

        if self.settings['adjust_psd'] is None:
            if geom['throat.size_distribution'].max() > spacing[0]:
                logger.warning('Given size distribution produced throats ' +
                               'larger than the spacing.')

        elif self.settings['adjust_psd'] == 'clip':
            geom.add_model(propname='throat.diameter',
                           model=mods.misc.clip,
                           prop='throat.size_distribution',
                           xmin=1e-12,
                           xmax=spacing[0])
            if geom['throat.size_distribution'].max() > spacing[0]:
                logger.warning('Given size distribution produced throats ' +
                               'larger than the spacing...tube diameters ' +
                               'will be clipped between 0 and given spacing')

        elif self.settings['adjust_psd'] == 'normalize':
            tmin = max(1e-12, geom['throat.size_distribution'].min())
            geom.add_model(propname='throat.diameter',
                           model=mods.misc.normalize,
                           prop='throat.size_distribution',
                           xmin=tmin,
                           xmax=spacing[0])
            if geom['throat.size_distribution'].max() > spacing[0]:
                logger.warning('Given size distribution produced throats ' +
                               'larger than the spacing...tube diameters ' +
                               'will be normalized to fit given spacing')
        else:
            logger.warning('Settings not understood, ignoring')

        geom.add_model(propname='pore.diameter',
                       model=mods.geometry.pore_size.from_neighbor_throats,
                       throat_prop='throat.diameter',
                       mode='max')
        geom.add_model(propname='pore.diameter',
                       model=mods.misc.constant,
                       value=0.0)
        geom.add_model(propname='throat.length',
                       model=mods.geometry.throat_length.ctc)
        geom.add_model(propname='throat.area',
                       model=mods.geometry.throat_area.cylinder)
        geom.add_model(propname='pore.area',
                       model=mods.misc.from_neighbor_throats,
                       throat_prop='throat.area')
        geom.add_model(propname='pore.volume',
                       model=mods.misc.constant,
                       value=0.0)
        geom.add_model(propname='throat.volume',
                       model=mods.geometry.throat_volume.cylinder)

        geom.regenerate_models()

        # Now create a generic phase with physics models on it
        phase = GenericPhase(network=net)
        m = mods.physics.hydraulic_conductance.classic_hagen_poiseuille
        phase.add_model(propname='throat.hydraulic_conductance',
                        model=m,
                        regen_mode='deferred')
        m = mods.physics.diffusive_conductance.classic_ordinary_diffusion
        phase.add_model(propname='throat.diffusive_conductance',
                        model=m,
                        regen_mode='deferred')
        m = mods.physics.diffusive_conductance.classic_ordinary_diffusion
        phase.add_model(propname='throat.entry_pressure',
                        model=m,
                        regen_mode='deferred')