Using and Creating Labels#

Labels are a way to ‘bookmark’ certain pores for easier lookup later, such as specifying boundary conditions. When networks are generated they include a set of relevent labels that have been added for convenience. It’s also possible for users to add their own labels. This tutorial will cover how they work, how to add them, and how to use them.

[1]:
import openpnm as op
%config InlineBackend.figure_formats = ['svg']
import numpy as np

Using Pre-defined Labels#

The simple Cubic network has several labels added during creating. We can see these labels when we inspecting (i.e. print) the network,

[2]:
pn = op.network.Cubic(shape=[5, 5, 1])
print(pn)
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
openpnm.network.Cubic : net_01
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
#     Properties                                    Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
1     pore.coords                                      25 / 25
2     throat.conns                                     40 / 40
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
#     Labels                                        Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
1     pore.all                                      25
2     pore.back                                     5
3     pore.front                                    5
4     pore.internal                                 25
5     pore.left                                     5
6     pore.right                                    5
7     pore.surface                                  16
8     throat.all                                    40
9     throat.internal                               40
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Parameters                          Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

In the above output we can see 2 ‘properties’, which is the term used for numerical data, and 10 ‘labels’. Labels are also Numpy arrays, so are stored in the OpenPNM objects along ‘propery’ arrays. The different is that ‘labels’ are boolean type (i.e. True, False).

A boolean array, such as ‘pore.left’ is an Np long with True values indicating which pores possess that label.

The label ‘pore.left’ clearly indicates which pores on of the ‘left’ side of the network. We can inspect the label array directly:

[3]:
print(pn['pore.left'])
[ True  True  True  True  True False False False False False False False
 False False False False False False False False False False False False
 False]

But it’s more useful to extract the locations of the true values:

[4]:
np.where(pn['pore.left'])[0]
[4]:
array([0, 1, 2, 3, 4])

OpenPNM objects all have a method for accessing such locations directly without calling where:

[5]:
pn.pores('left')
[5]:
array([0, 1, 2, 3, 4])

The advantage of the using the OpenPNM method is that you can create more complex queries, such as pores that are ‘left’ or ‘back’:

[6]:
pn.pores(['left', 'back'])
[6]:
array([ 0,  1,  2,  3,  4,  9, 14, 19, 24])

Or, pores that are both left and back:

[7]:
pn.pores(['left', 'back'], mode='and')
[7]:
array([4])

Because this is a 2D network, we only found one ‘corner’ pore ([0]). In 3D this would have found all the pores on the ‘edge’.

Points to Note about Using Labels#

  • Labels can be applied to throats in exactly the same way as decribed here for pores.

  • Every OpenPNM object has a pores and a throats method that can be used to retrieve the pore or throat indices where a label or combination of labels has been applied.

  • For internal purposes, every OpenPNM object has pre-defined labels called ‘pore.all’ and ‘throat.all’. These are True everywhere and are used internally for determining the number of pore and throats on an object.

  • The format of creating an entire ND-array to label just a few locations may seem a bit wasteful of data storage since many False values are created to indicate pores do not have a label. However, such boolean area can be used to index into Numpy arrays.

  • Labels are used throughout any given script, particularly for specifying boundary conditions, so are an important feature to understand.

Defining Custom Labels#

It is common in OpenPNM scripts to do some complex searching to find all pores that satisfy some set of conditions. It can be helpful to label these for later use. There are two ways to do this, by directly creating a boolean mask and storing it, or by calling the set_label method.

Creating Boolean Masks#

Assume we want to label the ‘corner’ pore we found above. First catch the result in a variable:

[8]:
Ps = pn.pores(['left', 'back'], mode='and')

Then create an empty label array (filled with False values) on the network:

[9]:
pn['pore.corner'] = False
print(pn['pore.corner'])
[False False False False False False False False False False False False
 False False False False False False False False False False False False
 False]

Now insert True values at the desired array indices corresponding to the pore location:

[10]:
pn['pore.corner'][Ps] = True
print(pn.pores('corner'))
[4]

Using set_label#

The process of creating an empty label array, then filling the True values is a bit annoying, so there is a helper/shortcut method on all OpenPNM objects. It can be used to create a new label, or to add to an existing one. Let’s label another corner pore as ‘pore.corner’:

[11]:
Ps = Ps = pn.pores(['left', 'front'], mode='and')
pn.set_label(label='corner', pores=Ps)
print(pn.pores('corner'))
[0 4]

The set_label method has a mode argument that can be used to change the behavior, such as 'add' or 'remove' labels from the given locations (default is mode='add'), 'purge' all existing indices from the given label, or 'remove' which purges then adds the given pores to the specified label.

[12]:
pn.set_label(label='pore.corner', mode='purge')
print('pore.corner' in pn.keys())
False