# [OpenPNM] Part 1——Network

Please refresh the page if equations are not rendered correctly.
---------------------------------------------------------------

# 1. OpenPNM基本介绍

Network;Geometry;Phase;Physics;Algorithm

Network: 生成一个网络实体，包括孔隙（pore）的空间位置，数量，及孔隙的相对距离和孔隙之间的连接情况。

Geometry: 网络模型生成后，孔隙的位置和个数已经有了，但是孔隙（球）与流道（棍）几何信息需要在geometry中确定。

Phase: 网格有了，孔隙和流道几何参数有了，需要明确流动相的参数。

Physics: 定义流动的物理模型及所需参数。

Algorithm:定义算法和边界条件

# 2. Network的相关设置

## 2.1 创建新的网络模型并快速可视化

OpenPNM包括各种网络模型生成器。这里介绍一些常见的网络模型，实现可视化可以直接在Spyder里运行，想要完全可视化最好在专用软件（如paraview或draongfly）中完成。

import openpnm as op
import numpy as np
import matplotlib.pyplot as plt
op.visualization.set_mpl_style()


Definition : set_mpl_style()
Prettifies matplotlib's output by adjusting fonts, markersize etc.

### 2.1.1 从最简单的立方体网络开始：

#快速生成网络模型可以直接调用network里的相关函数
pn = op.network.Cubic(shape=[4, 4, 4], spacing=1e-5)
#Shape[x,y,z]中的x,y,z分别为模型中在x,y,z轴上pore的个数
#spacing指孔隙间距，如果x,y,z轴方向上的孔隙间距相同则spacing=常数，如果不同则spacing=[a,b,c]

#采用下面的代码进行快速可视化，可视化选项后面探讨
ax = op.visualization.plot_coordinates(pn)#将pore可视化为点
ax = op.visualization.plot_connections(pn, ax=ax)#可视化流道为线


Definition : Cubic(shape, spacing=[1, 1, 1], connectivity=6, *, conns=None, coords=None, name='net') decorator(f)
Simple cubic lattice with connectivity from 6 to 26

Though simple, the Cubic network offers many advantages such as easy visualization and accurate determination of domain area and length in transport calculations.

Parameters

shape:array_like
The [Nx, Ny, Nz] size of the network in terms of the number of pores in each direction. For a 2D network

spacing:array_like, optional
The spacing between pore centers in each direction. If not given, then [1, 1, 1] is assumed.

connectivity:int, optional
The number of connections to neighboring pores. Connections are made symmetrically to any combination of face, edge, or corners neighbors. The default is 6 to create a simple cubic structure, but options are:
6 : Faces only
14 : Faces and Corners
18 : Faces and Edges
20 : Edges and Corners
26 : Faces, Edges and Corners

For a more random distribution of connectivity, use a high connectivity (i.e. 26) and then delete a fraction of the throats using openpnm.topotools.reduce_coordination. Also note that corners-only and edges-only are not permitted since they create disconnected networks. If you require one of these topologies you can specify 14 or 18, then use openpnm.topotools.trim to remove the face-to-face connections, which can be identified by looking for throats with a length equal to the network spacing.

pn = op.network.Cubic(shape=[8, 4, 2], spacing=[10e-5, 5e-5, 4e-5])
ax = op.visualization.plot_coordinates(pn)
ax = op.visualization.plot_connections(pn, ax=ax)


pn = op.network.Cubic(shape=[4, 4, 4], connectivity=26)
#spacing不写则默认流道长度为1
#connectivity Must be 6, 14, 18, 20 or 26.
ax = op.visualization.plot_coordinates(pn)
ax = op.visualization.plot_connections(pn, ax=ax)


OpenPNM可以通过:
np.random.seed(0)
np.random.randint

pn = op.network.Cubic(shape=[4, 4, 4], connectivity=26)
np.random.seed(0)
'''
seed( ) 用于指定随机数生成时所用算法开始的整数值。
1.如果使用相同的seed( )值，则每次生成的随机数都相同；
2.如果不设置这个值，则系统根据时间来自己选择这个值，此时每次生成的随机数因时间差异而不同。
3.设置的seed()值仅一次有效
'''
drop = np.random.randint(0, pn.Nt, 500)
'''

'''
op.topotools.trim(network=pn, throats=drop)
#drop中所有的元素对应流道的编号，删除这些元素对应编号的流道
ax = op.visualization.plot_coordinates(pn)
ax = op.visualization.plot_connections(pn, ax=ax)
'''
print('The total number of pores on the network is:', pn.num_pores())
print('A short-cut to the total number of pores is:', pn.Np)
print('The total number of throats on the network is:', pn.num_throats())
print('A short-cut to the total number of throats is:', pn.Nt)
print('A list of all calculated properties is availble with:\n', pn.props())
'''


numpy.random.randint(low, high=None, size=None, dtype='l')

low: int

（hign = None时，生成的数值要在0到low区间内）

high: int (可选)

size: int or tuple of ints(可选)

dtype: dtype(可选)：

out: int or ndarray of ints

### 2.1.2 查看网络模型的详细信息

print(pn)


Ps = pn.pores('back')
print("The following pores are labelled 'back':", Ps)
Ps = pn.pores(['back', 'left'])
print("The following pores are labelled 'back' AND 'left':", Ps)
'''
The following pores are labelled 'back': [12 13 14 15 28 29 30 31 44 45 46 47 60 61 62 63]
The following pores are labelled 'back' AND 'left': [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 28 29 30 31 44 45 46 47
60 61 62 63]
'''

Ts = pn.throats('surface')
print("The following throats are labelled 'surface':", Ts)
'''
The following throats are labelled 'surface': [  0   1   2   3   4   5   6  11  12  14  15  16  17  18  19  20  21  22
23  24  27  28  29  30  32  33  34  35  36  37  38  41  42  43  44  45
48  49  52  53  56  58  59  61  64  67  68  69  71  73  76  77  80  83
85  86  89  90  91  93  97  99 100 105 109 110 111 112 113 115 119 120
121 122 124 126 130 131 133 134 135 136 139 140 141 143 144 146 147 148
149 150 151 153 154 160]
'''


### 2.1.3 立方体模板

OpenPNM可以制作具有任意形状的立方网络，例如球体或圆柱体，甚至更复杂的网络，尽管它仍由立方体单元组成。

im = op.topotools.template_cylinder_annulus(z=3, r_outer=8, r_inner=3)
pn = op.network.CubicTemplate(template=im)
ax = op.visualization.plot_coordinates(pn)
ax = op.visualization.plot_connections(pn, ax=ax)


import openpnm as op
import numpy as np
import matplotlib.pyplot as plt
op.visualization.set_mpl_style()
fcc = op.network.FaceCenteredCubic(shape=[4, 4, 4], spacing=1e-5)
ax = op.visualization.plot_connections(fcc)
op.visualization.plot_coordinates(fcc, ax=ax)
#面心立方晶格

bcc = op.network.BodyCenteredCubic(shape=[4, 4, 4], spacing=1e-5)
ax = op.visualization.plot_connections(bcc)
ax = op.visualization.plot_coordinates(bcc, ax=ax);
#体心立方晶格


Definition : FaceCenteredCubic(shape, mode='sc', spacing=1, *, conns=None, coords=None, name='net')
Face-Centered Cubic lattice which is a simple cubic lattice with additional pores located on each face of the cubic unit cells. These pores are connected to each other and their diagonal neighbors.

Parameters

shape:array_like
The number of pores forming the corners of the unit cell in each direction

spacing:array_like (optional)
The spacing between pores that form the corners of the unit cells

%(Network.parameters)s

Cubic BodyCenteredCubic

Notes
The pores are labelled as beloning to 'corner_sites' and 'face_sites' Throats are labelled by the which type of pores they connect, e.g. 'throat.corner_to_body'.

print(bcc)


ax = op.visualization.plot_connections(bcc, throats=bcc.throats('body_to_body'))
ax = op.visualization.plot_coordinates(bcc, pores=bcc.pores('body'), ax=ax)


ax = op.visualization.plot_connections(bcc, throats=bcc.throats('body_to_body'))
ax = op.visualization.plot_coordinates(bcc, pores=bcc.pores('body'), ax=ax)
ax = op.visualization.plot_connections(bcc, throats=bcc.throats('corner_to_body'), c='g', ax=ax)
ax = op.visualization.plot_coordinates(bcc, pores=bcc.pores('corner'), ax=ax, c='orange')
#c=  表示定义颜色，放在最后


### 2.1.4 随机网络模型：Delaunay and Voronoi Tessellations

Delaunay and Voronoi Tessellations的相关解释可以参考：https://www.cnblogs.com/sddai/p/5740172.html

OpenPNM 还可以轻松处理随机网络，因为拓扑是以完全通用的方式存储的，将在后面的教程中讨论。

pn = op.network.Voronoi(shape=[1, 1, 1], points=100)
ax = op.visualization.plot_connections(pn)
ax = op.visualization.plot_coordinates(pn, ax=ax)


Definition : Voronoi(shape, points, trim=True, reflect=True, *, conns=None, coords=None, name='net')
Random network formed by Voronoi tessellation of arbitrary base points.

Parameters

points:array_like or int
Can either be an N-by-D array of point coordinates which will be used directly, or a scalar value indicating the number of points to generate. If 3D points are supplied, and a 2D shape is specified, then the z-coordinate is ignored.See Notes for more details.

shape:array_like
The size and shape of the domain:
| shape | result |
| ------------ | ------------ |
| [x, y, z] | A 3D cubic domain of dimension x, y and z |
| [x, y, 0] | A 2D square domain of size x by y |
trim:bool, optional
If True (default) then all Voronoi vertices laying outside the domain will be removed.

reflect:bool, optional
If True (default) then the base points will be reflected across all the faces of the domain prior to performing the tessellation. This feature is best combined with trim=True to make nice flat faces on all sides of the domain.

%(Network.parameters)s

Notes

These points are used by the Voronoi tessellation, meaning these points will each lie in the center of a Voronoi cell, so they will not be the pore centers. The number of pores in the returned network will greater that the number of points supplied or requested.

It is also possible to generate circular [r, 0], cylindrical [r, z], and spherical domains [r], but this feature does not quite work as desired. It does not produce a truly clean outer surface since the tessellation are conducted in cartesian coordinates, so the circular and spherical surfaces have artifacts. Scipy recently added the ability to do tessellations on spherical surfaces, for geological applications, but this is not flexible enough, yet.

Delaunay tessellation

Definition : Delaunay(f) Delaunay(shape, points, reflect=True, trim=True, *, conns=None, coords=None, name='net')
Random network formed by Delaunay tessellation of arbitrary base points

Parameters

points:array_like or int
Can either be an N-by-D array of point coordinates which will be used, or a scalar value indicating the number of points to generate. If 3D points are supplied, and a 2D shape is specified, then the z-coordinate is ignored.

shape:array_like
The size and shape of the domain:

[x, y, z]
A 3D cubic domain of dimension x, y and z

[x, y, 0]
A 2D square domain of size x by y

trim:bool, optional
If True (default) then all vertices laying outside the domain will be removed. This is only useful if reflect=True.

reflect:bool, optional
If True (default) then the base points will be reflected across all the faces of the domain prior to performing the tessellation. This feature is best combined with trim=True to prevent unreasonably long connections between points on the surfaces.

%(Network.parameters)s

Notes

It is also possible to generate circular [r, 0], cylindrical [r, z], and spherical domains [r], but this feature does not quite work as desired. It does not produce a truly clean outer surface since the tessellation are conducted in cartesian coordinates, so the circular and spherical surfaces have artifacts. Scipy recently added the ability to do tessellations on spherical surfaces, for geological applications, but this is not flexible enough, yet.

pn = op.network.Delaunay(shape=[1, 1, 1], points=100)
ax = op.visualization.plot_connections(pn)
ax = op.visualization.plot_coordinates(pn, ax=ax)


