diff --git a/.gitignore b/.gitignore index 7dd5be5..58710a0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ wheels/ *.egg-info/ .installed.cfg *.egg +*.tiff # PyInstaller # Usually these files are written by a python script from a template diff --git a/.readthedocs.yml b/.readthedocs.yml index b41cc55..c6487b2 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,16 +1,22 @@ -# .readthedocs.yml +# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + + # Build documentation in the docs/ directory with Sphinx sphinx: - configuration: docs/conf.py + configuration: docs/conf.py -# Optionally set the version of Python and requirements required to build your docs +# Optionally declare the Python requirements required to build your docs python: - version: 3.8 - install: - - requirements: docs/requirements.txt + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/HISTORY.md b/HISTORY.md index 9915c28..583f967 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,14 @@ # History +## 1.1.0 (2023-07-24) + +--- + +- Added comments from reviewers +- Added examples to documentation +- Added API documentation +- Fix test times on comparison + ## 1.0.0 (2023-03-23) --- diff --git a/docs/index.rst b/docs/index.rst index 0ebb58c..c9aa495 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,12 +2,13 @@ Welcome to TauFactor's documentation! ====================================== .. toctree:: - :maxdepth: 2 + :maxdepth: 3 :caption: Contents: readme installation usage + taufactor contributing authors history diff --git a/docs/taufactor.rst b/docs/taufactor.rst new file mode 100644 index 0000000..5cdd886 --- /dev/null +++ b/docs/taufactor.rst @@ -0,0 +1,45 @@ +API Reference +================= + + +Core module +----------------- + +taufactor.taufactor module +~~~~~~~~~~~~~~~~~ + + +.. automodule:: taufactor.taufactor + :members: + :undoc-members: + :show-inheritance: + + +Submodules +----------------- + +taufactor.metrics module +~~~~~~~~~~~~~~~~~ + + +.. automodule:: taufactor.metrics + :members: + :undoc-members: + :show-inheritance: + +taufactor.utils module +~~~~~~~~~~~~~~~~~ + + +.. automodule:: taufactor.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +------------------ + +.. automodule:: taufactor + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/usage.md b/docs/usage.md index 42b8c5b..e5a74ed 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,6 +1,6 @@ # Using Taufactor -This documentation covers the full usage of TauFactor +This documentation covers the common usage of TauFactor. For a more detailed description see the [module API documentation](./taufactor.rst). ## Core solver diff --git a/example.ipynb b/example.ipynb new file mode 100644 index 0000000..947939e --- /dev/null +++ b/example.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(500, 500, 500)\n", + "[ 0 255]\n" + ] + } + ], + "source": [ + "import taufactor\n", + "from taufactor import metrics\n", + "import tifffile\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "# Note you should unzip TF-500x500x500-1x2x6-v3.tiff.zip and move the tiff file into examples\n", + "img = tifffile.imread('TF-500x500x500-1x2x6-v3.tiff')\n", + "# Always check the image shape and values in the array before running\n", + "print(img.shape)\n", + "print(np.unique(img))\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we have a 500x500x500 image. Note that if you have a stack of images,\n", + "you should load them one by one and use np.concatenate to make a 3D array. If these are `.png` you can load these in with `plt.imread('filename.png')` - make sure the array has dimensions `(x,y)` not `(x,y,c)` where c is RGB or RGBA colour channels.\n", + "\n", + "We also have 2 values, 0 and 255 in our array. We need to turn these into 0s and 1s, then we can make a solver." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "converged to: 4.242071628570557 after: 2401 iterations in: 63.8043 seconds at a rate of 0.0266 s/iter\n" + ] + } + ], + "source": [ + "# set 255 values to 1\n", + "img[img==255] = 1\n", + "solver = taufactor.Solver(img)\n", + "tau0 = solver.solve()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nice, we have tau in the 0th dimension of the image, we can check the other two as well" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "converged to: 1.1513475179672241 after: 701 iterations in: 18.7676 seconds at a rate of 0.0268 s/iter\n", + "converged to: 1.3905668258666992 after: 801 iterations in: 21.2776 seconds at a rate of 0.0266 s/iter\n", + "tensor(4.2421, device='cuda:0') tensor(1.1513, device='cuda:0') tensor(1.3906, device='cuda:0')\n" + ] + } + ], + "source": [ + "solver = taufactor.Solver(np.transpose(img, (1,0,2)))\n", + "tau1 = solver.solve()\n", + "solver = taufactor.Solver(np.transpose(img, (2,0,1)))\n", + "tau2 = solver.solve()\n", + "print(tau0, tau1, tau2)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now lets try the multiphase solver. First we will set the diffusive voxels in the top half of the volume to have a phase 2 label." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0 1 2]\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# solve in dim 1 cus it's faster and we are impatient\n", + "img2 = np.transpose(img, (1,0,2))\n", + "# Set some values to equal 2\n", + "img2[:250] *= 2\n", + "plt.imshow(img2[:,:,0])\n", + "print(np.unique(img2))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we solve using multiphase solver, with phase 0 non-conductive by default, phase 1 conductivity 1, phase 2 conductivity 5" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "converged to: 2.102311372756958 after: 2500 iterations in: 107.192 seconds at a rate of 0.0429 s/iter\n" + ] + }, + { + "data": { + "text/plain": [ + "tensor(2.1023)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mpsolver = taufactor.MultiPhaseSolver(img2, cond={1:1, 2:5})\n", + "mpsolver.solve()\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, metrics examples" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.699999988079071, 0.14785805344581604, 0.15214195847511292]\n", + "tensor(0.0203)\n" + ] + } + ], + "source": [ + "vfs = metrics.volume_fraction(img)\n", + "# surface area between phase 0 and 1\n", + "sa = metrics.surface_area(img, phases=[0,1])\n", + "print(vfs)\n", + "print(sa)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cgan", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/paper.bib b/paper.bib index 4006d22..2626450 100644 --- a/paper.bib +++ b/paper.bib @@ -59,6 +59,7 @@ @misc{fidgit } @article{gostick2019porespy, + doi = {10.1051/0004-6361/201629272}, title={PoreSpy: A python toolkit for quantitative analysis of porous media images}, author={Gostick, Jeff T and Khan, Zohaib A and Tranter, Thomas G and Kok, Matthew DR and Agnaou, Mehrez and Sadeghi, Mohammadamin and Jervis, Rhodri}, journal={Journal of Open Source Software}, @@ -79,6 +80,7 @@ @article{ferguson2018puma } @article{le2021openimpala, + doi={10.1016/j.softx.2021.100729}, title={Openimpala: Open source image based parallisable linear algebra solver}, author={Le Houx, James and Kramer, Denis}, journal={SoftwareX}, @@ -89,6 +91,7 @@ @article{le2021openimpala } @article{cooper2016taufactor, + doi={10.1016/j.softx.2016.09.002}, title={TauFactor: An open-source application for calculating tortuosity factors from tomographic data}, author={Cooper, Samuel J and Bertei, Antonio and Shearing, Paul R and Kilner, JA and Brandon, Nigel P}, journal={SoftwareX}, @@ -99,6 +102,7 @@ @article{cooper2016taufactor } @article{hart1999measurement, + doi={10.1016/s1386-5056(98)00163-4}, title={Measurement and classification of retinal vascular tortuosity}, author={Hart, William E and Goldbaum, Michael and C{\^o}t{\'e}, Brad and Kube, Paul and Nelson, Mark R}, journal={International journal of medical informatics}, @@ -110,6 +114,7 @@ @article{hart1999measurement } @article{carey2016estimating, + doi={10.1111/gwat.12406}, title={Estimating tortuosity coefficients based on hydraulic conductivity}, author={Carey, Grant R and McBean, Edward A and Feenstra, Stan}, journal={Groundwater}, @@ -121,6 +126,7 @@ @article{carey2016estimating } @article{landesfeind2018tortuosity, + doi={10.1149/2.0231803jes}, title={Tortuosity of battery electrodes: validation of impedance-derived values and critical comparison with 3D tomography}, author={Landesfeind, Johannes and Ebner, Martin and Eldiven, Askin and Wood, Vanessa and Gasteiger, Hubert A}, journal={Journal of The Electrochemical Society}, @@ -132,6 +138,7 @@ @article{landesfeind2018tortuosity } @article{dahari2023fusion, + doi={10.1002/aenm.202370009}, title={Fusion of Complementary 2D and 3D Mesostructural Datasets Using Generative Adversarial Networks (Adv. Energy Mater. 2/2023)}, author={Dahari, Amir and Kench, Steve and Squires, Isaac and Cooper, Samuel J}, journal={Advanced Energy Materials}, @@ -142,6 +149,7 @@ @article{dahari2023fusion publisher={Wiley Online Library} } @article{kench2022microlib, + doi={10.1038/s41597-022-01744-1}, title={MicroLib: A library of 3D microstructures generated from 2D micrographs using SliceGAN}, author={Kench, Steve and Squires, Isaac and Dahari, Amir and Cooper, Samuel J}, journal={Scientific Data}, @@ -162,6 +170,7 @@ @article{withers2021x publisher={Nature Publishing Group UK London} } @article{nguyen2020electrode, + doi={10.1038/s41524-020-00386-4}, title={The electrode tortuosity factor: why the conventional tortuosity factor is not well suited for quantifying transport in porous Li-ion battery electrodes and what to use instead}, author={Nguyen, Tuan-Tu and Demorti{\`e}re, Arnaud and Fleutot, Benoit and Delobel, Bruno and Delacourt, Charles and Cooper, Samuel J}, journal={npj Computational Materials}, @@ -182,6 +191,7 @@ @incollection{pytorch url = {http://papers.neurips.cc/paper/9015-pytorch-an-imperative-style-high-performance-deep-learning-library.pdf} } @article{cooper2017simulated, + doi={10.1016/j.electacta.2017.07.152}, title={Simulated impedance of diffusion in porous media}, author={Cooper, Samuel J and Bertei, Antonio and Finegan, Donal P and Brandon, Nigel P}, journal={Electrochimica Acta}, @@ -191,6 +201,7 @@ @article{cooper2017simulated publisher={Elsevier} } @article{tjaden2016origin, + doi={10.1016/j.coche.2016.02.006}, title={On the origin and application of the Bruggeman correlation for analysing transport phenomena in electrochemical systems}, author={Tjaden, Bernhard and Cooper, Samuel J and Brett, Daniel JL and Kramer, Denis and Shearing, Paul R}, journal={Current opinion in chemical engineering}, diff --git a/paper.md b/paper.md index 7832487..6a82a10 100644 --- a/paper.md +++ b/paper.md @@ -18,16 +18,17 @@ authors: affiliation: 1 - name: Samuel Cooper corresponding: true # (This is how to denote the corresponding author) + orcid: 0000-0003-4055-6903 affiliation: 1 affiliations: - - name: Imperial College London, UK + - name: Imperial College London, United Kingdom index: 1 date: 9 March 2023 bibliography: paper.bib --- # Summary -TauFactor 2 is an open-source, GPU accelerated microstructural analysis tool for extracting metrics from voxel based data, including transport properties such as the touristy factor. Tortuosity factor, $\tau$, is a material parameter that defines the reduction in transport arising from the arrangement of the phases in a multiphase medium (see \autoref{example}). As shown in \autoref{eq:tort}, the effective transport co-efficient of a material, $D_{\text{eff}}$, can be calculated from the phases intrinsic transport coefficient, $D$, volume fraction, $\epsilon$, and $\tau$ [@cooper2016taufactor] (note, this value of $\tau$ should not be squared [@tjaden2016origin]). +TauFactor 2 is an open-source, GPU accelerated microstructural analysis tool for extracting metrics from voxel based data, including transport properties such as the touristy factor. Tortuosity factor, $\tau$, is a material parameter that defines the reduction in transport arising from the arrangement of the phases in a multiphase medium (see \autoref{example}). As shown in \autoref{eq:tort}, the effective transport coefficient of a material, $D_{\text{eff}}$, can be calculated from the phases intrinsic transport coefficient, $D$, volume fraction, $\epsilon$, and $\tau$ [@cooper2016taufactor] (note, this value of $\tau$ should not be squared [@tjaden2016origin]). \begin{equation}\label{eq:tort} D_{\text{eff}} = D\dfrac{\epsilon}{\tau} @@ -58,6 +59,10 @@ To compare the performance of TauFactor 2 to other available software, a test vo ![Speed comparison for the four solvers when applied to the test volume. The mean time across all 3 directions is plotted. The values of the overconverged $\tau$ in each direction are: 1.1513, 1.3905, 4.2431. \label{speeds}](tauspeeds.pdf) +# Authorship Contributions + +SK wrote the base, periodic and multiphase solvers with input from IS. IS wrote the electrode solver, metric calculations and documentation, and also performed speed tests for other software packages. The project was supervised by SC, and based on his original MATLAB tool. All authors contributed to the writing and editing of the manuscript. + # Acknowledgements This work was supported by funding from the EPSRC Faraday Institution Multi-Scale Modelling project diff --git a/requirements_dev.txt b/requirements_dev.txt index 39c031f..8c71d95 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -11,6 +11,6 @@ Click==7.0 pytest==4.6.5 matplotlib>3.6 pytest-runner==5.2 -numpy==1.24.2 +numpy>=1.24.2 tifffile==2023.2.3 myst-parser==0.18.1 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 349b7aa..ed1730f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.0.0 +current_version = 1.1.0 commit = True tag = True diff --git a/setup.py b/setup.py index 4ef683b..24c6814 100644 --- a/setup.py +++ b/setup.py @@ -36,6 +36,8 @@ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', ], description="TauFactor is an application for calculating tortuosity factors from tomographic data", install_requires=requirements, @@ -50,6 +52,6 @@ test_suite='tests', tests_require=test_requirements, url='https://github.com/tldr-group/taufactor', - version='1.0.0', + version='1.1.0', zip_safe=False, ) diff --git a/tau_speeds.png b/tau_speeds.png index 6699ff3..882d400 100644 Binary files a/tau_speeds.png and b/tau_speeds.png differ diff --git a/taufactor/__init__.py b/taufactor/__init__.py index 8021fac..4197b8c 100644 --- a/taufactor/__init__.py +++ b/taufactor/__init__.py @@ -2,6 +2,6 @@ __author__ = """Isaac Squires""" __email__ = 'is21@ic.ac.uk' -__version__ = '1.0.0' +__version__ = '1.1.0' from .taufactor import * \ No newline at end of file diff --git a/taufactor/metrics.py b/taufactor/metrics.py index ddc3102..b84667f 100644 --- a/taufactor/metrics.py +++ b/taufactor/metrics.py @@ -55,7 +55,7 @@ def surface_area(img, phases, periodic=False): SA_map = torch.zeros_like(img) if not isinstance(phases, list): - phases = [phases] + raise TypeError('phases should be a list') for i in range(dim): for j in [1, -1]: i_rolled = torch.roll(img, j, i) @@ -86,6 +86,13 @@ def surface_area(img, phases, periodic=False): return sa def triple_phase_boundary(img): + """Calculate triple phase boundary density i.e. fraction of voxel verticies that touch at least 3 phases + + Args: + img (numpy array): image to calculate metric on + Returns: + float: triple phase boundary density + """ phases = torch.unique(torch.tensor(img)) if len(phases)!=3: raise ValueError('Image must have exactly 3 phases') diff --git a/taufactor/taufactor.py b/taufactor/taufactor.py index b1a2735..d18ed9e 100644 --- a/taufactor/taufactor.py +++ b/taufactor/taufactor.py @@ -21,7 +21,6 @@ def __init__(self, img, bc=(-0.5, 0.5), D_0=1, device=torch.device('cuda')): for multiple solves. :param img: input img with 1s conductive and 0s non-conductive - :param precision: cp.single or cp.double :param bc: Upper and lower boundary conditions. Leave as default. :param D_0: reference material diffusivity :param device: pytorch device, can be cuda or cpu @@ -166,12 +165,16 @@ def check_convergence(self, verbose, conv_crit, start, iter_limit): # print progress self.semi_converged, self.new_fl, err = self.check_vertical_flux( conv_crit) - self.D_rel = ((self.new_fl) * self.L_A / - abs(self.top_bc - self.bot_bc)).cpu() - self.tau = self.VF / \ - self.D_rel if self.D_rel != 0 else torch.tensor(torch.inf) if self.semi_converged == 'zero_flux': + self.D_rel = 0 + self.tau = np.inf return True + else: + self.D_rel = ((self.new_fl) * self.L_A / + abs(self.top_bc - self.bot_bc)).cpu() + self.tau = self.VF / \ + self.D_rel if self.D_rel != 0 else torch.tensor(torch.inf) + if verbose == 'per_iter': print( @@ -196,10 +199,10 @@ def check_vertical_flux(self, conv_crit): vert_flux[self.conc[:, 1:-1, 1:-1, 1:-1] == 0] = 0 fl = torch.sum(vert_flux, (0, 2, 3))[1:-1] err = (fl.max() - fl.min())*2/(fl.max() + fl.min()) - if err < conv_crit or torch.isnan(err).item(): - return True, torch.mean(fl), err if fl.min() == 0: return 'zero_flux', torch.mean(fl), err + if err < conv_crit or torch.isnan(err).item(): + return True, torch.mean(fl), err return False, torch.mean(fl), err def check_rolling_mean(self, conv_crit): @@ -233,7 +236,6 @@ def __init__(self, img, bc=(-0.5, 0.5), D_0=1, device=torch.device('cuda:0')): for multiple solves. :param img: input img with 1s conductive and 0s non-conductive - :param precision: cp.single or cp.double :param bc: Upper and lower boundary conditions. Leave as default. :param D_0: reference material diffusivity @@ -313,7 +315,6 @@ def __init__(self, img, cond={1: 1}, bc=(-0.5, 0.5), device=torch.device('cuda:0 :param img: input img with n conductive phases labelled as integers, and 0s for non-conductive :param cond: dict with n phase labels as keys, and their corresponding conductivities as values e.g for a 2 phase material, {1:0.543, 2: 0.420}, with 1s and 2s in the input img - :param precision: cp.single or cp.double :param bc: Upper and lower boundary conditions. Leave as default. """ @@ -495,7 +496,6 @@ def check_vertical_flux(self, conv_crit): :-2, 1:-1, 1:-1]) * self.pre_factors[1][:, :-2, 1:-1, 1:-1] vert_flux[self.nn == torch.inf] = 0 fl = torch.sum(vert_flux, (0, 2, 3))[2:-2] - print(fl.argmin(), fl.argmax()) err = (fl.max() - fl.min())*2/(fl.max() + fl.min()) if err < conv_crit or torch.isnan(err).item(): return True, torch.mean(fl), err diff --git a/tests/test_taufactor.py b/tests/test_taufactor.py index 5d4992d..b36c4d5 100644 --- a/tests/test_taufactor.py +++ b/tests/test_taufactor.py @@ -9,7 +9,7 @@ from tests.utils import * import numpy as np import matplotlib.pyplot as plt - +import torch # Testing the main solver @@ -63,11 +63,32 @@ def test_solver_on_strip_of_ones(): S.solve() assert np.around(S.tau, decimals=5) == 1 +def test_solver_on_slanted_strip_of_ones(): + """Run solver on a slanted strip of ones""" + l = 20 + img = np.zeros([l, l+1, l+1]).reshape(1, l, l+1, l+1) + # t = 10 + # img[:, :, 0:t, 0:t] = 1 + for i in range(l): + img[:, i, i:i+2, i:i+2] = 1 + S = tau.Solver(img, device=pt.device('cpu')) + S.solve() + assert np.around(S.tau, decimals=5) == 4 # Testing the periodic solver +def test_deadend(): + """Test deadend pore""" + solid = np.zeros((10,50,50)) + solid[:8, 25,25] = 1 + # solve for tau + S = tau.Solver(solid) + S.solve() + assert np.around(S.D_eff, decimals=5) == 0 + assert S.tau == np.inf + def test_periodic_solver_on_uniform_block(): - """Run solver on a block of ones.""" + """Run periodic solver on a block of ones.""" l = 20 img = np.ones([l, l, l]).reshape(1, l, l, l) img[:, :, 0] = 0 @@ -77,7 +98,7 @@ def test_periodic_solver_on_uniform_block(): def test_periodic_solver_on_empty_block(): - """Run solver on a block of zeros.""" + """Run periodic solver on a block of zeros.""" l = 20 img = np.zeros([l, l, l]).reshape(1, l, l, l) img[:, 0] = 1 @@ -87,7 +108,7 @@ def test_periodic_solver_on_empty_block(): def test_periodic_solver_on_strip_of_ones(): - """Run solver on a strip of ones, 1/4 volume of total""" + """Run periodic solver on a strip of ones, 1/4 volume of total""" l = 20 img = np.zeros([l, l, l]).reshape(1, l, l, l) t = 10 @@ -144,7 +165,7 @@ def test_surface_area_on_uniform_block(): """Run surface area on uniform block""" l = 20 img = np.ones([l, l, l]) - sa = surface_area(img, phases=1) + sa = surface_area(img, phases=[1]) assert sa == 0 @@ -153,11 +174,10 @@ def test_surface_area_on_empty_block(): """Run surface area on empty block""" l = 20 img = np.zeros([l, l, l]) - sa = surface_area(img, phases=0) + sa = surface_area(img, phases=[0]) assert sa == 0 - def test_surface_area_on_checkerboard(): """Run surface area on checkerboard block""" l = 50 @@ -195,6 +215,7 @@ def test_surface_area_on_periodic_2d(): def test_surface_area_interfactial_3ph(): + """Run surface area 3 phases """ l = 3 img = np.zeros([l, l, l]) img[1] = 1 @@ -204,6 +225,7 @@ def test_surface_area_interfactial_3ph(): def test_tpb_2d(): + """Run tpb on 3x3""" l = 3 img = np.zeros([l, l]) img[0] = 1 @@ -213,6 +235,8 @@ def test_tpb_2d(): def test_tpb_3d_corners(): + """Run tpb on 2x2""" + l = 2 img = np.zeros([l, l, l]) img[0, 0, 0] = 1 @@ -224,6 +248,8 @@ def test_tpb_3d_corners(): def test_tpb_3d_corners(): + """Run tpb on 2x2 corners""" + l = 2 img = np.zeros([l, l, l]) img[0] = 1 @@ -233,6 +259,7 @@ def test_tpb_3d_corners(): def test_multiphase_and_solver_agree(): + """test mph and solver agree when Ds are the same""" x = 100 img = np.ones([x, x, x]) img[50:] = 2 @@ -250,7 +277,7 @@ def test_multiphase_and_solver_agree(): def test_mphsolver_on_empty_block(): - """Run solver on a block of zeros.""" + """Run mpsolver on a block of zeros.""" l = 20 img = np.zeros([l, l, l]).reshape(1, l, l, l) S = tau.MultiPhaseSolver(img, device=pt.device('cpu')) @@ -259,7 +286,7 @@ def test_mphsolver_on_empty_block(): def test_mphsolver_on_ones_block(): - """Run solver on a block of ones.""" + """Run mpsolver on a block of ones.""" l = 20 img = np.ones([l, l, l]).reshape(1, l, l, l) S = tau.MultiPhaseSolver(img, device=pt.device('cpu')) @@ -268,7 +295,7 @@ def test_mphsolver_on_ones_block(): def test_mphsolver_on_halves(): - """Run solver on a block of halves.""" + """Run mpsolver on a block of halves.""" l = 20 img = np.ones([l, l, l]).reshape(1, l, l, l) cond = 0.5 @@ -279,7 +306,7 @@ def test_mphsolver_on_halves(): def test_mphsolver_on_strip_of_ones(): - """Run solver on a strip of ones, 1/4 volume of total""" + """Run mpsolver on a strip of ones, 1/4 volume of total""" l = 20 img = np.zeros([l, l, l]).reshape(1, l, l, l) x = 10 @@ -316,7 +343,7 @@ def test_mphsolver_on_strip_of_ones_and_twos_and_threes(): def test_taue_deadend(): - """Run solver on a strip of ones, 1/4 volume of total""" + """Run solver on a deadend strip of ones""" l = 100 img = np.zeros((l, l)) @@ -328,7 +355,7 @@ def test_taue_deadend(): def test_taue_throughpore(): - """Run solver on a strip of ones, 1/4 volume of total""" + """Run taue solver on a strip of ones, 1/4 volume of total""" l = 100 img = np.zeros((l, l)) diff --git a/tox.ini b/tox.ini index 3a3a29e..fcbafe9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,10 @@ [tox] -envlist = py35, py36, py37, py38, flake8 +envlist = py35, py36, py37, py38, py39, py310, flake8 [travis] python = + 3.10: py310 + 3.9: py39 3.8: py38 3.7: py37 3.6: py36