Generate a Cubic Lattice with an Interpenetrating Dual Cubic Lattice

(Since version 1.6) OpenPNM offers two options for generating dual networks. This tutorial will outline the use of the basic CubicDual class, while the DelaunayVoronoiDual is covered elsewhere. The main motivation for creating these dual networks was to enable the modeling of transport in the void phase on one network and through the solid phase on the other. These networks are interpenetrating but not overlapping or coincident so it makes the topology realistic. Moreover, these networks are interconnected to each other so they can exchange species between them, such as gas-liquid heat transfer. The tutorial below outlines how to setup a CubicDual network object, describes the combined topology, and explains how to use labels to access different parts of the network.

As usual start by importing Scipy and OpenPNM:


In [1]:
import scipy as sp
import openpnm as op
import matplotlib.pyplot as plt
%matplotlib inline
wrk = op.Workspace()  # Initialize a workspace object
wrk.loglevel=50


C:\Users\Tom\Anaconda3\lib\site-packages\h5py\__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters

Let's create a CubicDual and visualize it in Paraview:


In [2]:
net = op.network.CubicDual(shape=[6, 6, 6])

The resulting network has two sets of pores, labelled as blue and red in the image below. By default, the main cubic lattice is referred to as the 'primary' network which is colored blue, and the interpenetrating dual is referred to as the 'secondary' network shown in red. These names are used to label the pores and throats associated with each network. These names can be changed by sending label_1 and label_2 arguments during initialization. The throats connecting the 'primary' and 'secondary' pores are labelled 'interconnect', and they can be seen as the diagonal connections below.

The topotools module of openpnm also has handy visualization functions which can be used to consecutively build a picture of the network connections and coordinates. Replace %matplotlib inline with %matplotlib notebook for 3D interactive plots.


In [3]:
from openpnm.topotools import plot_connections, plot_coordinates
fig1 = plot_coordinates(network=net, pores=net.pores('primary'), c='b')



In [4]:
fig2 = plot_coordinates(network=net, pores=net.pores('primary'), c='b')
fig2 = plot_coordinates(network=net, pores=net.pores('secondary'), fig=fig2, c='r')



In [5]:
fig3 = plot_coordinates(network=net, pores=net.pores('primary'), c='b')
fig3 = plot_coordinates(network=net, pores=net.pores('secondary'), fig=fig3, c='r')
fig3 = plot_connections(network=net, throats=net.throats('primary'), fig=fig3, c='b')



In [6]:
fig4 = plot_coordinates(network=net, pores=net.pores('primary'), c='b')
fig4 = plot_coordinates(network=net, pores=net.pores('secondary'), fig=fig4, c='r')
fig4 = plot_connections(network=net, throats=net.throats('primary'), fig=fig4, c='b')
fig4 = plot_connections(network=net, throats=net.throats('secondary'), fig=fig4, c='r')



In [7]:
fig5 = plot_coordinates(network=net, pores=net.pores('primary'), c='b')
fig5 = plot_coordinates(network=net, pores=net.pores('secondary'), fig=fig5, c='r')
fig5 = plot_connections(network=net, throats=net.throats('primary'), fig=fig5, c='b')
fig5 = plot_connections(network=net, throats=net.throats('secondary'), fig=fig5, c='r')
fig5 = plot_connections(network=net, throats=net.throats('interconnect'), fig=fig5, c='g')


Inspection of this image shows that the 'primary' pores are located at expected locations for a cubic network including on the faces of the cube, and 'secondary' pores are located at the interstitial locations. There is one important nuance to note: Some of 'secondary' pores area also on the face, and are offset 1/2 a lattice spacing from the internal 'secondary' pores. This means that each face of the network is a staggered tiling of 'primary' and 'secondary' pores.

The 'primary' and 'secondary' pores are connected to themselves in a standard 6-connected lattice, and connected to each other in the diagonal directions. Unlike a regular Cubic network, it is not possible to specify more elaborate connectivity in the CubicDual networks since the throats of each network would be conceptually entangled. The figure below shows the connections in the secondary (left), and primary (middle) networks, as well as the interconnections between them (right).

Using the labels it is possible to query the number of each type of pore and throat on the network:


In [9]:
print(net.num_pores('primary'))
print(net.num_pores('secondary'))
print(net.num_throats('primary'))
print(net.num_throats('secondary'))
print(net.num_throats('interconnect'))


216
275
540
450
1600

Now that this topology is created, the next step would be to create Geometry objects for each network, and an additional one for the 'interconnect' throats:


In [10]:
geo_pri = op.geometry.GenericGeometry(network=net,
                                      pores=net.pores('primary'),
                                      throats=net.throats('primary'))
geo_sec = op.geometry.GenericGeometry(network=net,
                                      pores=net.pores('secondary'),
                                      throats=net.throats('secondary'))
geo_inter = op.geometry.GenericGeometry(network=net,
                                        throats=net.throats('interconnect'))