Skip to content

API Reference

This page contains the API reference for the poromics package.

Main (poromics)

The main module of the poromics package provides the core functionality for calculating tortuosity and other transport properties.

tortuosity_fd(im, *, axis, rtol=1e-05, gpu=False)

Performs a tortuosity simulation on the given image along the specified axis.

The function removes non-percolating paths from the image before performing the tortuosity calculation.

Parameters:

Name Type Description Default
im ndarray

The input image.

required
axis int

The axis along which to compute tortuosity (0=x, 1=y, 2=z).

required
rtol float

Relative tolerance for the solver.

1e-05
gpu bool

If True, use GPU for computation.

False

Returns:

Name Type Description
result Result

An object containing the boolean image, axis, tortuosity, and concentration.

Raises:

Type Description
RuntimeError

If no percolating paths are found along the specified axis.

Source code in src/poromics/_metrics.py
def tortuosity_fd(im, *, axis: int, rtol: float = 1e-5, gpu: bool = False) -> Result:
    """
    Performs a tortuosity simulation on the given image along the specified axis.

    The function removes non-percolating paths from the image before performing
    the tortuosity calculation.

    Args:
        im (ndarray): The input image.
        axis (int): The axis along which to compute tortuosity (0=x, 1=y, 2=z).
        rtol (float): Relative tolerance for the solver.
        gpu (bool): If True, use GPU for computation.

    Returns:
        result: An object containing the boolean image, axis, tortuosity, and
            concentration.

    Raises:
        RuntimeError: If no percolating paths are found along the specified axis.
    """
    axis_jl = _jl.Symbol(["x", "y", "z"][axis])
    im = _taujl.Imaginator.trim_nonpercolating_paths(im, axis=axis_jl)
    if _jl.sum(im) == 0:
        raise RuntimeError("No percolating paths along the given axis found in the image.")
    sim = _taujl.TortuositySimulation(im, axis=axis_jl, gpu=gpu)
    sol = _taujl.solve(sim.prob, _taujl.KrylovJL_CG(), verbose=False, reltol=rtol)
    c = _taujl.vec_to_grid(sol.u, im)
    tau = _taujl.tortuosity(c, axis=axis_jl)
    return Result(np.asarray(im), axis, tau, np.asarray(c))
Julia helpers (poromics.julia_helpers)

The poromics.julia_helpers module provides helper functions for interacting with Julia and the Tortuosity.jl package. These functions are used internally by the main module to perform calculations. Feel free to explore them if you're interested in the implementation details.

ensure_julia_deps_ready(quiet=False, retry=True)

Ensures Julia and Tortuosity.jl are installed.

Parameters:

Name Type Description Default
quiet bool

If True, suppresses output during installation. Default is False.

False
retry bool

If True, retries the installation if it fails. Default is True.

True

Raises:

Type Description
ImportError

If Julia or Tortuosity.jl cannot be installed.

Source code in src/poromics/julia_helpers.py
def ensure_julia_deps_ready(quiet: bool = False, retry: bool = True) -> None:
    """Ensures Julia and Tortuosity.jl are installed.

    Args:
        quiet: If True, suppresses output during installation. Default is False.
        retry: If True, retries the installation if it fails. Default is True.

    Raises:
        ImportError: If Julia or Tortuosity.jl cannot be installed.
    """

    def _ensure_julia_deps_ready(quiet):
        if not is_julia_installed(error=False):
            logger.warning("Julia not found, installing Julia...")
            install_julia(quiet=quiet)
        Main = init_julia(quiet=quiet)
        if not is_backend_installed(Main=Main, error=False):
            logger.warning("Julia dependencies not found, installing Tortuosity.jl...")
            install_backend(quiet=quiet)

    def _reset_julia_env(quiet):
        remove_julia_env()
        if quiet:
            with suppress_output():
                juliapkg.resolve(force=True)
        else:
            juliapkg.resolve(force=True)

    try:
        _ensure_julia_deps_ready(quiet)
    except Exception:
        if retry:
            _reset_julia_env(quiet)
            _ensure_julia_deps_ready(quiet)
            return
        raise

import_backend(Main=None)

Imports Tortuosity.jl package from Julia.

Parameters:

Name Type Description Default
Main ModuleValue

Julia Main module. Default is None. If None, the Main module will be initialized.

None

Returns:

Name Type Description
backend ModuleValue

Handle to the Tortuosity.jl package.

Raises:

Type Description
ImportError

If Julia is not installed or the package is not found.

Source code in src/poromics/julia_helpers.py
def import_backend(Main: "juliacall.ModuleValue" = None) -> "juliacall.ModuleValue":
    """Imports Tortuosity.jl package from Julia.

    Args:
        Main: Julia Main module. Default is None. If None, the Main module will
            be initialized.

    Returns:
        backend: Handle to the Tortuosity.jl package.

    Raises:
        ImportError: If Julia is not installed or the package is not found.
    """
    Main = init_julia() if Main is None else Main
    is_backend_installed(Main=Main, error=True)
    return import_package("Tortuosity", Main)

import_package(package_name, Main, error=False)

Imports a package in Julia and returns the module.

Parameters:

Name Type Description Default
package_name str

Name of the Julia package to import.

required
Main ModuleValue

Julia Main module.

required
error bool

If True, raises an error if the package is not found. Default is False.

False

Returns:

Name Type Description
package ModuleValue

Handle to the imported package.

Raises:

Type Description
ImportError

If the package is not found and error is True.