pn = op.network.DelaunayVoronoiDual(shape=[1, 1, 1], points=100)
ax = op.visualization.plot_connections(pn)
ax = op.visualization.plot_coordinates(pn, ax=ax);


#圆柱
cyl = op.network.Voronoi(shape=[1, 1], points=200)
ax = op.visualization.plot_connections(cyl)
ax = op.visualization.plot_coordinates(cyl, ax=ax);

#球
sph = op.network.Voronoi(shape=[1], points=400)
ax = op.visualization.plot_connections(sph)
ax = op.visualization.plot_coordinates(sph, ax=ax);


### 2.1.5 导入网络模型

coords = [[0, 0, 0],  # coordinates for pore 0
[1, 0, 0],  # coordinates for pore 1
[1, 1, 0],  # coordinates for pore 2
[0, 1, 0]]  # coordinates for pore 3
conns = [[0, 1],  # throat 0 connects pores 0 and 1
[1, 2],  # throat 1 connects pores 1 and 2
[2, 3],  # throat 2 connects pores 2 and 3
[0, 3]]  # throat 3 connects pores 0 and 3
Dpore = [1,  # diameter for pore 0
2,  # diameter for pore 1
1,  # diameter for pore 2
3,]  # diameter for pore 3
Dthroat = [0.5,  # diameter for throat 0
0.2,  # diameter for throat 1
0.8,  # diameter for throat 2
0.7]  # diameter for throat 3

pn = op.network.Network(coords=coords, conns=conns)
ax = op.visualization.plot_connections(pn)
ax = op.visualization.plot_coordinates(pn, ax=ax)


Definition : Network(f) Network(conns=None, coords=None, name='net')
This class contains the main functionality used by all networks.

Parameters

settings:dataclass-like or dict, optional
User defined settings for the object to override defaults. Can be a dataclass-type object with settings stored as attributes or a python dicionary of key-value pairs. Settings are stored in the settings attribute of the object.

name:str, optional
A unique name to assign to the object for easier identification. If not given one will be generated.

coords:array_like (optional)
An Np-by-3 array of [x, y, z] coordinates for each pore

conns:array_like (optional)
An Nt-by-2 array of [head, tail] connections between pores

pn['pore.diameter'] = Dpore
pn['throat.diameter'] = Dthroat


ax = op.visualization.plot_connections(pn, color_by=pn['throat.diameter'], linewidth=4)
ax = op.visualization.plot_coordinates(pn, size_by=pn['pore.diameter'], markersize=500, ax=ax)


OpenPNM有一个模块 .io，可以从各种文件格式读取以及输出限的数量孔隙、流道信息，这个后面再说。

## 2.2 网络数据和拓扑的储存

OpenPNM 使用 Numpy 存储所有数据

OpenPNM 的所有对象都是子类化的 python 字典。

- The Spreadsheet Analogy
- Maintaining Data Integrity
- Representing Topology

### 2.2.1 Spreadsheet Analogy

OpenPNM中数据存储方式与电子表格类似，可以理解为OpenPNM所有数据存储在两个表中，一个用于储存孔隙数据，一个用于储存流道数据。每个孔隙（或流道）对应于一行，每个属性对应于一列。考虑以下具有 4 个孔隙、3 个流道的网络：

import openpnm as op
import numpy as np
op.visualization.set_mpl_style()
'''
Definition : set_mpl_style()
Prettifies matplotlib's output by adjusting fonts, markersize etc.
'''
np.random.seed(0)
pn = op.network.Demo(shape=[4, 1, 1])
'''
Definition : Demo(shape=[3, 3, 1], *, spacing=[1, 1, 1], connectivity=6, conns=None, coords=None, name='net')
A shortcut for generating a cubic network with geometrical properties already added.
'''


OpenPNM里的每个参数比如孔隙直径都是通过键值对储存在子类化的字典中的，孔隙直径为键（key），所有孔隙直径的数值组成的数组为值（value），ndim表示数组的维度，相关解释可以参考：https://blog.csdn.net/weixin_32767137/article/details/111950662

