Getting Started¶
This page covers package installation and the smallest end-to-end workflow that exercises the pore-network single-phase solver. For the map-based FVM/FEM and direct-image LBM backends, see Map-Based Single-Phase Solvers after the basic installation is working.
Installation¶
Install from PyPI¶
If you want the published package from PyPI:
Package page: https://pypi.org/project/voids/
Editable pip install¶
If you prefer a plain Python environment from a local repository checkout (Python ≥ 3.11):
Optional extras:
# Development tools (pytest, ruff, mypy, jupyterlab …)
python -m pip install -e ".[dev]"
# PyVista visualization
python -m pip install -e ".[viz]"
# OpenPNM cross-check tests
python -m pip install -e ".[test]"
# Optional XLB benchmark stack
python -m pip install -e ".[lbm]"
# Portable Python solver helpers and Gmsh bindings
python -m pip install -e ".[solvers,fem]"
# Common development and scientific extras
python -m pip install -e ".[dev,viz,test,lbm,solvers,fem]"
The solvers PyPI extra installs PyAMG but intentionally does not source-build
SuiteSparse/UMFPACK. The fem PyPI extra installs Gmsh bindings, but PyPI does
not distribute DOLFINx. Plain pip users must therefore provide a compatible
FEniCSx/DOLFINx stack separately before using voids.fem.
For Pixi/conda distribution, the repository includes a package definition whose
runtime metadata carries DOLFINx, Gmsh, PyAMG, and binary UMFPACK transitively.
This is the appropriate artifact for a consuming Pixi project that should
declare only voids; it must be built and published to a conda channel before
external projects can resolve it from that channel.
Repository development, notebook variables, and documentation build commands are covered in Development.
Minimal Example¶
The simplest way to exercise voids is with a synthetic linear-chain network:
from voids.examples import make_linear_chain_network
from voids.physics.petrophysics import absolute_porosity
from voids.physics.singlephase import FluidSinglePhase, PressureBC, solve
# Build a small synthetic network
net = make_linear_chain_network()
# Define fluid and boundary conditions
fluid = FluidSinglePhase(viscosity=1.0)
bc = PressureBC("inlet_xmin", "outlet_xmax", pin=1.0, pout=0.0)
# Solve single-phase incompressible flow
result = solve(net, fluid=fluid, bc=bc, axis="x")
# Print results
print("phi_abs =", absolute_porosity(net))
print("total_flow_rate =", result.total_flow_rate)
print("permeability x =", result.permeability["x"])
print("mass_balance_error =", result.mass_balance_error)
Assumptions to keep in mind:
- the default demo network is synthetic and intentionally simple
viscosity=1.0is dimensionless unless you also define consistent physical units- permeability is only meaningful when the attached
SampleGeometryis physically meaningful
For the canonical data model, label conventions, and unit expectations behind that example, see Concepts and Conventions.
For extracted or imported networks, continue with Scientific Workflow rather than copying the synthetic example verbatim.
Pressure-Dependent Viscosity¶
For water-property studies, voids can also solve with pressure-dependent viscosity:
from voids.physics.singlephase import FluidSinglePhase, PressureBC, SinglePhaseOptions, solve
from voids.physics.thermo import TabulatedWaterViscosityModel
mu_model = TabulatedWaterViscosityModel.from_backend(
"thermo",
temperature=298.15,
pressure_points=128,
)
result = solve(
net,
fluid=FluidSinglePhase(viscosity_model=mu_model),
bc=PressureBC("inlet_xmin", "outlet_xmax", pin=2.0e5, pout=1.0e5),
axis="x",
options=SinglePhaseOptions(
conductance_model="valvatne_blunt",
nonlinear_solver="newton",
solver="gmres",
solver_parameters={"preconditioner": "pyamg"},
),
)
Two assumptions change in this mode:
- pressures must be absolute and positive, typically in Pa
- the nonlinear solve is with respect to the tabulated/interpolated constitutive law, not the raw backend callable directly