Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## What is Pore2Chip?
Pore2Chip is a Python module designed to streamline the process of analyzing X-ray computed tomography (XCT) images of soil and creating 2D micromodel designs based on that analysis. It leverages the power of open-source libraries like OpenPNM, PoreSpy, and drawsvg to extract key information about the soil's porous structure and translate it into a blueprint for microfluidic simulations or physical `lab-on-a-chip` devices developed using additive manufacturing.

Documentation Quick Link: https://emsl-computing.github.io/Pore2Chip/

### A workflow for model-data-experiment (ModEx) design:

Below is a conceptual figure, workflow, and vision for this all-in-one Python tool. The working principle starts with XCT imaging files, which will be characterized for soil structure-property relationships and then transformed into a 2D rendering applicable to pore-scale micromodel building. Micromodel experiments will then be used with PFLOTRAN/OpenFOAM/PINNs process models to simulate flow and reactive transport for calibration and V&V.
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ dynamic = ["dependencies"]
[tool.setuptools.dynamic]
dependencies = {file = ["requirements.txt"]}

[project.optional-dependencies]
extras = [
"pypardiso",
]

[project.urls]
Homepage = "https://www.emsl.pnnl.gov/science/instruments-resources/terraforms-pore2chip"
Source = "https://github.com/EMSL-Computing/Pore2Chip"
123 changes: 67 additions & 56 deletions tests/test_coordination.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import openpnm as op
import porespy as ps
from pathlib import Path
import pytest
import numpy as np

# Uncomment and modify these lines if the pore2chip package is not in the PYTHONPATH
#mod_path = Path("__file__").resolve().parents[2]
#sys.path.append(os.path.abspath(mod_path))

from pore2chip.coordination import coordination_nums_2D, coordination_nums_3D
#from pore2chip.src.pore2chip.export import coordination_nums_3D, coordination_nums_2D


def generate_network():
"""
Expand All @@ -22,64 +22,75 @@ def generate_network():
"""
network = op.network.Cubic([3, 3]) # Create a 3x3 cubic network
network.add_model_collection(op.models.collections.geometry.
spheres_and_cylinders) # Add geometry models
spheres_and_cylinders) # Add geometry models
network.regenerate_models() # Generate network properties
print(network) # For debugging purposes
return network

class TestCoordination():

def test_coordination_nums_3D(network):
"""
Test coordination_nums_2D function given an OpenPNM network.
def test_coordination_nums_3D(self):
"""
Test coordination_nums_2D function given an OpenPNM network.

Args:
network (dict): The network structure and coordination numbers (e.g., op.network.Cubic).

Returns:
coordination_numbers (ndarray): An array of coordination numbers for each pore in the network..
"""
coordination_numbers = coordination_nums_3D(pn=network)
print(coordination_numbers) # For debugging purposes
print(coordination_numbers.mean()) # For debugging purposes
print(coordination_numbers.shape) # For debugging purposes
return coordination_numbers


def test_coordination_nums_2D(img_list):
"""
Test coordination_nums_2D function given a list of images.
Args:
network (dict): The network structure and coordination numbers (e.g., op.network.Cubic).

Returns:
coordination_numbers (ndarray): An array of coordination numbers for each pore in the network..
"""
network = generate_network()
coordination_numbers = coordination_nums_3D(pn=network)
assert coordination_numbers.any() == np.array([2,3,2,3,4,3,2,3,2],dtype=int).any()
#print(coordination_numbers) # For debugging purposes
#print(coordination_numbers.mean()) # For debugging purposes
#print(coordination_numbers.shape) # For debugging purposes
#return coordination_numbers


def test_coordination_nums_2D(self):
"""
Test coordination_nums_2D function given a list of images.

Args:
img_list (ndarray): 3D image list

Returns:
coordination_numbers (ndarray): An array of coordination numbers for each pore in the network..
"""
coordination_numbers = coordination_nums_2D(img_list)
print(coordination_numbers)
print(coordination_numbers.mean())
print(coordination_numbers.shape)
return coordination_numbers


def main():
"""
Main function to generate a network, test coordination number computations on 3D networks
and 2D image slices.
"""

# Generate network
network = generate_network()

# Test coordination 3D on generated network
test_coordination_nums_3D(network)

# Generate a 3D image using PoreSpy with specified dimensions and random seed
blobs = ps.generators.blobs([5, 100, 100], seed=1)

# Test coordination 2D on image list
test_coordination_nums_2D(blobs)


if __name__ == "__main__":
main()
Args:
img_list (ndarray): 3D image list

Returns:
coordination_numbers (ndarray): An array of coordination numbers for each pore in the network..
"""
blobs = ps.generators.blobs([1, 100, 100], seed=1)
coordination_numbers = coordination_nums_2D(blobs)
assert coordination_numbers.any() == np.array(
[3, 3, 1, 0, 3, 1, 0, 1, 1, 3, 2, 2, 3, 3, 1, 2, 3, 2, 2, 1, 2, 1, 3, 1,
2, 2, 5, 2, 0, 0, 1, 3, 1, 2, 1, 0, 1, 3, 4, 0, 3, 3, 0, 1, 2, 2, 3, 3,
2, 2, 2, 2, 3, 3, 0, 4, 1, 2, 4, 2, 1, 2, 3, 3, 2, 3, 5, 4, 1, 1, 2, 1,
2, 1, 2, 3, 3, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1,]
,dtype=float).any()
#print(coordination_numbers)
#print(coordination_numbers.mean())
#print(coordination_numbers.shape)
#return coordination_numbers


#def main():
#"""
#Main function to generate a network, test coordination number computations on 3D networks
#and 2D image slices.
#"""

## Generate network
#network = generate_network()

## Test coordination 3D on generated network
#test_coordination_nums_3D(network)

## Generate a 3D image using PoreSpy with specified dimensions and random seed
#blobs = ps.generators.blobs([5, 100, 100], seed=1)

## Test coordination 2D on image list
#test_coordination_nums_2D(blobs)


#if __name__ == "__main__":
#main()
6 changes: 3 additions & 3 deletions tests/test_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ def create_random_properties():
- coordination_nums (np.ndarray): Array of random coordination numbers (converted to integers).
"""
# Generating random pore diameters within specified range
pore_diameters = np.random.uniform(low=1.0, high=10.0, size=20)
pore_diameters = np.random.uniform(low=1.0, high=10.0, size=20, seed=1)

# Generating random throat diameters within specified range
throat_diameters = np.random.uniform(low=0.5, high=6.0, size=20)
throat_diameters = np.random.uniform(low=0.5, high=6.0, size=20, seed=1)

# Generating random coordination numbers within specified range and converting to integers
coordination_nums = np.random.uniform(low=0, high=8,
size=20).astype(np.int64)
size=20, seed=1).astype(np.int64)
return pore_diameters, throat_diameters, coordination_nums


Expand Down