import pandas as pd
pore_data_sheet = pd.DataFrame({k: pn[k] for k in pn.props(element='pore') if pn[k].ndim == 1})
pore_data_sheet


Pandas 数据结构 - DataFrame
DataFrame 是一个表格型的数据结构，它含有一组有序的列，每列可以是不同的值类型（数值、字符串、布尔型值）。
DataFrame 既有行索引也有列索引，它可以被看做由 Series 组成的字典（共同用一个索引）。

column = pore_data_sheet['pore.volume']
print(column)
'''
0    0.055905
1    0.090773
2    0.065994
3    0.055213
Name: pore.volume, dtype: float64
'''

#或者查看单个元素
print(pore_data_sheet['pore.volume'][0])
'''
0.05590507143096387
'''


### 2.2.2 维护数据完整性的规则

#### 所有 values 都转换为 numpy 数组

pn['throat.list'] = [1, 2, 3]
print(type(pn['throat.list']))
#
#这说明基本的python列表类型在存储在字典中时已转换为Numpy数组


#### 字典键（key）必须以“pore”或“throat”开头

#字典键（key）必须以“pore”或“throat”开头，用于标识它们包含的信息类型。
try:
pn['foo.bar'] = 0
except:
print('This will throw an exception since the dict name cannot start with foo')
#This will throw an exception since the dict name cannot start with foo


try:
pn['pore.test'] = [0, 0, 0]
except:
print('This will throw an exception since there are 4 pores, hence all pore arrays should be 4 elements long')
#This will throw an exception since there are 4 pores, hence all pore arrays should be 4 elements long


#### 任何标量都扩展为长度为Np或Nt向量

pn['pore.test'] = 0
print(pn['pore.test'])
[0 0 0 0]


#### 字典名是可以嵌套的

pn['pore.concentration'] = {'species_A': 0, 'species_B': 1}
print(pn['pore.concentration'])
'''
{'species_A': array([0, 0, 0, 0]), 'species_B': array([1, 1, 1, 1])}

'''
#可以直接访问字典键对应的值：
print(pn['pore.concentration.species_A'])
'''
[0 0 0 0]
'''
#也可以直接检索字典：
pn['pore.concentration']
pn['pore.concentration']['species_A']
'''
{'species_A': array([0, 0, 0, 0]), 'species_B': array([1, 1, 1, 1])}
array([0, 0, 0, 0])
'''


#### 布尔数组视为标签，数值数组视为属性

print(pn)

pn['pore.label'] = False
print(pn['pore.label'])
print(pn.labels(element='pore'))
print(pn)
'''
[False False False False]
pn['pore.label']为四个元素全为False的一维数组，意思是网络模型里的四个孔隙都没有加上pore.label的标签
['pore.label', 'pore.left', 'pore.right', 'pore.surface']
'''


pn.pores('label')
array([], dtype=int64)


pn['pore.label'][[0, 1, 2]] = True #表示编号为0，1，2的孔隙添加上了pore.label的标签
print(pn.pores('label'))
#[0 1 2]


pn.set_label('another', pores=[2, 3])
print(pn.pores('another'))
#[2 3]


#### 带有前置下划线的字典键是隐藏的

pn['pore._hidden'] = 1
print(pn.props())
pn['pore._hidden']
#array([1, 1, 1, 1])
print('pore._hidden' in pn.keys())
#True


### 2.2.3 前缀param

OpenPNM将所有标量值扩展为和Np或Nt一样长的数组是为了方便，这样就可以将参数X（key）的值（value）赋予给所有的孔隙，并且参数X在每个孔隙或者流道中可能具有不同的值。但是，有些特性是定值，例如分子量或临界温度。现在演示将定值属性引入所有对象pn.params

pn.params['lattice_connectivity'] = 6
print(pn.params)


pn['param.test'] = 2
print(pn.params)


### 2.2.4 拓扑

np.random.seed(0)
dn = op.network.Delaunay(points=4, shape=[1, 1, 0])
op.visualization.plot_tutorial(dn);


OpenPNM如何存储拓扑的基本前提可以用一句话来说明：

print(dn['throat.conns'])
'''
[[0 1]
[0 2]
[0 3]
[1 3]
[2 3]]
'''


### 2.2.5 conduit数据

OpenPNM中的conduit是指“孔-流道-孔”连接，其中孔和流道分别称为元素。这些元件串联起电阻(或导体)的作用。每个conduit恰好包含1个喉道和2个孔。网络内的传输是通过这些相互连接的管道进行的，因此这些元素的几何性质通常需要用于计算扩散等东西。这很常见，OpenPNM V3包含了一个新的helper函数来获取这些数据，如下所示:

D = pn.get_conduit_data('diameter')
print(D)
'''
[[0.47440675 0.23720338 0.55759468]
[0.55759468 0.25069084 0.50138169]
[0.50138169 0.2362208  0.47244159]]
'''
#上面的数组包含 3 列，中间列代表流道直径
print(pn['throat.diameter'])
'''
[0.23720338 0.25069084 0.2362208 ]
'''
#左右列代表流道两端孔的直径。“左”与“右”的顺序反映了数组的孔隙编号。'throat.conns'
print(pn.conns)
'''
[[0 1]
[1 2]
[2 3]]
'''
#孔的直径值可以使用numpy的索引获得
R1_R2 = pn['pore.diameter'][pn.conns]
print(R1_R2)
'''
[[0.47440675 0.55759468]
[0.55759468 0.50138169]
[0.50138169 0.47244159]]
'''


## 2.3 网络模型的显示、查询和操作

import openpnm as op
import numpy as np
import matplotlib.pyplot as plt
op.visualization.set_mpl_style()


### 2.3.1 邻接矩阵

Definition : create_adjacency_matrix(weights=None, fmt='coo', triu=False, drop_zeros=False)

weights：array_like，可选

fmt：str，可选

coo：这是OpenPNM数据的默认格式
lil：启用矩阵的逐行切片
csr：受大多数线性代数例程的青睐
dok：启用位置的下标访问

triu:bool，默认为False

drop_zers:bool，默认为False

Returns：

pn = op.network.Cubic(shape=[3, 2, 1], connectivity=26)
print(am)
'''
[[0 1 1 1 0 0]
[1 0 1 1 0 0]
[1 1 0 1 1 1]
[1 1 1 0 1 1]
[0 0 1 1 0 1]
[0 0 1 1 1 0]]
'''


print(pn.pores())
print(pn.throats())
op.visualization.plot_tutorial(pn)
'''
[0 1 2 3 4 5]
[ 0  1  2  3  4  5  6  7  8  9 10]
'''


#### 2.3.1.1 邻接矩阵的默认稀疏格式

am = pn.create_adjacency_matrix(triu=True)
print(am)
'''
(0, 1)    1
(2, 3)    1
(4, 5)    1
(0, 2)    1
(1, 3)    1
(2, 4)    1
(3, 5)    1
(0, 3)    1
(2, 5)    1
(1, 2)    1
(3, 4)    1
'''


am = pn.create_adjacency_matrix(weights=pn.Ts, triu=True)
print(am)
'''
(0, 1)    0
(2, 3)    1
(4, 5)    2
(0, 2)    3
(1, 3)    4
(2, 4)    5
(3, 5)    6
(0, 3)    7
(2, 5)    8
(1, 2)    9
(3, 4)    10
'''


#### 2.3.1.2 其他稀疏格式

#查询孔 i 和那些孔相连
am = pn.create_adjacency_matrix(weights=pn.Ts, fmt='lil', triu=False)
for locations_of_nonzeros in am.rows:
print(locations_of_nonzeros)
'''
[1, 2, 3]
[0, 2, 3]
[0, 1, 3, 4, 5]
[0, 1, 2, 4, 5]
[2, 3, 5]
[2, 3, 4]
'''


0 [1, 2, 3] ——0号孔和1，2，3号孔相连
1 [0, 2, 3] ——1号孔和0，2，3号孔相连
2 [0, 1, 3, 4, 5] ——2号孔和0, 1, 3, 4, 5号孔相连
3 [0, 1, 2, 4, 5] ——3号孔和0, 1, 2, 4, 5号孔相连
4 [2, 3, 5] ——4号孔和2, 3, 5号孔相连
5 [2, 3, 4] ——5号孔和2, 3, 4号孔相连

for values_of_nonzeros in am.data:
print(values_of_nonzeros)
'''
[0, 3, 7]
[0, 9, 4]
[3, 9, 1, 5, 8]
[7, 4, 1, 10, 6]
[5, 10, 2]
[8, 6, 2]
'''


https://zhuanlan.zhihu.com/p/188700729

#### 2.3.1.3 关联矩阵

im = pn.create_incidence_matrix().todense()
print(im)
'''
[[1 0 0 1 0 0 0 1 0 0 0]
[1 0 0 0 1 0 0 0 0 1 0]
[0 1 0 1 0 1 0 0 1 1 0]
[0 1 0 0 1 0 1 1 0 0 1]
[0 0 1 0 0 1 0 0 0 0 1]
[0 0 1 0 0 0 1 0 1 0 0]]
'''


### 2.3.2 OpenPNM的查询操作

pn = op.network.Cubic(shape=[4, 4, 1])
#查找特定标签的孔或者流道信息
P_left = pn.pores('left')
P_bottom = pn.pores('back')
print(P_left)
print(P_bottom)
'''
[0 1 2 3]
[ 3  7 11 15]
'''


#### 2.3.2.1 查询网络中孔的相关信息

fig, ax = plt.subplots()
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red', marker='*',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue', marker='.',
markersize=50, ax=ax);


Ps = pn.pores(['left', 'back'])
print(Ps)
Ps = pn.find_neighbor_pores(pores=Ps, mode='or')
print(Ps)
'''
[ 0  1  2  3  7 11 15]
[ 4  5  6 10 14]
'''


mode='or'查找与输入孔之间存在流道的其他所有孔

fig, ax = plt.subplots()
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue',
markersize=50, marker='.', ax=ax)
op.visualization.plot_coordinates(pn, Ps, c='green',
markersize=50, marker='s', ax=ax);


'mode='xor' 查找只与输入孔隙列表中的一个孔相连的其他所有孔孔隙

Ps = pn.pores(['left', 'back'])
print(Ps)
Ps = pn.find_neighbor_pores (pores=Ps, mode='xor')
print(Ps)
'''
[ 0  1  2  3  7 11 15]
[ 4  5 10 14]
'''
fig, ax = plt.subplots()
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue',
markersize=50, marker='.', ax=ax)
op.visualization.plot_coordinates(pn, Ps, c='green',
markersize=50, marker='s', ax=ax);


mode='xnor'查找与输入孔隙列表中的 2 个或更多孔隙连接的其他所有孔

Ps = pn.pores(['left', 'back'])
print(Ps)
Ps = pn.find_neighbor_pores(pores=Ps, mode='xnor')
print(Ps)
'''
[ 0  1  2  3  7 11 15]
[6]
'''
fig, ax = plt.subplots()
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue',
markersize=50, marker='.', ax=ax)
op.visualization.plot_coordinates(pn, Ps, c='green',
markersize=50, marker='s', ax=ax);


#### 2.3.2.2 查找与指定孔隙相连的流道

mode='or'：

Ps = pn.pores(['left', 'back'])
Ts = pn.find_neighbor_throats(pores=Ps, mode='or')
fig, ax = plt.subplots()
op.visualization.plot_connections(pn, Ts, ax=ax)
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue',
markersize=50, marker='.', ax=ax);


'mode='xnor' 仅查找输入孔之间的流道

Ps = pn.pores(['left', 'back'])
Ts = pn.find_neighbor_throats(pores=Ps, mode='xnor')
fig, ax = plt.subplots()
op.visualization.plot_connections(pn, Ts, ax=ax)
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue',
markersize=50, marker='.', ax=ax);


mode=xor查找仅与输入孔中一个孔相连的流道

