satn_profile#

Computes the saturation profiles in an invasion image

import matplotlib.pyplot as plt
import numpy as np
import porespy as ps

The arguments and their defaults for this function are:

import inspect
inspect.signature(ps.metrics.satn_profile)
<Signature (satn, s, axis=0, span=10, mode='tile')>

Start by performing a basic invasion simulation:

np.random.seed(1)
im = ps.generators.blobs(shape=[150, 150], porosity=0.6, blobiness=1)
inlets = np.zeros_like(im)
inlets[0, :] = True
inv = ps.simulations.drainage(im=im, inlets=inlets, voxel_size=1, g=0)

fig, ax = plt.subplots(1, 2, figsize=[12, 6])
ax[0].imshow(inv.im_satn/im, interpolation='none', origin='lower')
ax[0].axis(False)
ax[0].set_title('Saturation map')
ax[1].imshow((inv.im_satn < 0.6)*(inv.im_satn > 0)/im, interpolation='none', origin='lower')
ax[1].axis(False)
ax[1].set_title('Fluid distribution at saturation = 0.6');
../../../_images/7fa8e49b4e878b09af8a4ae8144d89da36b800264133f99c507352af927bab1f.png

satn#

This is the output of the invasion function, converted to saturation if needed:

s = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6)
plt.plot(s.position, s.saturation, 'b-o')
plt.xlabel("distance from injection face")
plt.ylabel("non-wetting phase saturation");
../../../_images/cffef978a772934b68542f753072f6d168f2fddfbca65739aff950dbd4f88229.png

s#

The global saturation for which the profile should be obtained:

s = 0.6
s1 = ps.metrics.satn_profile(satn=inv.im_satn, s=s)
plt.plot(s1.position, s1.saturation, 'b-o')

s = 0.4
s2 = ps.metrics.satn_profile(satn=inv.im_satn, s=s)
plt.plot(s2.position, s2.saturation, 'r-o')

s = 0.1
s3 = ps.metrics.satn_profile(satn=inv.im_satn, s=s)
plt.plot(s3.position, s3.saturation, 'g-o')

plt.xlabel("distance from injection face")
plt.ylabel("non-wetting phase saturation");
../../../_images/94248ca24dc9e585b261db52f99df7b1003e4caacf44c4350527c2ed65edae7e.png

span#

The width of the slice over which the saturation is computed. The default is 10 voxels. A higher number makes the curve smoother, but risks losing features like dips and spikes:

s = 5
s1 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, span=s)
plt.plot(s1.position, s1.saturation, 'b-o')

s = 10
s2 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, span=s)
plt.plot(s2.position, s2.saturation, 'r-o')

s = 30
s3 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, span=s)
plt.plot(s3.position, s3.saturation, 'g-o')

plt.xlabel("distance from injection face")
plt.ylabel("non-wetting phase saturation");
../../../_images/5ee7bd6a2c564a986815dcd1b43a3f5ad9f3a51b160524cd4646b304ce1a7a91.png

mode#

How the averaging window moves, either by sliding or by tiling.

s1 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, mode='slide')
plt.plot(s1.position, s1.saturation, 'b-o')

s = 10
s2 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, mode='tile')
plt.plot(s2.position, s2.saturation, 'r-o')

plt.xlabel("distance from injection face")
plt.ylabel("non-wetting phase saturation");
../../../_images/b979053a3a6c72f2b1b356adb34954d4549888f4c59df993f80d15d5b50f1cda.png

axis#

The direction along with the averaging window moves. This can be perpendicular to the axis where the injection occurred to give additional insights into the saturation distribution:

s1 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, axis=0)
plt.plot(s1.position, s1.saturation, 'b-o')

s = 10
s2 = ps.metrics.satn_profile(satn=inv.im_satn, s=0.6, axis=1)
plt.plot(s2.position, s2.saturation, 'r-o')

plt.xlabel("distance from injection face")
plt.ylabel("non-wetting phase saturation");
../../../_images/4b1101493adb08a52ac64fcc362b9f5d7f2430843bdab6f822f1c0b061f00766.png