Please refresh the page if equations are not rendered correctly.
---------------------------------------------------------------
Creating Phases
OpenPNM中的所有模拟最终都需要知道流体和相的物理和热力学性质。OpenPNM提供了在子模块中计算这些值的框架,以及一组用于预测纯相和混合物性质的基本函数。因为我们不可能支持详尽的物理属性库,所以我们的策略是提供一组合理的默认函数作为一个近似值。当需要更精确的值时,可以使用许多其他包
The classPhase(基础相)
如果仿真过程很简单,那么一个相就足够了。它没有用于计算任何东西的预定义模型,因此必须直接分配已知值(例如粘度)或定义将计算所需值的模型。可以从库中获取模型,也可以自定义模型。我们将在下面介绍所有三个选项
import openpnm as op
import numpy as np
op.visualization.set_mpl_style()
#所有模拟都从定义/创建网络开始。首先创建了一个简单的立方网络,其中包含各种有用的几何属性:Demo
pn = op.network.Demo(shape=[2, 2, 1])
#定义网络后,它作为参数传递给网络模型。
phase1 = op.phase.Phase(network=pn)
print(phase1)
直接赋值
基础相创建一个(几乎)空的模型,每个孔只分配了基本的物理模型例如标准温度和压力。为了使用此对象进行模拟,需要添加一些额外的物理模型。例如,要计算渗透率,我们需要粘度。
在OpenPNM V2中有一个独立的类:Physics 去定义一些物理量,但是在V3 中,这部分内容合并到了Phase这个类里面,有些常见的相已经预定义了许多物理量,如果想要自定义相可以通过本教程后面的add_model方式添加想要的物理模型
因此,让我们直接为phase1分配一个已知值:
phase1['pore.viscosity'] = 0.001 # Pa.s
'''
标量值被扩展到完整的 ndarray
当将标量值分配给字典键时,它被分配给每个孔(或流道)。上述分配的结果如下所示。
'''
phase1['pore.viscosity']
array([0.001, 0.001, 0.001, 0.001])
使用OpenPNM自带的内置模型
如果在存在温度梯度的情况下运行模拟,而粘度是温度的强函数。在这种情况下,需要分配一个孔隙尺度模型,OpenPNM 将运行该模型来计算每个孔隙中的流体粘度。
OpenPNM 中的库包含一些可以使用的通用模型,例如多项式或线性线。四阶多项式可以拟合粘度与温度的实验数据,产生以下系数:
phase1['pore.viscosity'] = 0.001 # Pa.s
a4 = 5.8543E-11
a3 = -7.6756E-08
a2 = 3.7831E-05
a1 = -8.3156E-03
a0 = 6.8898E-01
#这些可以在模型中使用,如下所示:op.models.misc.polynomial
print('Before:', phase1['pore.viscosity'])
f = op.models.misc.polynomial
'''
define: polynomial(target, a, prop):
Calculates a property as a polynomial function of a given property
Parameters
target : Base
The object for which these values are being calculated. Thiscontrols the length of the calculated array, and also provides access to other necessary thermofluid properties.
a : array_like
A list containing the polynomial coefficients, where element 0 in the list corresponds to a0 and so on. Note that no entries can be skipped so 0 coefficients must be sent as 0.
prop : str
The dictionary key containing the independent variable or phaseproperty to be used in the polynomial.
Returns
value : ndarray
Array containing ``Pn(target[prop])``, where ``Pn`` is nth order polynomial with coefficients stored in ``a``.
'''
phase1.add_model(propname='pore.viscosity',
model=f,
a = (a0, a1, a2, a3, a4),
prop='pore.temperature')
print('After:', phase1['pore.viscosity'])
Before: [0.001 0.001 0.001 0.001]
After: [0.00091476 0.00091476 0.00091476 0.00091476]
注意:当使用该函数分配孔隙尺度模型时,它会自动运行,因此它要么覆盖其中的任何值,要么在该位置创建一个新数组。如果一个模型在运行之前需要计算其他信息,可以在add_model()里添加regen_mode='deferred'
phase1.add_model(propname='pore.viscosity',
model=f,
a = (a0, a1, a2, a3, a4),
prop='pore.temperature'
regen_mode='deferred' )
使用孔隙尺度模型最重要的好处是,如果每个模型的属性之一发生更改,它可以重新计算每个模型。为了说明这一点,让我们将温度设置为 300 到 350 K 之间的随机数,在新温度下重新运行模型:
print('Before:', phase1['pore.viscosity'])
phase1['pore.temperature'] = 300.0 + np.random.rand(pn.Np)*50
'''
random.rand(d0, d1, ..., dn)
Random values in a given shape.
Create an array of the given shape and populate it with random samples from a uniform distribution over [0, 1).
Parameters:
d0, d1, …, dnint, optional
The dimensions of the returned array, must be non-negative. If no argument is given a single Python float is returned.
Returns:
outndarray, shape (d0, d1, ..., dn)
Random values.
'''
phase1.regenerate_models()
print('After:', phase1['pore.viscosity'])
'''
Before: [0.00091476 0.00091476 0.00091476 0.00091476]
After: [0.00066419 0.00077815 0.00065211 0.00060267]
'''
使用特定相模型例如‘水’
#由于水在模拟中非常常见,OpenPNM具有一些可直接使用的属性功能。例如,不需要手动输入数据并去合粘度对于温度的 n 次多项式,因为已经提供了:
print('Before:', phase1['pore.viscosity'])
f = op.models.phase.viscosity.water_correlation
#Calculates viscosity of pure water or seawater at atmospheric pressure.
phase1.add_model(propname='pore.viscosity',
model=f)
print('After:', phase1['pore.viscosity'])
'''
Before: [0.0007246 0.00050654 0.00081815 0.00047741]
After: [0.00069612 0.00047515 0.00079382 0.00044681]
'''
分配新模型将覆盖现有模型并储存在模型中,在本例中,该模型就是我们上面定义的自定义模型。propname='pore.viscostiy'在 pn.models ['pore.viscosity@\']里
自定义模型
创建自定义模型,包含所需的任何功能,就像定义一个新的 python 函数一样简单:
def custom_mu(phase, temperature='pore.temperature'):
T = phase[temperature]
a4 = 5.8543E-11
a3 = -7.6756E-08
a2 = 3.7831E-05
a1 = -8.3156E-03
a0 = 6.8898E-01
mu = a0 + a1*T + a2*T**2 + a3*T**3 + a4*T**4
return mu
phase1.add_model(propname='pore.viscosity',
model=custom_mu)
print(phase1['pore.viscosity'])
#[0.0007246 0.00050654 0.00081815 0.00047741]
常见流体的类
空气、水和汞的使用非常普遍,OpenPNM 不仅为其属性提供了孔隙尺度模型,而且我们还创建了预定义的类,并且附加了所有适当的模型
water = op.phase.Water(network=pn)
print(water)
从上面的输出中可以看出,已经计算了各种各样的东西,其中大部分来自水的特定孔隙尺度模型。这些可以通过以下方式查看:
print(water.models)
可以看到,这些模型中很多都包含参数(pore.temperature和pore.salinity),这意味着这些模型在运行时会获取参数当前的值,从而使用温度的当前值。
相的种类和多相流设置
纯相
想要创建一个多相流,必须首先创建几个单相:
o2 = op.phase.Species(network=pn, species='oxygen')
print(o2)
如上所示,该类不计算给定物种的任何属性,但在属性中预定义了许多热力学属性
print(o2.params)
#这些参数用于各种属性估计方法。例如,为了计算氧气的粘度,OpenPNM提供了一个函数来实现Stiel和Thodos()的模型:
f = op.models.phase.viscosity.gas_pure_st
o2.add_model(propname='pore.viscosity',
model=f)
print(o2['pore.viscosity'])
'''
[2.01023694e-05 2.01023694e-05 2.01023694e-05 2.01023694e-05]
'''
#此功能需要几条热力学信息,例如临界温度和临界压力。您可以在下面看到所有参数
print(o2.models)
op.models.phase.viscosity.gas_pure_st(
phase,
T='pore.temperature',
Tc='param.critical_temperature',
Pc='param.critical_pressure',
MW='param.molecular_weight',):Calculates the viscosity of a pure gas using the correlation in:
Sharqawy M. H., Lienhard J. H., and Zubair, S. M., Desalination and Water Treatment, 2010.
#当我们重新生成模型时,m模型将获取每个孔隙个体的临界温度值,并重新计算粘度值:
o2.regenerate_models()
print(o2['pore.viscosity'])
'''
[2.01023694e-05 2.01023694e-05 2.01023694e-05 2.01023694e-05]
'''
气相和液相
OpenPNM有一套计算纯相性质的函数,但这些函数对于气体和液体是不同的。因此,我们为气体和液体提供了两个类,并已经定义了适当的模型。这些被称为StandardLiquid和StandardGas,以表明所使用的模型是提供第一近似的标准选择:
o2 = op.phase.StandardGas(network=pn, species='o2')
h2o = op.phase.StandardLiquid(network=pn, species='h2o')
print(o2)
print(h2o)
print(h2o.models)
单相混合物
要创建一个单相混合物,我们必须首先指定单个对象。下面我们使用op.phase.StandardGasMixture,它是基本类,但已经附加了用于计算组件属性的各种模型:
o2 = op.phase.StandardGas(network=pn, species='o2', name='oxygen')
n2 = op.phase.StandardGas(network=pn, species='n2', name='nitrogen')
air = op.phase.StandardGasMixture(network=pn, components=[o2, n2])
air.y(o2, 0.21)
air.y(n2, 0.79)
air.regenerate_models()
print(air)
改变混合相的组成,混合相的相关属性会重新计算:
print(o2['pore.viscosity'])
print('Before:', air['pore.viscosity'])
air.y(o2, 0.8)
air.y(n2, 0.2)
air.regenerate_models()
print('After:', air['pore.viscosity'])
'''
[2.01023694e-05 2.01023694e-05 2.01023694e-05 2.01023694e-05]
Before: [1.78543425e-05 1.78543425e-05 1.78543425e-05 1.78543425e-05]
After: [2.01881831e-05 2.01881831e-05 2.01881831e-05 2.01881831e-05]
'''
可以通过查询字典键的方法查询混合相的成分和各组分的含量
print(air['pore.mole_fraction'])
{'oxygen': array([0.8, 0.8, 0.8, 0.8]), 'nitrogen': array([0.2, 0.2, 0.2, 0.2])}
print(air['pore.mole_fraction'][o2.name])
#[0.8 0.8 0.8 0.8]
air['pore.mole_fraction'].keys()
#dict_keys(['oxygen', 'nitrogen'])
air.components
'''
{'oxygen': oxygen : ,
'nitrogen': nitrogen : }
'''
air.y()
'''
{'oxygen': array([0.8, 0.8, 0.8, 0.8]),
'nitrogen': array([0.2, 0.2, 0.2, 0.2])}
'''
air.y(o2.name)
#array([0.8, 0.8, 0.8, 0.8])
单相混合物的相关操作
删除
air.remove_comp(o2.name)
air.components
'''
{'nitrogen': nitrogen : }
'''
#当且仅当出现在混合物字典中时,纯相物质被视为混合物的组成部分。从字典中添加和删除相应的数组实际上是重新定义混合物的组成。'pore.mole_fraction.'
del air['pore.mole_fraction.' + n2.name]
air.components
'''
{}
'''
#可以以相同的方式重新添加它们:
air['pore.mole_fraction.' + o2.name] = 0.21
air.components
'''
{'oxygen': oxygen : }
'''
#还有一个特定的方法:
air.add_comp(n2, mole_fraction=0.79)
air.components
'''
{'oxygen': oxygen : ,
'nitrogen': nitrogen : }
'''
报告混合物属性 info
air.info
'''
══════════════════════════════════════════════════════════════════════════════
mixture_01 :
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Properties Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.temperature 4 / 4
3 pore.pressure 4 / 4
4 pore.heat_capacity 4 / 4
5 pore.thermal_conductivity 4 / 4
6 pore.viscosity 4 / 4
7 pore.density 4 / 4
8 pore.mole_fraction.oxygen 4 / 4
9 pore.mole_fraction.nitrogen 4 / 4
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Labels Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.all 4
3 throat.all 4
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Component Phases
══════════════════════════════════════════════════════════════════════════════
oxygen :
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Properties Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.temperature.oxygen 4 / 4
3 pore.pressure.oxygen 4 / 4
4 pore.heat_capacity_gas.oxygen 4 / 4
5 pore.heat_capacity.oxygen 4 / 4
6 pore.thermal_conductivity.oxygen 4 / 4
7 pore.viscosity.oxygen 4 / 4
8 pore.density.oxygen 4 / 4
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Labels Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.all.oxygen 4
3 throat.all.oxygen 4
══════════════════════════════════════════════════════════════════════════════
nitrogen :
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Properties Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.temperature.nitrogen 4 / 4
3 pore.pressure.nitrogen 4 / 4
4 pore.heat_capacity_gas.nitrogen 4 / 4
5 pore.heat_capacity.nitrogen 4 / 4
6 pore.thermal_conductivity.nitrogen 4 / 4
7 pore.viscosity.nitrogen 4 / 4
8 pore.density.nitrogen 4 / 4
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Labels Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.all.nitrogen 4
3 throat.all.nitrogen 4
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
'''
获取单相混合物的组分
pore.mole_fraction
air['pore.mole_fraction']
'''
{'oxygen': array([0.21, 0.21, 0.21, 0.21]),
'nitrogen': array([0.79, 0.79, 0.79, 0.79])}
'''
component
d = air.components
print(d.keys())
'''
dict_keys(['oxygen', 'nitrogen'])
'''
用get_comp_vals获取组分的属性
mus = air.get_comp_vals('pore.viscosity')
print(mus)
'''
{'oxygen': array([2.09391006e-05, 2.09391006e-05, 2.09391006e-05, 2.09391006e-05]), 'nitrogen': array([1.69779528e-05, 1.69779528e-05, 1.69779528e-05, 1.69779528e-05])}
'''
#也可以通过询问混合物并附加组件名称来检索组件的属性,如下所示:
air['pore.viscosity.' + o2.name]
'''
array([2.09391006e-05, 2.09391006e-05, 2.09391006e-05, 2.09391006e-05])
'''
检查一致性check_mixture_health
#例如是否所有摩尔分数加起来每个孔 1.0:
print(air.check_mixture_health())
'''
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Key Value
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
mole_fraction_too_low []
mole_fraction_too_high []
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
'''
air.y(o2.name, 0.1)#检查o2含量是否过低(o2含量默认为0.21)
print(air.check_mixture_health())
'''
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Key Value
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
mole_fraction_too_low (4,)
mole_fraction_too_high []
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
'''
使用wildcard () syntax:*
air['pore.viscosity.*']
'''
{'oxygen': array([2.09391006e-05, 2.09391006e-05, 2.09391006e-05, 2.09391006e-05]),
'nitrogen': array([1.69779528e-05, 1.69779528e-05, 1.69779528e-05, 1.69779528e-05])}
'''
Comments NOTHING