Benchmarks¶
The voids.benchmarks sub-package provides utilities for cross-checking voids
results against reference implementations such as OpenPNM and XLB. In the
broader project documentation, these utilities belong to the verification
side of the Verification & Validation split: they benchmark voids against
software references or alternative numerical workflows, not directly against
experimental measurements.
The two high-level segmented-volume benchmark wrappers now share the same physical pressure convention:
- the preferred public input is the physical pressure drop
delta_p, typically in Pa - optional
pinandpoutvalues can also be supplied when the user wants to preserve a particular absolute pressure reference level - for the current incompressible permeability benchmark, only the pressure drop
Δp = pin - poutaffects the reported permeability - the applied
p_inlet_physical,p_outlet_physical, anddp_physicalvalues are recorded in the benchmark result tables
So delta_p=1.0, pin=1.0/pout=0.0, and delta_p=1.0 with
pin=101326.0/pout=101325.0 all represent the same current benchmark
driving condition.
The XLB benchmark API now has two distinct package layers:
voids.lbm.singlephase.xlb.solve_binary_volume_with_xlbis the low-level direct-image solver. It works in lattice units and accepts lattice pressure boundary conditions throughpressure_inlet_lattice,pressure_outlet_lattice, orpressure_drop_lattice.voids.benchmarks.xlb.benchmark_segmented_volume_with_xlbis the high-level verification wrapper. It resolves a physical pressure drop fromdelta_pand optionalpin/pout, then maps that same physicalΔpinto lattice units before calling XLB on the original binary image.
For backward compatibility, voids.benchmarks.xlb re-exports the low-level XLB
types and direct solver, but the implementation lives in voids.lbm.
For the high-level XLB benchmark, fluid.density must be provided because the
shared physical pressure drop must be converted into lattice pressure units.
Cross-Check¶
voids.benchmarks.crosscheck
¶
SinglePhaseCrosscheckSummary
dataclass
¶
Summary of a solver-to-reference comparison.
Attributes:
| Name | Type | Description |
|---|---|---|
reference |
str
|
Name of the reference implementation or workflow. |
axis |
str
|
Flow axis used in the comparison. |
permeability_abs_diff, permeability_rel_diff |
Absolute and relative differences between apparent permeabilities. |
|
total_flow_abs_diff, total_flow_rel_diff |
Absolute and relative differences between total flow rates. |
|
details |
dict[str, Any]
|
Auxiliary metadata useful for debugging and reporting. |
Source code in src/voids/benchmarks/crosscheck.py
ConduitConductanceAudit
dataclass
¶
Per-throat single-phase conduit conductance breakdown.
The arrays are defined on throat order and expose the exact pore1-core-pore2
decomposition used by the voids Valvatne-Blunt conduit model. The three
segment conductances match the Imperial pnflow SPConductance(area, mu)
semantics, meaning lengths are accounted for separately in the equivalent
pore-to-pore resistance sum.
Source code in src/voids/benchmarks/crosscheck.py
to_columns
¶
Return a tabulation-friendly column mapping.
Source code in src/voids/benchmarks/crosscheck.py
NetworkGeometrySummary
dataclass
¶
Compact geometry and connectivity summary for one pore network.
Source code in src/voids/benchmarks/crosscheck.py
to_record
¶
Return a flat record with prefixed field names.
Source code in src/voids/benchmarks/crosscheck.py
NetworkGeometryComparison
dataclass
¶
Geometry and topology mismatch summary between two pore networks.
Source code in src/voids/benchmarks/crosscheck.py
to_record
¶
Return a flat comparison record suitable for CSV export.
Source code in src/voids/benchmarks/crosscheck.py
summarize_network_geometry
¶
Summarize geometry and connectivity for a network or pore-induced subset.
Source code in src/voids/benchmarks/crosscheck.py
compare_network_geometry
¶
compare_network_geometry(
reference_net,
candidate_net,
*,
axis,
reference_pore_mask=None,
candidate_pore_mask=None,
reference_name="reference",
candidate_name="candidate",
)
Compare geometry and connectivity between two networks or pore subsets.
Source code in src/voids/benchmarks/crosscheck.py
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | |
audit_singlephase_conduit_conductance
¶
audit_singlephase_conduit_conductance(
net,
viscosity,
*,
model="valvatne_blunt",
pore_viscosity=None,
throat_viscosity=None,
)
Return a per-throat conduit conductance breakdown for voids.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
net
|
Network
|
Network with conduit lengths and pore/throat geometry. |
required |
viscosity
|
float | ndarray | None
|
Scalar or array viscosity passed to the Valvatne-Blunt closure. |
required |
model
|
str
|
Conductance model. Currently only the conduit-based Imperial-style
variants |
'valvatne_blunt'
|
pore_viscosity
|
float | ndarray | None
|
Optional separate viscosities for pore and throat segments. |
None
|
throat_viscosity
|
float | ndarray | None
|
Optional separate viscosities for pore and throat segments. |
None
|
Returns:
| Type | Description |
|---|---|
ConduitConductanceAudit
|
Per-throat geometric and conductance decomposition. |
Source code in src/voids/benchmarks/crosscheck.py
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | |
crosscheck_singlephase_roundtrip_openpnm_dict
¶
Cross-check voids after a dict roundtrip through OpenPNM-style keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
net
|
Network
|
Network to solve and round-trip. |
required |
fluid
|
FluidSinglePhase
|
Fluid properties. |
required |
bc
|
PressureBC
|
Pressure boundary conditions. |
required |
axis
|
str
|
Flow axis used in the permeability calculation. |
required |
options
|
SinglePhaseOptions | None
|
Optional solver configuration. |
None
|
Returns:
| Type | Description |
|---|---|
SinglePhaseCrosscheckSummary
|
Comparison between the original |
Notes
This path does not require OpenPNM itself. It checks whether exporting to the
flat OpenPNM/PoreSpy naming convention and importing back into voids changes
any transport-relevant fields.
Source code in src/voids/benchmarks/crosscheck.py
crosscheck_singlephase_with_openpnm
¶
Cross-check voids against OpenPNM StokesFlow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
net
|
Network
|
Network to simulate. |
required |
fluid
|
FluidSinglePhase
|
Fluid properties. |
required |
bc
|
PressureBC
|
Pressure boundary conditions. |
required |
axis
|
str
|
Flow axis used for apparent permeability. |
required |
options
|
SinglePhaseOptions | None
|
Optional solver configuration. |
None
|
Returns:
| Type | Description |
|---|---|
SinglePhaseCrosscheckSummary
|
Comparison between |
Raises:
| Type | Description |
|---|---|
ImportError
|
If OpenPNM is not installed. |
RuntimeError
|
If the installed OpenPNM API is incompatible with the adapter. |
ValueError
|
If the imposed pressure drop is zero. |
Notes
The comparison injects the voids-computed throat.hydraulic_conductance
into OpenPNM. That means the crosscheck isolates differences in system assembly,
boundary-condition handling, sign conventions, and linear-solver behavior,
rather than differences in geometric conductance modeling.
Source code in src/voids/benchmarks/crosscheck.py
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 | |
Segmented Volume Benchmarks¶
voids.benchmarks.segmented_volume
¶
SegmentedVolumeCrosscheckResult
dataclass
¶
Store extraction, porosity, and solver cross-check outputs.
Attributes:
| Name | Type | Description |
|---|---|---|
extract |
NetworkExtractionResult
|
Result of importing the segmented volume into a |
fluid |
FluidSinglePhase
|
Fluid properties used in the permeability solve. |
bc |
PressureBC
|
Pressure boundary conditions imposed on the extracted network. |
options |
SinglePhaseOptions
|
Solver and conductance options used for the comparison. |
image_porosity |
float
|
Void fraction of the segmented binary image. |
absolute_porosity, effective_porosity |
Porosity diagnostics computed from the pruned extracted network. |
|
summary |
SinglePhaseCrosscheckSummary
|
Comparison summary between |
Notes
This high-level benchmark follows the same public pressure-BC convention as
benchmark_segmented_volume_with_xlb: the preferred user input is
delta_p, while optional pin / pout values can still be used to
preserve an absolute pressure gauge. The applied physical pressures and
pressure drop are recorded explicitly in
:meth:SegmentedVolumeCrosscheckResult.to_record.
Source code in src/voids/benchmarks/segmented_volume.py
to_record
¶
Return scalar diagnostics suitable for tabulation.
Source code in src/voids/benchmarks/segmented_volume.py
benchmark_segmented_volume_with_openpnm
¶
benchmark_segmented_volume_with_openpnm(
phases,
*,
voxel_size,
extraction_backend="porespy",
flow_axis=None,
fluid=None,
delta_p=None,
pin=None,
pout=None,
options=None,
length_unit="m",
pressure_unit="Pa",
extraction_kwargs=None,
provenance_notes=None,
strict=True,
)
Benchmark an extracted segmented volume against OpenPNM.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
phases
|
ndarray
|
Binary segmented image encoded as |
required |
voxel_size
|
float
|
Edge length of one voxel in the declared length unit. |
required |
extraction_backend
|
str
|
Image-to-network extraction backend forwarded to
:func: |
'porespy'
|
flow_axis
|
str | None
|
Requested transport axis. When omitted, the longest image axis is used. |
None
|
fluid
|
FluidSinglePhase | None
|
Fluid properties. Defaults to water-like viscosity |
None
|
delta_p
|
float | None
|
Preferred physical pressure drop for the benchmark, typically in Pa.
When provided alone, the wrapper uses |
None
|
pin
|
float | None
|
Optional absolute physical inlet and outlet pressures. They are kept for
backward compatibility and for cases where the user wants to preserve a
particular pressure reference level. For the current incompressible
benchmark, only the pressure drop |
None
|
pout
|
float | None
|
Optional absolute physical inlet and outlet pressures. They are kept for
backward compatibility and for cases where the user wants to preserve a
particular pressure reference level. For the current incompressible
benchmark, only the pressure drop |
None
|
options
|
SinglePhaseOptions | None
|
Solver controls. Defaults to the image-workflow baseline
|
None
|
length_unit
|
str
|
Units attached to the extracted sample geometry. |
'm'
|
pressure_unit
|
str
|
Units attached to the extracted sample geometry. |
'm'
|
extraction_kwargs
|
dict[str, object] | None
|
Extra keyword arguments forwarded to |
None
|
provenance_notes
|
dict[str, object] | None
|
Optional metadata attached to the extracted network provenance. |
None
|
strict
|
bool
|
Forwarded to :func: |
True
|
Returns:
| Type | Description |
|---|---|
SegmentedVolumeCrosscheckResult
|
Extraction metadata, porosity diagnostics, and the OpenPNM comparison. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the image is invalid, the pressure specification is inconsistent, or the implied pressure drop is not positive. |
Notes
This helper uses :func:voids.benchmarks.crosscheck_singlephase_with_openpnm,
which injects the voids throat hydraulic conductances into OpenPNM. The
resulting comparison isolates extraction consistency, boundary-condition
handling, and linear-solver agreement; it does not benchmark independent
conductance models between packages.
Unlike the XLB high-level benchmark, no fluid-density-based unit conversion is needed here because both sides solve the same extracted pore network directly under the same physical pressure BC.
The absolute pressure offset is numerically immaterial for this current
incompressible benchmark. For example, delta_p=1, pin=1/pout=0,
and delta_p=1 with pin=101326/pout=101325 all impose the same
permeability-driving pressure drop.
Source code in src/voids/benchmarks/segmented_volume.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | |
voids.benchmarks.xlb
¶
Segmented-volume benchmarks that consume the XLB LBM backend.
The direct-image XLB adapter lives in :mod:voids.lbm.singlephase.xlb. This
module composes that backend with voids network extraction and single-phase
PNM solves for benchmark comparisons. Low-level XLB symbols are re-exported here
for backward compatibility with older notebooks.
XLBConvergenceWarning
¶
XLBDirectSimulationResult
dataclass
¶
Store direct-image LBM outputs from an XLB run.
Attributes:
| Name | Type | Description |
|---|---|---|
lattice_pressure_inlet, lattice_pressure_outlet, lattice_pressure_drop |
Resolved inlet, outlet, and differential pressure in lattice units. |
|
lattice_density_inlet, lattice_density_outlet |
Equivalent lattice densities associated with the pressure BCs through
|
|
permeability |
float
|
Apparent permeability mapped back to physical units. |
max_mach_lattice, reynolds_voxel_max |
Low-inertia diagnostics useful when interpreting a run as a creeping-flow reference. |
Source code in src/voids/lbm/singlephase/xlb.py
XLBOptions
dataclass
¶
Numerical controls for the direct-image XLB solver.
Attributes:
| Name | Type | Description |
|---|---|---|
formulation |
str
|
Either |
backend |
str
|
XLB compute backend. The current |
precision_policy |
str
|
XLB precision policy name, for example |
collision_model |
str
|
XLB collision operator label passed to the stepper. |
streaming_scheme |
str
|
XLB streaming scheme label passed to the stepper. |
lattice_viscosity |
float
|
Kinematic viscosity in lattice units. |
pressure_inlet_lattice, pressure_outlet_lattice |
Optional inlet and outlet lattice pressures. If both are provided they define the pressure BC directly. |
|
pressure_drop_lattice |
float | None
|
Optional lattice pressure drop. When set without explicit inlet/outlet
pressures, it is applied relative to |
reference_density_lattice |
float
|
Reference lattice density used to construct a baseline outlet pressure
when only |
rho_inlet, rho_outlet |
Legacy density-based BC inputs retained for backward compatibility.
They are converted internally to lattice pressure using
|
|
inlet_outlet_buffer_cells |
int
|
Number of fluid reservoir layers inserted ahead of and behind the sample. |
max_steps, min_steps, check_interval, steady_rtol |
Iteration and convergence controls for the steady-state solve. |
Notes
The current voids adapter uses XLB's JAX backend only. This keeps the
dependency path compatible with CPU-only macOS and Linux environments.
The currently exposed XLB operator is the incompressible Navier-Stokes
lattice-Boltzmann stepper. Setting formulation="steady_stokes_limit"
does not switch to a different PDE solver; it selects conservative forcing
and convergence defaults so the converged solution can be interpreted in the
steady creeping-flow limit.
In this isothermal LBM setting, lattice pressure satisfies
p_lu = c_s^2 rho. The preferred public inputs are therefore the lattice
pressure fields pressure_inlet_lattice / pressure_outlet_lattice or
the pressure drop pressure_drop_lattice. The legacy fields rho_inlet
and rho_outlet remain supported for backward compatibility and are
converted internally to pressure.
Source code in src/voids/lbm/singlephase/xlb.py
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | |
steady_stokes_defaults
classmethod
¶
Return a conservative preset for the steady creeping-flow limit.
Notes
XLB does not currently expose a separate Stokes-only stepper in the
installed package used by voids. This preset therefore still uses the
incompressible Navier-Stokes LBM operator, but with a smaller lattice
pressure drop and tighter steady-state controls so the converged solution is
interpreted in the low-Reynolds, low-Mach limit.
The buffer and convergence controls are intentionally stricter than the
generic :class:XLBOptions defaults. They were selected from same-ROI
DRP-317 sensitivity runs as a conservative direct-image permeability
preset, not as a fit to experimental permeability.
Source code in src/voids/lbm/singlephase/xlb.py
SegmentedVolumeXLBResult
dataclass
¶
Store extraction, porosity, and direct-image XLB benchmark outputs.
Attributes:
| Name | Type | Description |
|---|---|---|
bc |
PressureBC
|
Physical pressure BC used on the extracted-network |
xlb_options |
XLBOptions
|
XLB options actually used for the direct-image solve. For the high-level
benchmark wrapper these are pressure-coupled so they match the resolved
physical pressure drop used on the |
xlb_result |
XLBDirectSimulationResult
|
Direct-image XLB result, including resolved lattice pressure diagnostics. |
Source code in src/voids/benchmarks/xlb.py
to_record
¶
Return scalar diagnostics suitable for tabulation.
Source code in src/voids/benchmarks/xlb.py
solve_binary_volume_with_xlb
¶
Backward-compatible wrapper for the LBM XLB direct-image solver.
Source code in src/voids/benchmarks/xlb.py
benchmark_segmented_volume_with_xlb
¶
benchmark_segmented_volume_with_xlb(
phases,
*,
voxel_size,
flow_axis=None,
fluid=None,
delta_p=None,
pin=None,
pout=None,
options=None,
xlb_options=None,
length_unit="m",
pressure_unit="Pa",
extraction_kwargs=None,
provenance_notes=None,
strict=True,
)
Benchmark a segmented volume against a direct-image XLB solve.
The voids side solves on the extracted pore network. The XLB side solves
directly on the binary segmented image through
:func:voids.lbm.singlephase.xlb.solve_binary_volume_with_xlb. The wrapper
enforces a shared physical pressure drop before comparing permeability.
Source code in src/voids/benchmarks/xlb.py
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | |