rev_tortuosity
#
# Import Packages
import matplotlib.pyplot as plt
import porespy as ps
ps.visualization.set_mpl_style()
im
#
The image can be 2D or 3D and the tortuosity is computed on the True
voxels.
# Generate a Test Image
im = ps.generators.blobs(shape=[300, 300], porosity=0.7, blobiness=2, seed=1)
plt.figure(figsize=[6, 6])
plt.imshow(im, origin='lower')
# Calculate Tortuosity for Different Subdomain Sizes
rev = ps.metrics.rev_tortuosity(im)
The rev_tortuosity
function returns a Results
object, which has several named attributes:
print(rev)
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Results of rev_tortuosity generated at Sat Jul 12 16:17:05 2025
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
porosity_orig Dictionary with 200 items
porosity_perc Dictionary with 200 items
g Dictionary with 200 items
tau Dictionary with 200 items
volume Dictionary with 200 items
length Dictionary with 200 items
axis Dictionary with 200 items
time Dictionary with 200 items
slice Dictionary with 200 items
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
We can plot these results as follows:
# Visualize the Results
fig, ax = plt.subplots(1, 3, figsize=[15, 5])
# Plot porosity vs volume
ax[0].scatter(rev.volume, rev.porosity_orig, marker='.', alpha=0.25, fc='tab:red', ec='none')
ax[0].set_ylim([0, 1])
ax[0].set_xlim([0, im.size])
ax[0].set_ylabel('Porosity')
ax[0].set_xlabel('Subdomain Volume')
# Plot tortuosity vs volume
ax[1].scatter(rev.volume, rev.tau, marker='.', alpha=0.25, fc='tab:blue', ec='none')
ax[1].set_ylim([0, None])
ax[1].set_xlim([0, im.size])
ax[1].set_ylabel('Tortuosity')
ax[1].set_xlabel('Subdomain Volume')
# Plot tortuosity vs porosity
ax[2].scatter(rev.porosity_perc, rev.tau, marker='.', alpha=0.25, fc='tab:green', ec='none')
ax[2].set_xlim([0, 1])
ax[2].set_ylim([0, None])
ax[2].set_xlabel('Porosity')
ax[2].set_ylabel('Tortuosity')
plt.tight_layout();
n
#
Be default the function will compute the tortuosity of n
randomly sized blocks selected from random locations throughout the domain. The default is 100, but more or less can be specified:
rev = ps.metrics.rev_tortuosity(im, n=200)
print(rev)
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Results of rev_tortuosity generated at Sat Jul 12 16:17:12 2025
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
porosity_orig Dictionary with 400 items
porosity_perc Dictionary with 400 items
g Dictionary with 400 items
tau Dictionary with 400 items
volume Dictionary with 400 items
length Dictionary with 400 items
axis Dictionary with 400 items
time Dictionary with 400 items
slice Dictionary with 400 items
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
slices
#
If more control of the subdomains is needed then you can passes a list of slice
objects direct as slices
. There are functions in the tools
module from computing other slices:
slices = ps.tools.get_slices_multigrid(
im=im,
block_size_range=[50, 300, 50],
)
rev = ps.metrics.rev_tortuosity(im, slices=slices)
print(rev)
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Results of rev_tortuosity generated at Sat Jul 12 16:17:13 2025
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
porosity_orig Dictionary with 102 items
porosity_perc Dictionary with 102 items
g Dictionary with 102 items
tau Dictionary with 102 items
volume Dictionary with 102 items
length Dictionary with 102 items
axis Dictionary with 102 items
time Dictionary with 102 items
slice Dictionary with 102 items
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Visualize the Results
fig, ax = plt.subplots(1, 3, figsize=[15, 5])
# Plot porosity vs volume
ax[0].scatter(rev.volume, rev.porosity_orig, marker='.', alpha=0.25, fc='tab:red', ec='none')
ax[0].set_ylim([0, 1])
ax[0].set_xlim([0, im.size])
ax[0].set_ylabel('Porosity')
ax[0].set_xlabel('Subdomain Volume')
# Plot tortuosity vs volume
ax[1].scatter(rev.volume, rev.tau, marker='.', alpha=0.25, fc='tab:blue', ec='none')
ax[1].set_ylim([0, None])
ax[1].set_xlim([0, im.size])
ax[1].set_ylabel('Tortuosity')
ax[1].set_xlabel('Subdomain Volume')
# Plot tortuosity vs porosity
ax[2].scatter(rev.porosity_perc, rev.tau, marker='.', alpha=0.25, fc='tab:green', ec='none')
ax[2].set_xlim([0, 1])
ax[2].set_ylim([0, None])
ax[2].set_xlabel('Porosity')
ax[2].set_ylabel('Tortuosity')
plt.tight_layout();
axis
#
By default the tortuosity is computed in all directions for each block, but the axis
can be specified:
rev = ps.metrics.rev_tortuosity(im, axis=1)
print(rev)
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Results of rev_tortuosity generated at Sat Jul 12 16:17:15 2025
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
porosity_orig Dictionary with 100 items
porosity_perc Dictionary with 100 items
g Dictionary with 100 items
tau Dictionary with 100 items
volume Dictionary with 100 items
length Dictionary with 100 items
axis Dictionary with 100 items
time Dictionary with 100 items
slice Dictionary with 100 items
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――