Source code for openpnm.models.physics.multiphase._funcs
import numpy as np
from openpnm.models import _doctxt
__all__ = ["conduit_conductance", "late_filling"]
[docs]
@_doctxt
def conduit_conductance(phase, throat_conductance,
throat_occupancy='throat.occupancy',
pore_occupancy='pore.occupancy',
mode='strict', factor=1e-6):
r"""
Determines the conductance of a pore-throat-pore conduit based on the
invaded state of each element.
Parameters
----------
%(phase)s
throat_conductance : str
%(dict_blurb)s throat conductance for transport
pore_occupancy : str
%(dict_blurb)s pore occupancy of the phase associated with ``phase``.
An occupancy of 1 means the pore is completely filled with the phase
and it fully conducts.
throat_occupancy : str
%(dict_blurb)s throat occupancy of the phase associated with
``phase``. An occupancy of 1 means the pore is completely filled
with the phase and it fully conducts.
mode : str
How agressive the method should be when determining if a conduit is
closed. Options are:
========= ============================================================
Mode Description
========= ============================================================
strict If any pore or throat in the conduit is unoccupied by
the given phase, the conduit is closed.
medium If either the throat or both pores are unoccupied, the
conduit is closed
loose Only close the conduit if the throat is unoccupied
========= ============================================================
factor : float (default is 1e-6)
The factor which becomes multiplied to the original conduit's
conductance to severely limit transport, but not set it to zero.
Returns
-------
%(return_arr)s adjusted conductance values
"""
network = phase.network
Tinv = phase[throat_occupancy] < 0.5
P12 = network['throat.conns']
Pinv = phase[pore_occupancy][P12] < 0.5
if mode == 'loose':
mask = Tinv
elif mode == 'medium':
mask = Tinv + np.all(Pinv, axis=1)
elif mode == 'strict':
mask = Tinv + np.any(Pinv, axis=1)
else:
raise Exception('Unrecongnized mode '+mode)
value = phase[throat_conductance].copy()
value[mask] = value[mask]*factor
return value
[docs]
@_doctxt
def late_filling(phase, pressure='pore.pressure',
Pc_star='pore.pc_star',
Swp_star=0.2, eta=3):
r"""
Calculates the fraction of a pore or throat filled with invading fluid
based on the capillary pressure in the invading phase. The invading phase
volume is calculated from:
.. math::
S_{nwp} = 1 - S_{wp}^{*} (P^{*}/P_{c})^{\eta}
Parameters
----------
pressure : str
%(dict_blurb)s capillary pressure in the non-wetting phase (Pc > 0).
Pc_star : str
%(dict_blurb)s minimum pressure required to create an interface
within the pore body or throat. Typically this would be calculated
using the Washburn equation.
Swp_star : float
The residual wetting phase in an invaded pore or throat at a pressure
of ``pc_star``.
eta : float
Exponent controlling the rate at which wetting phase is displaced with
increasing pressure.
Returns
-------
%(return_arr)s fraction of each pore or throat that would be filled with
non-wetting phase at the given phase pressure. This does not account
for whether or not the element is actually invaded, which requires a
percolation algorithm of some sort.
"""
pc_star = phase[Pc_star]
Pc = phase[pressure]
# Remove any 0's from the Pc array to prevent numpy div by 0 warning
Pc = np.maximum(Pc, 1e-9)
Swp = Swp_star*((pc_star/Pc)**eta)
values = np.clip(1 - Swp, 0.0, 1.0)
return values