Source code in src/poromics/julia_helpers.py
def import_package(
    package_name: str, Main: "juliacall.ModuleValue", error: bool = False
) -> "juliacall.ModuleValue":
    """Imports a package in Julia and returns the module.

    Args:
        package_name: Name of the Julia package to import.
        Main: Julia Main module.
        error: If True, raises an error if the package is not found. Default is False.

    Returns:
        package: Handle to the imported package.

    Raises:
        ImportError: If the package is not found and error is True.
    """
    from juliacall import JuliaError

    try:
        Main.seval(f"using {package_name}")
        return eval(f"Main.{package_name}")
    except JuliaError as e:
        if error:
            raise e
    return None

init_julia(quiet=False)

Initializes Julia and returns the Main module.

Parameters:

Name Type Description Default
quiet bool

If True, suppresses the output of Julia initialization. Default is False.

False

Returns:

Name Type Description
Main ModuleValue

The Julia Main module.

Raises:

Type Description
ImportError

If Julia is not installed.

Source code in src/poromics/julia_helpers.py
def init_julia(quiet: bool = False) -> "juliacall.ModuleValue":
    """Initializes Julia and returns the Main module.

    Args:
        quiet: If True, suppresses the output of Julia initialization. Default is False.

    Returns:
        Main: The Julia Main module.

    Raises:
        ImportError: If Julia is not installed.
    """
    is_julia_installed(error=True)
    if not can_skip_resolve():
        logger.warning("Julia is installed, but needs to be resolved...")
    if quiet:
        with suppress_output():
            from juliacall import Main  # type: ignore
    else:
        from juliacall import Main  # type: ignore

    return Main

install_backend(quiet=False)

Installs Julia dependencies for Poromics.

Parameters:

Name Type Description Default
quiet bool

If True, suppresses output during installation. Default is False.

False

Raises:

Type Description
ImportError

If Julia is not installed.

Source code in src/poromics/julia_helpers.py
def install_backend(quiet: bool = False) -> None:
    """Installs Julia dependencies for Poromics.

    Args:
        quiet: If True, suppresses output during installation. Default is False.

    Raises:
        ImportError: If Julia is not installed.
    """
    is_julia_installed(error=True)

    if quiet:
        with suppress_output():
            juliapkg.resolve()
    else:
        juliapkg.resolve()

install_julia(quiet=False)

Installs Julia using juliapkg.

Parameters:

Name Type Description Default
quiet bool

If True, suppresses output during installation. Default is False.

False
Source code in src/poromics/julia_helpers.py
def install_julia(quiet: bool = False) -> None:
    """Installs Julia using juliapkg.

    Args:
        quiet: If True, suppresses output during installation. Default is False.
    """
    # Importing juliacall automatically installs Julia using juliapkg
    if quiet:
        with suppress_output():
            import juliacall  # noqa: F401
    else:
        import juliacall  # noqa: F401

is_backend_installed(Main=None, error=False)

Checks if Tortuosity.jl is installed.

Parameters:

Name Type Description Default
Main ModuleValue

Julia Main module. Default is None. If None, it will be initialized.

None
error bool

If True, raises an error if backend is not found. Default is False.

False

Returns:

Name Type Description
flag bool

True if the package is installed, False otherwise.

Raises:

Type Description
ImportError

If Julia is not installed or backend is not found and error is True.

Source code in src/poromics/julia_helpers.py
def is_backend_installed(Main: "juliacall.ModuleValue" = None, error: bool = False) -> bool:
    """Checks if Tortuosity.jl is installed.

    Args:
        Main: Julia Main module. Default is None. If None, it will be initialized.
        error: If True, raises an error if backend is not found. Default is False.

    Returns:
        flag: True if the package is installed, False otherwise.

    Raises:
        ImportError: If Julia is not installed or backend is not found and error is True.
    """
    Main = init_julia() if Main is None else Main
    if import_package("Tortuosity", Main, error=False) is not None:
        return True
    msg = "Tortuosity.jl not found, run 'python -m poromics install'"
    if error:
        raise ImportError(msg)
    return False

is_julia_installed(error=False)

Checks that Julia is installed.

Parameters:

Name Type Description Default
error bool

If True, raises an error if Julia is not found. Default is False.

False

Returns:

Name Type Description
flag bool

True if Julia is installed, False otherwise.

Raises:

Type Description
ImportError

If Julia is not installed and error is True.

Source code in src/poromics/julia_helpers.py
def is_julia_installed(error: bool = False) -> bool:
    """Checks that Julia is installed.

    Args:
        error: If True, raises an error if Julia is not found. Default is False.

    Returns:
        flag: True if Julia is installed, False otherwise.

    Raises:
        ImportError: If Julia is not installed and error is True.
    """
    # Look for system-wide Julia executable
    try:
        find_julia()
        return True
    except Exception:
        pass
    # Look for local Julia executable (e.g., installed by juliapkg)
    if can_skip_resolve():
        return True
    msg = "Julia not found. Visit https://github.com/JuliaLang/juliaup and install Julia."
    if error:
        raise ImportError(msg)
    return False

remove_julia_env()

Removes the active Julia environment directory.

When Julia or its dependencies are corrupted, this is a possible fix.

Source code in src/poromics/julia_helpers.py
def remove_julia_env() -> None:
    """Removes the active Julia environment directory.

    When Julia or its dependencies are corrupted, this is a possible fix.
    """
    path_julia_env = Path(juliapkg.project())

    if path_julia_env.exists():
        logger.warning(f"Removing Julia environment directory: {path_julia_env}")
        shutil.rmtree(path_julia_env)
    else:
        logger.warning("Julia environment directory not found.")