Beispiel #1
0
    def load(cls, filename, project=None, settings={}):
        r"""
        """
        # Parse the link1 file
        filename = cls._parse_filename(filename=filename, ext='dict')
        with open(filename, mode='rb') as f:
            net = pk.load(f)

        network = GenericNetwork(project=project)
        network = cls._update_network(network=network, net=net)
        # The following list of props comes from porespy but are not good
        for item in [
                'pore.diameter', 'pore.area', 'throat.conduit_lengths.pore1',
                'throat.conduit_lengths.pore2',
                'throat.conduit_lengths.throat', 'throat.endpoints.head',
                'throat.endpoints.tail', 'throat.diameter', 'throat.length',
                'throat.volume'
        ]:
            network.pop(item, None)

        # Deal with a few other PoreSpy specific issues
        network['pore.region_volume'] = network.pop('pore.volume')

        Imported(network=network, settings=settings)

        return network.project
Beispiel #2
0
    def import_data(cls, filename, project=None, settings=None):
        r"""
        Load a network extracted using the PoreSpy package

        Parameters
        ----------
        filename : str or dict
            Can either be a filename point to a pickled dictionary, or an
            actual dictionary.  The second option lets users avoid the
            step of saving the dictionary to a file
        project : Project
            If given, the loaded network and geometry will be added to this
            project, otherwise a new one will be created.

        """
        # Parse the filename
        if isinstance(filename, dict):
            net = filename
        else:
            filename = cls._parse_filename(filename=filename, ext='dict')
            with open(filename, mode='rb') as f:
                net = pk.load(f)

        network = GenericNetwork(project=project)
        network = cls._update_network(network=network, net=net)
        Imported(network=network, settings=settings)

        return network.project
Beispiel #3
0
    def import_data(cls, filename, project=None, settings={}):
        r"""
        Load a network extracted using the PoreSpy package

        Parameters
        ----------
        filename : str or dict
            Can either be a filename point to a pickled dictionary, or an
            actual dictionary.  The second option lets users avoid the
            step of saving the dictionary to a file
        project : OpenPNM Project object
            If given, the loaded network and geometry will be added to this
            project, otherwise a new one will be created.
        """
        # Parse the filename
        if isinstance(filename, dict):
            net = filename
        else:
            filename = cls._parse_filename(filename=filename, ext='dict')
            with open(filename, mode='rb') as f:
                net = pk.load(f)

        network = GenericNetwork(project=project)
        network = cls._update_network(network=network, net=net)
        # The following list of props comes from porespy but are not good
        for item in [
                'pore.diameter', 'pore.area', 'throat.conduit_lengths.pore1',
                'throat.conduit_lengths.pore2',
                'throat.conduit_lengths.throat', 'throat.endpoints.head',
                'throat.endpoints.tail', 'throat.diameter', 'throat.length',
                'throat.volume'
        ]:
            network.pop(item, None)

        # Deal with a few other PoreSpy specific issues
        network['pore.region_volume'] = network.pop('pore.volume')

        Imported(network=network, settings=settings)

        return network.project
Beispiel #4
0
def to_openpnm(net, filename):
    r"""
    Save the result of the `snow` network extraction function in a format
    suitable for opening in OpenPNM.

    Parameters
    ----------
    net : dict
        The dictionary object produced by the network extraction functions

    filename : string or path object
        The name and location to save the file, which will have `.net` file
        extension.

    """
    from openpnm.network import GenericNetwork
    # Convert net dict to an openpnm Network
    pn = GenericNetwork()
    pn.update(net)
    pn.project.save_project(filename)
    ws = pn.project.workspace
    ws.close_project(pn.project)
