From e61648e63513440734345f564cdcba39a71f60ce Mon Sep 17 00:00:00 2001 From: aramyxt Date: Mon, 18 Aug 2025 09:15:28 -0700 Subject: [PATCH 1/2] More JOSS Edits More edits for JOSS publication, as well as starting implementation of pytest to the test suites. --- README.md | 2 + pyproject.toml | 5 ++ tests/test_coordination.py | 123 ++++++++++++++++++++----------------- 3 files changed, 74 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 7021de6..4aa160b 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/pyproject.toml b/pyproject.toml index 44bdd4f..065a5f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" \ No newline at end of file diff --git a/tests/test_coordination.py b/tests/test_coordination.py index ab46f76..733ce5f 100644 --- a/tests/test_coordination.py +++ b/tests/test_coordination.py @@ -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(): """ @@ -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() From 84196abed681f55a8e1a28318fe65352e53e59e0 Mon Sep 17 00:00:00 2001 From: aramyxt Date: Tue, 19 Aug 2025 08:17:10 -0700 Subject: [PATCH 2/2] Updating Generation Test Suites Starting more testing suite changes with pytest. --- tests/test_generate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_generate.py b/tests/test_generate.py index 359792e..5ce0850 100644 --- a/tests/test_generate.py +++ b/tests/test_generate.py @@ -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