Ps = pn.pores(['left', 'back'])
Ts = pn.find_neighbor_throats(pores=Ps, mode='xor')
fig, ax = plt.subplots()
op.visualization.plot_connections(pn, Ts, ax=ax)
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P_left, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P_bottom, c='blue',
markersize=50, marker='.', ax=ax);


find_connecting_throats

P1 = [0, 1, 2, 3]
P2 = [4, 5, 6, 7]
Ts = pn.find_connecting_throat(P1, P2)
print(Ts)
#[12 13 14 15]
fig, ax = plt.subplots()
op.visualization.plot_connections(pn, Ts, ax=ax)
op.visualization.plot_coordinates(pn, pn.Ps, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_coordinates(pn, P1, c='red',
markersize=50, marker='*', ax=ax)
op.visualization.plot_coordinates(pn, P2, c='blue',
markersize=50, marker='.', ax=ax);


P1 = [0, 1, 2, 3]
P2 = [7, 7, 7, 7]
Ts = pn.find_connecting_throat(P1, P2)
print(Ts)
#[nan nan nan 15.]


find_connected_porespn['throat.conns']

Ps = pn.find_connected_pores(throats=[0, 1, 2])
print(Ps)
'''
[[0 1]
[1 2]
[2 3]]
'''
Ps = pn['throat.conns'][[0, 1, 2]]
print(Ps)
'''
[[0 1]
[1 2]
[2 3]]
'''

#通常有一些孔隙编号是重复项。这可以通过以下方式消除：np.unique
print(np.unique(Ps))
'''
[0 1 2 3]
'''

#该方法有一个执行相同操作的参数：find_connected_poresflatten
Ps = pn.find_connected_pores(throats=[0, 1, 2], flatten=True)
print(Ps)
'''
[0 1 2 3]
'''


### 2.3.3 删除操作

#### 删除流道

pn = op.network.Cubic(shape=[3, 2, 1])
print(pn)
print(pn.Ts)
'''
[0,1,2,3,4,5,6]
'''


mask = np.ones(pn.Nt, dtype=bool)
mask[[0, 3]] = False
print(pn)
print(pn.Ts)
'''
[0，1，2，3，4]

'''


Definition : trim(network, pores=[], throats=[])
Remove pores or throats from the network

Parameters

networkNetwork
The Network from which pores or throats should be removed

pores (or throats)array_like
The indices of the of the pores or throats to be removed from the network.

pn = op.network.Cubic(shape=[3, 2, 1])
print(pn)
op.topotools.trim(network=pn, throats=[0, 3])
print(pn)
print(pn.Ts)


#### 删除孔

pn = op.network.Cubic(shape=[3, 2, 1])
op.topotools.trim(network=pn, pores=[2, 4])
fig, ax = plt.subplots()
op.visualization.plot_coordinates(pn, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_connections(pn, ax=ax);


### 2.3.4 增加孔或者流道的操作

Definition : extend(network, coords=[], conns=[], labels=[], **kwargs)
Add pores or throats to the network from a list of coords or conns.

Parameters

network:Network
The network to which pores or throats should be added

coords:array_like
The coordinates of the pores to add. These will be appended to the 'pore.coords' array so should be of shape N-by-3, where N is the number of pores in the list.

conns:array_like
The throat connections to add. These will be appended to the 'throat.conns' array so should be of shape N-by-2. Note that the numbering must point to existing pores.

labels:str, or list[str], optional
A list of labels to apply to the new pores and throats

pn = op.network.Cubic(shape=[3, 2, 1])
new_pores = [[1.5, 2.5, 0.5], [3, 1, 0.5]]
new_conns = [[1, 6], [4, 7], [5, 7]]
op.topotools.extend(network=pn, coords=new_pores)
op.topotools.extend(network=pn, conns=new_conns)
fig, ax = plt.subplots()
op.visualization.plot_coordinates(pn, c='lightgrey',
markersize=50, ax=ax)
op.visualization.plot_connections(pn, ax=ax);


Everything not saved will be lost.