hg_porosimetry#

Simulates a mercury intrusion-extrusion experiment by running a drainage and an imbibition from all faces using mercury contact angle and surface tension. Returns the two pressure-saturation curves.

import matplotlib.pyplot as plt
import numpy as np

import porespy as ps

ps.visualization.set_mpl_style()

The arguments and their defaults are:

import inspect

inspect.signature(ps.simulations.hg_porosimetry)
<Signature (im, steps=25, voxel_size=1.0)>

im#

A boolean image with True indicating the void phase. Both 2D and 3D images are supported, but 3D is the typical use case.

im = ps.generators.blobs(
    shape=[60, 60, 60], porosity=0.6, blobiness=1.5, seed=0)
mip = ps.simulations.hg_porosimetry(im=im, voxel_size=1e-5)

Plotting the result#

The returned object holds four arrays: pc_intrusion and snwp_intrusion for the drainage curve, plus pc_extrusion and snwp_extrusion for the imbibition curve. Plotting log10(Pc) vs. mercury saturation gives a familiar MIP hysteresis loop.

fig, ax = plt.subplots(figsize=[6, 5])
ax.step(np.log10(mip.pc_intrusion), mip.snwp_intrusion, 'b.-',
        where='post', label='intrusion')
ax.step(np.log10(mip.pc_extrusion), mip.snwp_extrusion, 'r.-',
        where='post', label='extrusion')
ax.set_xlabel('log10(Pc)  [Pa]')
ax.set_ylabel('mercury saturation')
ax.set_ylim([0, 1.05])
ax.legend();

voxel_size#

Image resolution in metres per voxel. Mercury surface tension and contact angle are hard-coded (sigma = 0.465 N/m, theta = 140 deg), so voxel_size is the knob that sets the absolute pressure scale on the x-axis.

for vs in [1e-6, 1e-5, 1e-4]:
    mip = ps.simulations.hg_porosimetry(im=im, voxel_size=vs, steps=15)
    plt.step(np.log10(mip.pc_intrusion), mip.snwp_intrusion,
             where='post', label=f'voxel_size = {vs:.0e} m')
plt.xlabel('log10(Pc)  [Pa]')
plt.ylabel('mercury saturation')
plt.ylim([0, 1.05])
plt.legend();

steps#

Number of pressure steps used for both intrusion and extrusion. More steps give a smoother curve at higher cost. The default is 25.

for n in [10, 25, 50]:
    mip = ps.simulations.hg_porosimetry(im=im, voxel_size=1e-5, steps=n)
    plt.step(np.log10(mip.pc_intrusion), mip.snwp_intrusion,
             where='post', label=f'steps = {n}')
plt.xlabel('log10(Pc)  [Pa]')
plt.ylabel('mercury saturation')
plt.ylim([0, 1.05])
plt.legend();