Relative Permeability#

This is an example of relative permeability calculation using Metrics algorithm in OpenPNM. First, we create a network and assign geometry,phases and physics in a similar way that we used to do for the other examples.

[1]:
import numpy as np
import pandas as pd
import openpnm as op
%config InlineBackend.figure_formats = ['svg']
import openpnm.models.physics as pmods
import matplotlib.pyplot as plt
[2]:
pn = op.network.Cubic(shape=[15,15,15], spacing=6e-5)
geom = op.geometry.SpheresAndCylinders(network=pn, pores=pn['pore.all'],
                                throats=pn['throat.all'])
air = op.phases.Air(network=pn,name='air')
water = op.phases.Water(network=pn,name='water')
air.add_model(propname='throat.hydraulic_conductance',
              model=pmods.hydraulic_conductance.hagen_poiseuille)
air.add_model(propname='throat.entry_pressure',
              model=pmods.capillary_pressure.washburn)
water.add_model(propname='throat.hydraulic_conductance',
                model=pmods.hydraulic_conductance.hagen_poiseuille)
water.add_model(propname='throat.entry_pressure',
                model=pmods.capillary_pressure.washburn)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [2], in <cell line: 4>()
      1 pn = op.network.Cubic(shape=[15,15,15], spacing=6e-5)
      2 geom = op.geometry.SpheresAndCylinders(network=pn, pores=pn['pore.all'],
      3                                 throats=pn['throat.all'])
----> 4 air = op.phases.Air(network=pn,name='air')
      5 water = op.phases.Water(network=pn,name='water')
      6 air.add_model(propname='throat.hydraulic_conductance',
      7               model=pmods.hydraulic_conductance.hagen_poiseuille)

AttributeError: module 'openpnm' has no attribute 'phases'

The only other argument that needs to be passed to the metrics relative permeability is the invasion sequence (We made it as a user defined sequence, so that the user has the option to implement the drainage process in any direction using any algorithm). The invasion sequence can be obtained by implementing an Invasion Percolation on the network. Asumming a drainage process, the air(invading/non-wetting phase) will be invading the medium.

In the following code, we can find the invasion sequence applying an invasion percolation through a user-defined inlet face (here from the left surface pores in the x direction). By updating the air phase, the invasion sequence can then be found using the phase occupancy which is a property of the phase. This calculation is all done inside the metrics relative permeability algorithm without any user contribution. We encourage the users to reach the available source code of this algorithm for more information.

[3]:
ip = op.algorithms.InvasionPercolation(network=pn, phase=air)
Finlets= pn.pores('top')
ip.set_inlets(pores=Finlets)
ip.run()
air.update(ip.results())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 ip = op.algorithms.InvasionPercolation(network=pn, phase=air)
      2 Finlets= pn.pores('top')
      3 ip.set_inlets(pores=Finlets)

NameError: name 'air' is not defined

Having the network and invasion sequence, we can now use the metrics relative permeability algorithm. These are the minimum required arguments for the algorithm to be run. If we do not pass the defending phase to the algorithm, it does not give us any report related to the defendin phase relative permeability. If we do not define the flow direction, it will automatically calculate the relative permeability in all three directions

[4]:
rp = op.algorithms.metrics.RelativePermeability(network=pn)
rp.settings.update({'nwp': 'air',
                    'invasion_sequence': 'invasion_sequence'})
rp.run(Snwp_num=10)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 rp = op.algorithms.metrics.RelativePermeability(network=pn)
      2 rp.settings.update({'nwp': 'air',
      3                     'invasion_sequence': 'invasion_sequence'})
      4 rp.run(Snwp_num=10)

AttributeError: module 'openpnm.algorithms' has no attribute 'metrics'

Once the algorithm is run, the output can either be a table of values or a graph showing the relative permeability curves of the phase(s). Here we call both of those methods to see the outputs.

[5]:
results=rp.get_Kr_data()
pd.DataFrame(results['kr_nwp'])
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [5], in <cell line: 1>()
----> 1 results=rp.get_Kr_data()
      2 pd.DataFrame(results['kr_nwp'])

NameError: name 'rp' is not defined
[6]:
fig = rp.plot_Kr_curves()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [6], in <cell line: 1>()
----> 1 fig = rp.plot_Kr_curves()

NameError: name 'rp' is not defined

In order to get the relative permeability curves of both phases, we need to pass the defending phase as an argument to the algorithm.

[7]:
rp = op.algorithms.metrics.RelativePermeability(network=pn)
rp.settings.update({'nwp': 'air',
                    'wp': 'water',
                    'invasion_sequence': 'invasion_sequence'})
rp.run(Snwp_num=10)
fig = rp.plot_Kr_curves()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [7], in <cell line: 1>()
----> 1 rp = op.algorithms.metrics.RelativePermeability(network=pn)
      2 rp.settings.update({'nwp': 'air',
      3                     'wp': 'water',
      4                     'invasion_sequence': 'invasion_sequence'})
      5 rp.run(Snwp_num=10)

AttributeError: module 'openpnm.algorithms' has no attribute 'metrics'

The algorithm can also find the relative permeabilities of the phase(s) in the user-defined flow direction(s). The algorithm overwrites the flow inlets/outlets for the user-defined direction. Then calculates the relative permeability through the other directions from the default settings. This is illustrated as following.

[8]:
rp = op.algorithms.metrics.RelativePermeability(network=pn)
inlets = {'x': 'top'}
outlets = {'x': 'bottom'}
rp.settings.update({'nwp': 'air',
                    'wp': 'water',
                    'invasion_sequence': 'invasion_sequence'
                            })
rp.settings['flow_inlets'].update(inlets)
rp.settings['flow_outlets'].update(outlets)
rp.run(Snwp_num=10)
fig = rp.plot_Kr_curves()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [8], in <cell line: 1>()
----> 1 rp = op.algorithms.metrics.RelativePermeability(network=pn)
      2 inlets = {'x': 'top'}
      3 outlets = {'x': 'bottom'}

AttributeError: module 'openpnm.algorithms' has no attribute 'metrics'

As we see both Kr values for the x and z direction are the same, because we changed the inlets/outlets in the x direction in such a way that it is equivalent to the algorithm default z direction. If we pass the flow intelts/outlets to the algorithm, the algorithm overwrites its default pores with the passed arguments corresponding to that direction. The same procedure cna be applied to a 2D model.

Note: The direction of the flow is found by finding the boundaries’ corresponding cartesian coordinates direction. This rule also allows the user to define their boundary pores easily. As an example if the user defines the ‘x’ direction boundary pores, the algorithm overwrites the default boundary pores that were related to the ‘x’ direction. Any other possible boundaries (which is dependent on the shape of the network) will be automatically assigned to the default pores in the other direction. Note that the algorithm distinguishes whether a network is a 2D or not by looking at the number of boundary faces labeled. By doing so, the shape of the network is found and so does their corresponding default boundary pores. As mentioned before the algorithm will not plot the defending phase curves, if it is not passed as an argument (optional).