import pnmlib as pnm
import numpy as np
import matplotlib.pyplot as plt
from pnmlib.inspect import tree
from pnmlib.core import get_data, set_data
from IPython.display import MarkdownDemo of core functions
sim = pnm.generators.cubic([3, 3])
sim['pore.coords'] = sim.pop('node.coords')
sim['throat.conns'] = sim.pop('edge.conns')tree(sim)├── 'pore.coords': (9, 3), float64 └── 'throat.conns': (12, 2), int64
add_network This takes the dict from a network generator and adds it to the top level. It also adds 'pore.all' and 'throat.all' since these are used by other functions.
pnm.core.add_network(sim, sim)
tree(sim)├── 'pore.all': 9/9, bool ├── 'pore.coords': (9, 3), float64 ├── 'throat.all': 12/12, bool └── 'throat.conns': (12, 2), int64
create_group
When creating an empty group the 'pore.all' and 'throat.all' arrays are created as place holders. It is not possible to have an empty group though, as this will break things:
pnm.core.create_group(sim, 'phase1')
tree(sim)├── 'pore.all': 9/9, bool
├── 'pore.coords': (9, 3), float64
├── 'throat.all': 12/12, bool
├── 'throat.conns': (12, 2), int64
└── phase1
├── 'pore.all': 9/9, bool
└── 'throat.all': 12/12, bool
for item in sim.keys():
print(item)pore.coords
throat.conns
pore.all
throat.all
phase1/pore.all
phase1/throat.all
get_group This fetches a subset of data as a standalone dict:
tmp = pnm.core.get_group(sim, 'phase1')
tree(tmp)├── 'pore.all': 9/9, bool └── 'throat.all': 12/12, bool
But leaves the main simulation intact:
tree(sim)├── 'pore.all': 9/9, bool
├── 'pore.coords': (9, 3), float64
├── 'throat.all': 12/12, bool
├── 'throat.conns': (12, 2), int64
└── phase1
├── 'pore.all': 9/9, bool
└── 'throat.all': 12/12, bool
pop_group This can be used to remove a group from the simulation, and it also returns it in case it’s needed:
tmp = pnm.core.pop_group(sim, 'phase1')
tree(tmp)└── phase1
├── 'pore.all': 9/9, bool
└── 'throat.all': 12/12, bool
In this case the simulation is altered:
tree(sim)├── 'pore.all': 9/9, bool ├── 'pore.coords': (9, 3), float64 ├── 'throat.all': 12/12, bool └── 'throat.conns': (12, 2), int64
build_conduit_data The returns an array of pore-throat-pore values for use in conductance calculations:
set_data(sim, 'pore.diameter', value=2.0)
set_data(sim, 'throat.diameter', value=1.0)
D = pnm.core.build_conduit_data(sim, group='', propname='diameter')
print(D)[[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]
[2. 1. 2.]]
count This is a way to programmatically find the number of pores or throats:
print(pnm.core.count(sim, 'pore'))
print(pnm.core.count(sim, 'throat'))9
12
fold_dict Takes a flat dict and creates a nested one.
pnm.core.create_group(sim, 'phase_02')
print(sim.keys())
folded = pnm.core.fold_dict(sim, '/')
print(folded.keys())dict_keys(['pore.coords', 'throat.conns', 'pore.all', 'throat.all', 'pore.diameter', 'throat.diameter', 'phase_02/pore.all', 'phase_02/throat.all'])
dict_keys(['phase_02', 'throat.diameter', 'pore.diameter', 'throat.all', 'pore.all', 'throat.conns', 'pore.coords'])
flatten_dict Takes a nested dict and creates a flattened one:
flattened = pnm.core.flatten_dict(folded, '/')
pnm.inspect.data(flattened)
══════════════════════════════════════════════════════════════════════════════
# Properties Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.coords 9 / 9
3 pore.diameter 9 / 9
4 throat.conns 12 / 12
5 throat.diameter 12 / 12
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Labels Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.all 9
3 throat.all 12
4 phase_02/pore.all 9
5 phase_02/throat.all 12
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
flatten_list
This is not really relevant, it’s more of a ‘just-in-case’ utility function.
generate_name This will generate a unique name based on the given prefix. It essential just adds a number larger than the largest currently in use:
name = pnm.core.generate_name(sim, 'phase')
print(name)phase_01
get_components When multiphase mixtures are used, this function tells us which components belong to a given mixture:
pnm.core.create_group(sim, 'phase_01/phase_02')
pnm.core.create_group(sim, 'phase_01/phase_03')
comps = pnm.core.get_components(sim, 'phase_01')
print(comps)['phase_02', 'phase_03']
set_label This creates an empty label array (filled with False) of the given name, and optionally fills in the given locs with True.
pnm.core.set_label(sim, label='network/pore.test4', locs=[1, 2, 3])
pnm.core.set_label(sim, label='network/pore.test3', locs=[1, 2, 3])
tree(sim)├── 'pore.all': 9/9, bool
├── 'pore.coords': (9, 3), float64
├── 'pore.diameter': (9,), float64
├── 'throat.all': 12/12, bool
├── 'throat.conns': (12, 2), int64
├── 'throat.diameter': (12,), float64
├── network
│ ├── 'pore.test3': 3/9, bool
│ └── 'pore.test4': 3/9, bool
├── phase_01
│ ├── phase_03
│ │ ├── 'pore.all': 9/9, bool
│ │ └── 'throat.all': 12/12, bool
│ └── phase_02
│ ├── 'pore.all': 9/9, bool
│ └── 'throat.all': 12/12, bool
└── phase_02
├── 'pore.all': 9/9, bool
└── 'throat.all': 12/12, bool
get_indices Get the indices where the given labels are True, using the specified mode which defaults to 'or'.
pnm.core.get_indices(sim, labels=['network/pore.test4', 'network/pore.test3'], mode='and')array([1, 2, 3])
set_data(sim, 'network/pore.test2', True, [3, 4])
pnm.core.get_indices(sim, element='pore', labels=['network/pore.test2', 'network/pore.test3'], mode='xor')array([1, 2, 4])
get_label_data Gets all the arrays on the simulation which are bool (i.e. labels):
labels = pnm.core.get_label_data(sim)
pnm.inspect.info(labels)
══════════════════════════════════════════════════════════════════════════════
# Properties Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Labels Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 pore.all 9
3 throat.all 12
4 phase_02/pore.all 9
5 phase_02/throat.all 12
6 phase_01/phase_02/pore.all 9
7 phase_01/phase_02/throat.all 12
8 phase_01/phase_03/pore.all 9
9 phase_01/phase_03/throat.all 12
10 network/pore.test4 3
11 network/pore.test3 3
12 network/pore.test2 2
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
get_prop_data Get’s all the arrays on the simulation which are numerical.
set_data(sim, 'phase_02/pore.test', 1.1)
props = pnm.core.get_prop_data(sim)
pnm.inspect.info(props)
══════════════════════════════════════════════════════════════════════════════
# Properties Valid Values
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2 phase_02/pore.test 9 / 9
3 pore.coords 9 / 9
4 pore.diameter 9 / 9
5 throat.conns 12 / 12
6 throat.diameter 12 / 12
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Labels Assigned Locations
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
get_param_data Gets all the parameters (i.e. scalars) on the simulation.
set_data(sim, 'param.T', 333.0)
set_data(sim, 'phase_01/param.T', 333.0)
tmp = pnm.core.get_param_data(sim)
tree(tmp)├── 'param.T': 333.0
└── phase_01
└── 'param.T': 333.0
get_pores Returns a list of pore indices where the give label(s) are present, according to the given 'mode'.
pnm.core.get_pores(sim, 'network/pore.test2')array([3, 4])
get_throats Returns a list of throat indices where the give label(s) are present, according to the given 'mode'.
set_data(sim, 'network/throat.test5', True, [0, 1, 2])
pnm.core.get_throats(sim, 'network/throat.test5')array([0, 1, 2])
num_pores Counts the number of pores in the simulation where the given label(s) are present, according to the specified 'mode'.
Np = pnm.core.num_pores(sim, labels=['pore.all'])
print(Np)9
num_throats Counts the number of throats in the simulation where the given label(s) are present, according to the specified 'mode'.
Nt = pnm.core.num_throats(sim, labels=['throat.all'])
print(Nt)12
filter_pores
pnm.core.filter_pores(sim, locs=[0, 1, 2], labels=['network/pore.test3'])array([1, 2])