Fickian Diffusion with Reaction#
OpenPNM
is capable of simulating chemical reactions in pores by adding source and sink terms. This example shows how to add source and sink terms to a steady state fickian diffusion simulation.
[1]:
import warnings
import scipy as sp
import numpy as np
import openpnm as op
%config InlineBackend.figure_formats = ['svg']
import matplotlib.pyplot as plt
np.set_printoptions(precision=5)
np.random.seed(10)
%matplotlib inline
Create Network and Other Objects#
Start by creating the network, geometry, phase and physics objects as usual:
[2]:
pn = op.network.Cubic(shape=[40, 40], spacing=1e-4)
geo = op.geometry.SpheresAndCylinders(network=pn, pores=pn.Ps, throats=pn.Ts)
gas = op.phases.Air(network=pn)
phys = op.physics.Standard(network=pn, phase=gas, geometry=geo)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Input In [2], in <cell line: 3>()
1 pn = op.network.Cubic(shape=[40, 40], spacing=1e-4)
2 geo = op.geometry.SpheresAndCylinders(network=pn, pores=pn.Ps, throats=pn.Ts)
----> 3 gas = op.phases.Air(network=pn)
4 phys = op.physics.Standard(network=pn, phase=gas, geometry=geo)
AttributeError: module 'openpnm' has no attribute 'phases'
Now add the source and sink models to the physics object. In this case we’ll think of the as chemical reactions. We’ll add one source term and one sink term, meaning one negative reaction rate and one positive reaction rate
[3]:
gas['pore.concentration'] = 0
phys['pore.sinkA'] = -1e-10
phys['pore.sinkb'] = 1
phys.add_model(propname='pore.sink', model=op.models.physics.generic_source_term.power_law,
A1='pore.sinkA', A2='pore.sinkb', X='pore.concentration')
phys['pore.srcA'] = 1e-11
phys['pore.srcb'] = 1
phys.add_model(propname='pore.source', model=op.models.physics.generic_source_term.power_law,
A1='pore.srcA', A2='pore.srcb', X='pore.concentration')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 gas['pore.concentration'] = 0
2 phys['pore.sinkA'] = -1e-10
3 phys['pore.sinkb'] = 1
NameError: name 'gas' is not defined
Setup Fickian Diffusion with Sink Terms#
Now we setup a FickianDiffusion algorithm, with concentration boundary conditions on two side, and apply the sink term to 3 pores:
[4]:
rx = op.algorithms.FickianDiffusion(network=pn, phase=gas)
rx.set_source(propname='pore.sink', pores=[420, 820, 1220])
rx.set_value_BC(values=1, pores=pn.pores('front'))
rx.set_value_BC(values=1, pores=pn.pores('back'))
rx.run()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 rx = op.algorithms.FickianDiffusion(network=pn, phase=gas)
2 rx.set_source(propname='pore.sink', pores=[420, 820, 1220])
3 rx.set_value_BC(values=1, pores=pn.pores('front'))
NameError: name 'gas' is not defined
Plot Distributions#
We can use the plot_connections
and plot_coordinates
to get a quick view of the pore network, with colors and sizes scaled appropriately.
[5]:
pn['pore.concentration'] = rx['pore.concentration']
fig, ax = plt.subplots(figsize=[15, 15])
op.topotools.plot_connections(network=pn, color='k', alpha=.2, ax=ax)
op.topotools.plot_coordinates(network=pn, color_by=pn['pore.concentration'],
size_by=pn['pore.diameter'], cmap='plasma',
ax=ax, markersize=100)
_ = plt.axis('off')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [5], in <cell line: 1>()
----> 1 pn['pore.concentration'] = rx['pore.concentration']
2 fig, ax = plt.subplots(figsize=[15, 15])
3 op.topotools.plot_connections(network=pn, color='k', alpha=.2, ax=ax)
NameError: name 'rx' is not defined
Plot Distributions as Heatmaps#
Because the network is a 2D cubic, it is convenient to visualize it as an image, so we reshape the ‘pore.concentration’ array that is produced by the FickianDiffusion algorithm upon running, and turn it into a colormap representing concentration in each pore.
[6]:
pn['pore.concentration'] = rx['pore.concentration']
fig, ax = plt.subplots(figsize=[15, 15])
op.topotools.plot_connections(network=pn, color='k', alpha=0, ax=ax)
op.topotools.plot_coordinates(network=pn, color_by=pn['pore.concentration'], cmap='plasma',
ax=ax, markersize=420, marker='s')
_ = plt.axis('off')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [6], in <cell line: 1>()
----> 1 pn['pore.concentration'] = rx['pore.concentration']
2 fig, ax = plt.subplots(figsize=[15, 15])
3 op.topotools.plot_connections(network=pn, color='k', alpha=0, ax=ax)
NameError: name 'rx' is not defined
Setup Fickian Diffusion with Source Terms#
Similarly, for the source term:
[7]:
rx = op.algorithms.FickianDiffusion(network=pn, phase=gas)
rx.set_source(propname='pore.source', pores=[420, 820, 1220])
rx.set_value_BC(values=1, pores=pn.pores('front'))
rx.set_value_BC(values=1, pores=pn.pores('back'))
rx.run()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [7], in <cell line: 1>()
----> 1 rx = op.algorithms.FickianDiffusion(network=pn, phase=gas)
2 rx.set_source(propname='pore.source', pores=[420, 820, 1220])
3 rx.set_value_BC(values=1, pores=pn.pores('front'))
NameError: name 'gas' is not defined
And plotting the result as a color map:
[8]:
pn['pore.concentration'] = rx['pore.concentration'] - 1
fig, ax = plt.subplots(figsize=[15, 15])
op.topotools.plot_connections(network=pn, color='k', alpha=0, ax=ax)
op.topotools.plot_coordinates(network=pn, color_by=pn['pore.concentration'], cmap='plasma',
ax=ax, markersize=420, marker='s')
_ = plt.axis('off')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [8], in <cell line: 1>()
----> 1 pn['pore.concentration'] = rx['pore.concentration'] - 1
2 fig, ax = plt.subplots(figsize=[15, 15])
3 op.topotools.plot_connections(network=pn, color='k', alpha=0, ax=ax)
NameError: name 'rx' is not defined