injection
#
Simulate volume controlled injection of non-wetting fluid into an image using either “image-based invasion percolation” (ibip) [1] or “queue-based invasion percolation” (qbip) [2]. The injection
function is a wrapper function which provides access to both methods. Each of the available arguments will be explained below.
import matplotlib.pyplot as plt
import numpy as np
import porespy as ps
ps.visualization.set_mpl_style()
im
#
Can be a 2D or 3D image. To use the injection
functions properly a capillary transform should be computed and provided to pc
argument. If pc
is not given, however, the function will still work as pc
is computed assuming \(pc = 2/dt\).
im = ps.generators.blobs(shape=[200, 200], porosity=0.7, blobiness=0.75, seed=0)
inv = ps.simulations.injection(im=im)
The function returns a Results
object with a images containing the invasion sequence map , the saturation map, and capillary pressure map. These are shown below:
def plot_results(inv):
fig, ax = plt.subplots(1, 3, figsize=[15, 4])
h = ax[0].imshow(inv.im_seq/im, origin='lower')
cbar = fig.colorbar(h, aspect=10, format="{x:.0f}")
cbar.ax.set_title('Invasion Sequence', rotation=90, y=0, c='w')
ax[0].axis(False)
ax[0].set_title('(a) Sequence Map')
h = ax[1].imshow(inv.im_snwp/im, origin='lower')
cbar = fig.colorbar(h, aspect=10, format="{x:.1f}")
cbar.ax.set_title('Non-Wetting Phase Saturation', rotation=90, y=0, c='w')
ax[1].axis(False)
ax[1].set_title('(b) Saturation Map')
h = ax[2].imshow(np.log10(inv.im_pc)/im, origin='lower')
cbar = fig.colorbar(h, aspect=10, format="{x:.1f}")
cbar.ax.set_title('log(Capillary Pressure)', rotation=90, y=0, c='w')
ax[2].axis(False)
ax[2].set_title('(c) Capillary Pressure Map')
plot_results(inv)
inlets
#
By default invasion begins from x=0
, but the inlets
can be specified, for instance to inject from y=0
:
pc
#
Supplying a capillary pressure transform as pc
is how you tell injection
what the capillary entry pressure of each voxel is. This is calculated separately (e.g. using porespy.filters.capillary_transform
) so that you have maximum control over how this is calculated, for instance to include gravity.
outlets
#
Of outlets
are specified then trapping of the wetting phase is included in the returned displacement maps.
min_size
#
The min_size
argument is passed to the find_trapped_regions
function. It limits the minimum size of a cluster that can be considered trapped. For instance, in the above image there can be seen many small isolated trapped pixels next to the walls. These occur because of the digitized nature of the images, and are probably not realistic. Supplying min_size > 0
removes these pixels:
conn
#
The conn
argument controls the neighbor searches for both the invasion simulation and the trapped wetting phase search (if outlets
are provided. It can be either 'min'
or 'max'
. 'min'
means 4 neighbors in 2D and 6 in 3D, while 'max'
means 8 neighbors in 2D and 26 neighbors in 3D.
maxiter
#
The maximum number of iterations to run before stopping, mostly to prevent the algorithm from stalling (or appearing to stall) on huge images. By default it will run until completion.
method
#
The method
argument allows the choice of the original “image-based invasion percolation” ('ibip'
) algorithm which uses basic image analysis tools to find the next most easily invadable voxels on each loop, or it can use the new “queue-based” method ('qbip'
) which uses a binary heap to implement a priority queue which makes the searching for the next invasion location much faster. The 'ibip'
option is only included for legacy/academic reasons. Both methods give equivalent results while 'qbip'
is much faster.
inv1 = ps.simulations.injection(
im=im,
pc=pc,
inlets=inlets,
method='qbip'
)
inv2 = ps.simulations.injection(
im=im,
pc=pc,
inlets=inlets,
method='ibip'
)
diff = np.sum(inv1.im_seq != inv2.im_seq)
print(f"The number of pixels with a different value is {diff}")
The number of pixels with a different value is 0
Other Arguments#
dt
#
Like many of the functions in PoreSpy, injection
optionally accepts a distance transform. This is computed automatically if dt
is not provided, but providing one can save a small amount of time if the distance transform has already been computed (which is often the case).
return_sizes
and return_pressures
#
These two flags indicate whether or not to compute the size map and capillary pressure maps. Setting these to False
can save some time if these results are not required. returns_pressures
is True
by default, while return_sizes
is False
.