Beispiel #5
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
Beispiel #6
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
Beispiel #7
0
    def from_networkx(cls, G, project=None):
        r"""
        Add data to an OpenPNM Network from a undirected NetworkX graph object.

        Parameters
        ----------
        G : networkx.classes.graph.Graph Object
            The NetworkX graph. G should be undirected. The numbering of nodes
            should be numeric (int's), zero-based and should not contain any
            gaps, i.e. ``G.nodes() = [0,1,3,4,5]`` is not allowed and should be
            mapped to ``G.nodes() = [0,1,2,3,4]``.

        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.

        Returns
        -------
        An OpenPNM Project containing a GenericNetwork with all the data from
        the NetworkX object.

        """
        import networkx as nx

        net = {}

        # Ensure G is an undirected networkX graph with numerically numbered
        # nodes for which numbering starts at 0 and does not contain any gaps
        if not isinstance(G, nx.Graph):
            raise ('Provided object is not a NetworkX graph.')
        if nx.is_directed(G):
            raise ('Provided graph is directed. Convert to undirected graph.')
        if not all(isinstance(n, int) for n in G.nodes()):
            raise ('Node numbering is not numeric. Convert to int.')
        if min(G.nodes()) != 0:
            raise ('Node numbering does not start at zero.')
        if max(G.nodes()) + 1 != len(G.nodes()):
            raise ('Node numbering contains gaps. Map nodes to remove gaps.')

        # Parsing node data
        Np = len(G)
        net.update({'pore.all': np.ones((Np,), dtype=bool)})
        for n, props in G.nodes(data=True):
            for item in props.keys():
                val = props[item]
                dtype = type(val)
                # Remove prepended pore. and pore_ if present
                for b in ['pore.', 'pore_']:
                    item = item.replace(b, '')
                # Create arrays for subsequent indexing, if not present already
                if 'pore.'+item not in net.keys():
                    if dtype == str:  # handle strings of arbitrary length
                        net['pore.'+item] = sp.ndarray((Np,), dtype='object')
                    elif dtype is list:
                        dtype = type(val[0])
                        if dtype == str:
                            dtype = 'object'
                        cols = len(val)
                        net['pore.'+item] = sp.ndarray((Np, cols), dtype=dtype)
                    else:
                        net['pore.'+item] = sp.ndarray((Np,), dtype=dtype)
                net['pore.'+item][n] = val

        # Parsing edge data
        # Deal with conns explicitly
        try:
            conns = list(G.edges)   # NetworkX V2
        except Exception:
            conns = G.edges()       # NetworkX V1
        conns.sort()

        # Add conns to Network
        Nt = len(conns)
        net.update({'throat.all': np.ones(Nt, dtype=bool)})
        net.update({'throat.conns': np.array(conns)})

        # Scan through each edge and extract all its properties
        i = 0
        for t in conns:
            props = G[t[0]][t[1]]
            for item in props:
                val = props[item]
                dtype = type(val)
                # Remove prepended throat. and throat_ if present
                for b in ['throat.', 'throat_']:
                    item = item.replace(b, '')
                # Create arrays for subsequent indexing, if not present already
                if 'throat.'+item not in net.keys():
                    if dtype == str:
                        net['throat.'+item] = sp.ndarray((Nt,), dtype='object')
                    if dtype is list:
                        dtype = type(val[0])
                        if dtype == str:
                            dtype = 'object'
                        cols = len(val)
                        net['throat.'+item] = sp.ndarray((Nt, cols),
                                                         dtype=dtype)
                    else:
                        net['throat.'+item] = sp.ndarray((Nt,), dtype=dtype)
                net['throat.'+item][i] = val
            i += 1

        network = GenericNetwork(project=project)
        network = cls._update_network(network=network, net=net)
        return network.project
Beispiel #8
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
Beispiel #9
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
Beispiel #10
0
    def load(cls, filename, network=None):
        r"""
        """
        net = {}

        # ---------------------------------------------------------------------
        # Parse the link1 file
        filename = cls._parse_filename(filename=filename, ext='am')
        with open(filename, mode='r') as f:
            Np = None
            Nt = None
            while (Np is None) or (Nt is None):
                s = f.readline()[:-1].split(' ')
                if s[0] == 'define':
                    if s[1] == 'VERTEX':
                        Np = int(s[2])
                    if s[1] == 'EDGE':
                        Nt = int(s[2])

            net = {}
            propmap = {}
            typemap = {}
            shapemap = {}
            while True:
                s = f.readline()[:-1].split(' ')
                if s[0] == 'VERTEX':
                    dshape = [Np]
                    if s[2].endswith(']'):
                        ncols = int(s[2].split('[', 1)[1].split(']')[0])
                        dshape.append(ncols)
                    dtype = s[2].split('[')[0]
                    temp = np.zeros(dshape, dtype=dtype)
                    net['pore.' + s[3]] = temp
                    key = int(s[-1].replace('@', ''))
                    propmap[key] = 'pore.' + s[3]
                    typemap[key] = dtype
                    shapemap[key] = dshape
                elif s[0] == 'EDGE':
                    dshape = [Nt]
                    if s[2].endswith(']'):
                        ncols = int(s[2].split('[', 1)[1].split(']')[0])
                        dshape.append(ncols)
                    dtype = s[2].split('[')[0]
                    temp = np.zeros(dshape, dtype=dtype)
                    net['throat.' + s[3]] = temp
                    key = int(s[-1].replace('@', ''))
                    propmap[key] = 'throat.' + s[3]
                    typemap[key] = dtype
                    shapemap[key] = dshape
                elif s[0] == '#':
                    break

            s = f.read().split('@')
            for key in propmap.keys():
                if key in s:
                    data = s[key].split('\n')[1:]
                    data = ' '.join(data)
                    arr = np.fromstring(data, dtype=typemap[key], sep=' ')
                    arr = np.reshape(arr, newshape=shapemap[key])
                    net[propmap[key]] = arr
            # End file parsing

        net['pore.coords'] = net['pore.VertexCoordinates']
        net['throat.conns'] = np.sort(net['throat.EdgeConnectivity'], axis=1)

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

        return network.project
Beispiel #11
0
    def load(self, filename, project=None):
        r"""
        Loads the JGF file onto the given project.

        Parameters
        ----------
        filename : string
            The name of the file containing the data to import.  The formatting
            of this file is outlined below.

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

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

        # Ensure input file is valid
        filename = self._parse_filename(filename=filename, ext='json')

        # Load and validate input JSON
        with open(filename, 'r') as file:
            json_file = json.load(file)
            if not self.__validate_json__(json_file):
                raise Exception('FIle is not in the JSON Graph Format')

        # Extract graph metadata from JSON
        number_of_nodes = json_file['graph']['metadata']['number_of_nodes']
        number_of_links = json_file['graph']['metadata']['number_of_links']

        # Extract node properties from JSON
        nodes = sorted(json_file['graph']['nodes'],
                       key=lambda node: int(node['id']))
        x = np.array(
            [node['metadata']['node_coordinates']['x'] for node in nodes])
        y = np.array(
            [node['metadata']['node_coordinates']['y'] for node in nodes])
        z = np.array(
            [node['metadata']['node_coordinates']['z'] for node in nodes])

        # Extract link properties from JSON
        edges = sorted(json_file['graph']['edges'],
                       key=lambda edge: int(edge['id']))
        source = np.array([int(edge['source']) for edge in edges])
        target = np.array([int(edge['target']) for edge in edges])
        link_length = np.array(
            [edge['metadata']['link_length'] for edge in edges])
        link_squared_radius = np.array(
            [edge['metadata']['link_squared_radius'] for edge in edges])

        # Generate network object
        network = GenericNetwork(Np=number_of_nodes, Nt=number_of_links)

        # Define primitive throat properties
        network['throat.length'] = link_length
        network['throat.conns'] = np.column_stack([source, target])
        network['throat.diameter'] = 2.0 * np.sqrt(link_squared_radius)

        # Define derived throat properties
        network['throat.area'] = gmods.throat_area.cylinder(network)
        network['throat.volume'] = gmods.throat_volume.cylinder(network)
        network['throat.perimeter'] = gmods.throat_perimeter.cylinder(network)
        network['throat.surface_area'] = gmods.throat_surface_area.cylinder(
            network)

        # Define primitive pore properties
        network['pore.index'] = np.arange(number_of_nodes)
        network['pore.coords'] = np.column_stack([x, y, z])
        network['pore.diameter'] = np.zeros(number_of_nodes)

        # Define derived pore properties
        network['pore.area'] = gmods.pore_area.sphere(network)
        network['pore.volume'] = gmods.pore_volume.sphere(network)

        return network.project
Beispiel #12
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