peclet.voro — dynamic Voronoi tessellation + Voronoi-mesh flow¶
Moving-cell Voronoi tessellation, moving-cell dynamics, the unstructured-mesh generator that feeds peclet.flow, the covolume / collocated Navier–Stokes solver on a Voronoi mesh (FlowSolver) and the distributed moving tessellation (DistributedTessellation, over the VoronoiHalo primitive). Developer instruments live on each object's diagnostics; the pore-mesh algorithms are peclet.voro.pore_mesh, the scene helpers peclet.voro.scenes.
Note
Auto-generated from the installed module docstrings. Drive simulations from Python; the full C++ API is on each repo's Doxygen site.
peclet.voro¶
peclet.voro — dynamic 3D Voronoi tessellation of moving particles.
A device-native (Kokkos) moving-cell Voronoi engine: periodic boxes, incremental cell repair, and
compressible Euler / Navier–Stokes / multiphase dynamics on the moving cells. Also serves as
an unstructured-mesh generator that can feed an Eulerian solve in :mod:peclet.flow. The compiled
backend (Serial / OpenMP / CUDA / HIP) is chosen at build time — peclet.voro.execution_space reports
which one this build has.
The public surface (suite/docs/QUALITY_PLAN.md D2 — everything else is on each object's
diagnostics):
- :class:
Tessellation— cold build + incremental repair of a moving point set, volumes, neighbour and wall counts, the energy layer (energy_forces). - :class:
FlowSolver— the static collocated / covolume Navier–Stokes solvers on the face mesh. - :class:
Simulation— the moving-cell compressible-Euler / Navier–Stokes fluid. - :func:
optimize_volume_mesh, :func:minimize_interface— mesh optimisers on a periodic box. - :mod:
peclet.voro.pore_mesh(imported on first use) — the SDF-walled pore-space family:optimize_pore_mesh,redistribute_pore_mesh,sdf_voronoi_cells,sdf_voronoi_section. - :mod:
peclet.voro.scenes(imported on first use) — scene helpers:sphere_union_scene,sphere_union_sdf. - :class:
VoronoiHalo, :class:DistributedTessellation— the MPI path (builds withPECLET_VORO_MPI=ONonly). defaults— the named defaults the engine is driven with;execution_space;finalize.
peclet is an implicit (PEP 420) namespace shared with the other peclet-* packages, so it has no
top-level __init__.py.
Tessellation¶
Moving-particle (power-)Voronoi tessellator on the device path, optionally clipped by an SDF solid.
Build a tessellation once (build) then advance it cheaply as the points move (step) —
the incremental two-pass repair is several times faster than rebuilding for the small
per-step displacements typical of CFD/DEM, and falls back to a full rebuild (via an
adaptive gate) when displacements are large, so it is never much slower than a cold
build. Periodic box anchored at the origin. Single domain (one process); see
DistributedTessellation for the MPI driver. Instruments: diagnostics.
| Method / property | Description |
|---|---|
build |
build(self, positions: ndarray[dtype=float64, order='C'], strict: bool = False) -> None Cold-build the (power-)Voronoi tessellation of positions (N,3) from scratch and make it resident, clipped by the geometry from set_geometry if any. Sets the particle count N for subsequent step calls. Warns (raises if strict=True) when the result is not a guaranteed-exact partition: buried power cells (a seed outside its own cell — never for w = r² of non-overlapping spheres), a search reach beyond half the box, or overflowed cells; see diagnostics.build_report(). |
clear_geometry |
clear_geometry(self) -> None Drop the SDF geometry (takes effect at the next build). |
clear_weights |
clear_weights(self) -> None Back to the unweighted Voronoi diagram (next build). |
diagnostics |
The diagnostics tier: build_report(), set_local_certificate(), set_gate(), set_profile(). |
energy_forces |
energy_forces(self, types: ndarray[dtype=int32, order='C'], tension: ndarray[dtype=float64, order='C'], sigma_wall: ndarray[dtype=float64, order='C'] |
extent |
The box size (Lx, Ly, Lz) — read-only; set it with set_domain. |
get_neighbor_counts |
get_neighbor_counts(self) -> numpy.ndarray[dtype=int32] Per-particle Voronoi neighbour count (N,) int32 (a copy) — the number of faces of each cell (wall facets included). |
get_volumes |
get_volumes(self) -> numpy.ndarray[dtype=float64] Per-particle Voronoi cell volume (N,) float64 (a copy). Sums to the box volume (space-filling). |
get_wall_counts |
get_wall_counts(self) -> numpy.ndarray[dtype=int32] Per-particle number of resident SDF wall planes (N,) int32 (a copy); all zero without geometry. |
num_particles |
Particle count N set by the last build (0 before it). |
set_domain |
set_domain(self, extent: collections.abc.Sequence[float], origin: collections.abc.Sequence[float] = [0.0, 0.0, 0.0], periodic: collections.abc.Sequence[bool] = [True, True, True]) -> None Set the periodic box before build: extent is the box SIZE (Lx, Ly, Lz). The suite-wide spelling (suite/docs/NAMING.md 1.1), the same call dem.Simulation.set_domain takes. origin must be (0, 0, 0) and periodic (True, True, True) — this engine's box is anchored at the origin and periodic on every axis; both are checked rather than ignored, so a caller who writes the suite-wide form gets an error naming the limitation. |
set_geometry |
set_geometry(self, node_ints: ndarray[dtype=int32, order='C'], node_reals: ndarray[dtype=float64, order='C'], root: int = 0, grad_h: float = 1e-05) -> None Clip the cells by an SDF solid given as a core shape scene in the flat node encoding (node_ints int32 (3 per node), node_reals float64 (16 per node)) — exactly what peclet.geom.SceneBuilder.encode() returns and dem.add_analytic_wall takes; root is the tree root to evaluate. Suite sign convention: sdf < 0 inside the solid. Seeds inside the solid get no cell (volume 0); cells reaching into it gain wall facets. Applies to the next build and is carried through every step (wall planes are resident; a boundary watch re-clips cells at the wall). grad_h (default 1e-05) is the central-difference step for the SDF gradient. Analytic vocabulary only (no sampled grids through this path yet). |
set_tolerance |
set_tolerance(self, frac: float = 0.0001) -> None Certificate tolerance of the repair as a fraction of the mean inter-particle spacing (default 0.0001 = peclet.voro.defaults['certificate_tolerance']). A vertex poking past a stored plane by more than this flags the cell for repair; smaller is stricter (closer to machine-exact) at marginally higher cost. Takes effect at the next build(). |
set_wall_mode |
set_wall_mode(self, mode: str, skin_frac: float = 0.0) -> None Wall re-gather policy for step. mode: one of 'exact', 'skin'. 'exact' (the default) re-clips every wall-clipped cell that moved, so the incremental result equals a cold rebuild; 'skin' keeps a cell's stale tangent planes until it moved more than skin_frac x the mean spacing (default 0; cheaper, not exact by construction). Takes effect at the next build(). |
set_weights |
set_weights(self, weights: ndarray[dtype=float64, order='C']) -> None Per-seed POWER (Laguerre) weights (N,) float64: the cells become the power diagram (radical planes) instead of the Voronoi diagram. Takes effect at the next build; call again before a step to update the weights alongside the positions. Exact in the small-weight regime (see the docs). |
step |
step(self, positions: ndarray[dtype=float64, order='C']) -> dict Incrementally repair the resident tessellation to new positions (N,3, same N as build; raises before build). Returns a dict of per-step work stats: 'flagged' (cells the certificate flagged), 'pass1' and 'pass2' (cells re-gathered in each pass), 'extra' (cells gathered across verify extra-passes), 'surgical' (Pass-1 cells repaired surgically), 'verify_passes' (verify iterations run), 'rebuilt' (True if the gate routed this step to a full rebuild), 'fell_back' (True if the verify failed and a cold rebuild was forced), 'wall_flagged' (cells the SDF boundary watch re-clipped). |
Simulation¶
Device-native compressible-Euler / Navier-Stokes Voronoi fluid simulation.
Velocity-Verlet dynamics of a moving-particle Voronoi fluid: pressure forces from an
EOS plus an optional per-particle viscous (Navier-Stokes) term, with the tessellation
repaired each step on the device. Set the particle state, init, set_dt, then step;
the state setters raise after init (the state is then resident on the device).
Instruments: diagnostics.
| Method / property | Description |
|---|---|
clear_geometry |
clear_geometry(self) -> None Drop the SDF geometry (before init()). |
diagnostics |
The diagnostics tier: set_repair(), set_profile(). |
dt |
The stored time step (0 until set_dt). |
extent |
The box size (Lx, Ly, Lz) — read-only; set it with set_domain. |
get_forces |
get_forces(self) -> numpy.ndarray[dtype=float64] Current per-particle force (N,3) float64 — the pressure (EOS) force plus the optional viscous Navier-Stokes term, as used by the last velocity-Verlet kick. Useful for force-field analysis, equilibrium/convergence checks, and coupling. |
get_neighbor_counts |
get_neighbor_counts(self) -> numpy.ndarray[dtype=int32] Per-particle Voronoi neighbour (facet) count (N,) int32 (a copy). |
get_positions |
get_positions(self) -> numpy.ndarray[dtype=float64] Current particle positions (N,3) float64. |
get_velocities |
get_velocities(self) -> numpy.ndarray[dtype=float64] Current particle velocities (N,3) float64. |
get_volumes |
get_volumes(self) -> numpy.ndarray[dtype=float64] Per-particle Voronoi cell volume (N,) float64 (a copy). |
init |
init(self) -> None Build the first tessellation and forces from the particle state set above (checks that every per-particle array has the N of set_masses). |
internal_energy |
internal_energy(self) -> float Total internal (EOS) energy (scalar). |
kinetic_energy |
kinetic_energy(self) -> float Total kinetic energy ½ Σ m_i |
num_particles |
Particle count N. |
set_bulk_viscosities |
set_bulk_viscosities(self, viscosities: ndarray[dtype=float64, order='C']) -> None Per-particle bulk viscosity (N,) float64 (defaults to zero if unset; before init). |
set_domain |
set_domain(self, extent: collections.abc.Sequence[float], origin: collections.abc.Sequence[float] = [0.0, 0.0, 0.0], periodic: collections.abc.Sequence[bool] = [True, True, True]) -> None Set the periodic box before init: extent is the box SIZE (Lx, Ly, Lz). The suite-wide spelling (suite/docs/NAMING.md 1.1), the same call dem.Simulation.set_domain takes. origin must be (0, 0, 0) and periodic (True, True, True) — this engine's box is anchored at the origin and periodic on every axis; both are checked rather than ignored, so a caller who writes the suite-wide form gets an error naming the limitation. |
set_dt |
set_dt(self, dt: float) -> None Set the time step. The suite-wide way to configure a stepper (suite/docs/NAMING.md 1.5) — flow.Solver, dem.Simulation and peclet.core.amr.Flow all take set_dt. |
set_geometry |
set_geometry(self, node_ints: ndarray[dtype=int32, order='C'], node_reals: ndarray[dtype=float64, order='C'], root: int = 0, grad_h: float = 1e-05) -> None SDF solid walls for the fluid (same flat node encoding as Tessellation.set_geometry). The cells are clipped by the solid; the EOS pressure acts on the wall facets (the wall pushes back). Before init(). |
set_masses |
set_masses(self, masses: ndarray[dtype=float64, order='C']) -> None Particle masses (N,) float64, all > 0 (before init; sets N). |
set_positions |
set_positions(self, positions: ndarray[dtype=float64, order='C']) -> None Initial particle positions (N,3) float64 (before init). |
set_pressure |
set_pressure(self, pressure: float) -> None Equation-of-state pressure constant (the stiffness of the barotropic EOS; before init). |
set_velocities |
set_velocities(self, velocities: ndarray[dtype=float64, order='C']) -> None Initial particle velocities (N,3) float64 (before init; at rest if not set). |
set_viscosities |
set_viscosities(self, viscosities: ndarray[dtype=float64, order='C']) -> None Per-particle shear viscosity (N,) — enables the viscous Navier-Stokes term (before init). |
step |
step(self, num_steps: int) -> None Advance the velocity-Verlet dynamics by num_steps steps of the stored time step (set_dt); raises before init() and if no dt was set. |
time |
Current simulation time. |
FlowSolver¶
Static Navier–Stokes solver on the face mesh of a resident (built) Tessellation (Voronoi methods plan, track C). layout='collocated' (default): peclet.flow's approximate projection with the skew-corrected adjoint constraint pair — second order on unstructured Voronoi meshes; layout='covolume': the staggered covolume scheme (exact energy conservation, first order on unstructured meshes). Walls come from the tessellation's SDF geometry (no-slip unless set_wall_velocity). SSP-RK3 with a projection per stage; GraphAMG-PCG pressure solve. The mesh is frozen at construction — build a new FlowSolver after moving the seeds. Instruments: diagnostics.
| Method / property | Description |
|---|---|
diagnostics |
The diagnostics tier: set_skew_corrected(), set_wall_gradient_quadratic(). |
dt |
The stored time step (0 until set_dt). |
get_pressure |
get_pressure(self) -> numpy.ndarray[dtype=float64] Cell pressure (num_cells,) float64 (a copy). |
get_velocities |
get_velocities(self) -> numpy.ndarray[dtype=float64] Cell velocity (num_cells, 3) float64 (a copy; the covolume layout reconstructs it from the face fluxes). |
get_volumes |
get_volumes(self) -> numpy.ndarray[dtype=float64] Cell volume (num_cells,) float64 (a copy) — the face mesh's, i.e. the tessellation's. |
kinetic_energy |
kinetic_energy(self) -> float Total kinetic energy ½ Σ V_i |
layout |
The solver layout this instance was built with: 'collocated' or 'covolume'. |
max_divergence |
max_divergence(self) -> float Max over the cells of the discrete divergence of the transporting face flux — round-off after a projection. |
num_cells |
Number of cells of the face mesh (= the tessellation's particle count). |
num_faces |
Number of faces of the face mesh: interior faces first, then the wall faces. |
num_wall_faces |
Number of SDF wall faces (the trailing block of the faces); 0 without geometry. |
pressure_iterations |
PCG iteration count of the last pressure solve. |
set_body_force |
set_body_force(self, force: collections.abc.Sequence[float]) -> None Uniform body force per unit mass (fx, fy, fz) applied to every cell (a pressure gradient drive, gravity). |
set_dt |
set_dt(self, dt: float) -> None Set the time step (suite/docs/NAMING.md 1.5); step uses it. |
set_implicit_diffusion |
set_implicit_diffusion(self, on: bool) -> None Collocated only (raises on covolume): flow's semi-implicit step (explicit convection, backward-Euler viscous solve, approximate projection) — no diffusive dt limit, first order in time. |
set_pressure_tolerance |
set_pressure_tolerance(self, tol: float) -> None Relative residual at which the pressure PCG stops (default set by the solver). |
set_stokes |
set_stokes(self, on: bool) -> None Drop the convective term (creeping flow). |
set_velocity |
set_velocity(self, U: ndarray[dtype=float64, order='C']) -> None Initial cell velocity (num_cells, 3); projected once. |
set_wall_velocity |
set_wall_velocity(self, U: ndarray[dtype=float64, order='C']) -> None Prescribed velocity on the wall faces, (num_wall_faces, 3). |
step |
step(self, num_steps: int) -> None Advance num_steps steps of the stored time step (set_dt); raises if none was set. |
VoronoiHalo¶
Distributed (MPI) ghost-gather for the multi-rank Voronoi tessellation.
ORB block-decomposes a periodic box across MPI ranks and gathers, for each rank, every seed
within a cutoff rcut of its owned block (periodic images included). The recipe: select this
rank's owned seeds with owned_mask, gather(...) the owned+ghost set, tessellate it with the
single-rank Tessellation building only the first n_owned cells, and keep those cells — they
are bit-identical to a serial full-box tessellation (each owned cell has all its neighbours
present). rcut must exceed the largest owned-cell interaction distance (a few mean spacings).
For moving points use DistributedTessellation (the repair driver over this halo).
Auto-initialises MPI (MPI_COMM_WORLD). Drive it from mpi4py.
| Method / property | Description |
|---|---|
gather |
gather(self, positions: ndarray[dtype=float64, order='C'], gids: ndarray[dtype=int64, order='C'], rcut: float, weights: ndarray[dtype=float64, order='C'] |
num_ranks |
Number of MPI ranks. |
owned_mask |
owned_mask(self, positions: ndarray[dtype=float64, order='C']) -> numpy.ndarray[dtype=int32] Mask (N,) int32 over the given positions (N,3): 1 where this rank owns the point, else 0. |
owner_of |
owner_of(self, point: collections.abc.Sequence[float]) -> int Owning rank of a single point (x, y, z). |
rank |
This rank's MPI index. |
refresh_positions |
refresh_positions(self, positions: ndarray[dtype=float64, order='C']) -> numpy.ndarray[dtype=float64] Position-only halo refresh (Verlet fast path): re-forward the current owned positions (N,3) onto the topology of the last gather, returning the combined owned+ghost positions (M,3) in the same order as that gather (no re-decomposition / ghost re-selection). |
DistributedTessellation¶
Distributed (MPI) moving-point Voronoi tessellation: VoronoiHalo's ORB decomposition + ghost
gather composed with the device incremental repair under the distributed Verlet-skin
invariant (peclet::voro::mpi::DistributedMovingTessellation, gated by tests/kokkos_mpi at
np = 1, 2, 4). Each rank owns the seeds owned_mask selects; establish gathers the ghosts
within rcut and cold-builds; every step refreshes the ghost positions on the established
topology and repairs locally — until any rank's owned displacement since the last gather
exceeds skin/2, when ALL ranks re-gather and rebuild (a collective decision). The owned
cells [0, num_owned) equal a cold rebuild of the same combined positions to the certificate
tolerance. rcut, skin and tolerance are fractions of the mean spacing cbrt(V/N_global)
(defaults 3.5, 0.25, 0.0001). Collective calls: establish, step. Auto-initialises MPI
(MPI_COMM_WORLD). Instruments: diagnostics.
| Method / property | Description |
|---|---|
clear_geometry |
clear_geometry(self) -> None Drop the SDF geometry (before establish()). |
diagnostics |
The diagnostics tier: num_regathers, set_profile(). |
establish |
establish(self, positions: ndarray[dtype=float64, order='C'], gids: ndarray[dtype=int64, order='C'], weights: ndarray[dtype=float64, order='C'] |
get_combined_gids |
get_combined_gids(self) -> numpy.ndarray[dtype=int64] Global ids (num_combined,) int64 of the owned + ghost seeds after the last gather (owned first, in establish() order). |
get_neighbor_counts |
get_neighbor_counts(self) -> numpy.ndarray[dtype=int32] Owned-cell neighbour counts (num_owned,) int32 (a copy). |
get_volumes |
get_volumes(self) -> numpy.ndarray[dtype=float64] Owned-cell volumes (num_owned,) float64 (a copy), in establish() order. |
get_wall_counts |
get_wall_counts(self) -> numpy.ndarray[dtype=int32] Owned-cell resident SDF wall plane counts (num_owned,) int32 (a copy). |
num_combined |
Owned + ghost seed count of this rank's tessellation after the last gather. |
num_owned |
This rank's owned cell count. |
num_ranks |
Number of MPI ranks. |
owned_mask |
owned_mask(self, positions: ndarray[dtype=float64, order='C']) -> numpy.ndarray[dtype=int32] Mask (N,) int32 over the given positions (N,3): 1 where this rank owns the point. |
rank |
This rank's MPI index. |
set_geometry |
set_geometry(self, node_ints: ndarray[dtype=int32, order='C'], node_reals: ndarray[dtype=float64, order='C'], root: int = 0, grad_h: float = 1e-05) -> None Replicated SDF solid (every rank passes the same scene), as Tessellation.set_geometry. Before establish(). |
set_wall_mode |
set_wall_mode(self, mode: str, skin_frac: float = 0.0) -> None Wall re-gather policy, as Tessellation.set_wall_mode: mode one of 'exact', 'skin'. Before establish(). |
step |
step(self, positions: ndarray[dtype=float64, order='C']) -> dict Collective: advance to the new owned positions (N,3, same N and ownership as establish). Returns the Tessellation.step stats dict plus 'regathered' (True when this step took the re-gather + cold-rebuild path; the repair stats are then zero). |
OptimizeResult¶
Result of optimize_volume_mesh / pore_mesh.optimize_pore_mesh.
| Method / property | Description |
|---|---|
converged |
True if the gradient fell below tol. |
iters |
Gauss-Newton / descent iterations run. |
max_vol_err |
max_i |
mean_vol_err |
mean_i |
num_empty |
Seeds whose cell is empty at the returned seeds (0 for a valid mesh). |
positions |
The optimised seeds (N,3) float64. |
weights |
The optimised power weights (N,) float64, or None when use_weights=False. |
InterfaceResult¶
Result of minimize_interface.
| Method / property | Description |
|---|---|
converged |
True if the gradient fell below tol. |
energy |
Final interfacial energy E = sum sigma A_ij over faces between different types. |
energy_ratio |
energy / the energy of the input seeds. |
iters |
Descent iterations run. |
positions |
The minimised seeds (N,3) float64. |
Module attributes¶
| Attribute | Value in this build |
|---|---|
execution_space |
'OpenMP' |
finalize¶
finalize() -> None
Release every live object and zero-copy array of this module, then Kokkos::finalize() (deterministic teardown; also run automatically at interpreter exit). Idempotent. After it, the module's solver objects and *_view arrays must not be used.
minimize_interface¶
minimize_interface(positions: ndarray[dtype=float64, order='C'], types: ndarray[dtype=int32, order='C'], extent: collections.abc.Sequence[float], *, sigma: float = 1.0, search_window: int = 5, max_iter: int = 60, tol: float = 1e-09) -> peclet.voro._voro.InterfaceResult
Surface-Evolver-style interfacial-tension minimiser: move seeds (N,3) on the periodic box
`extent` to minimise the total area of faces between cells of different integer type (N,),
E = sum sigma A_ij (sigma default 1). Steepest descent with a trust-region line search on
the (non-smooth) interfacial energy; search_window / max_iter / tol default to 5 / 60 / 1e-09.
Returns an InterfaceResult (positions, energy, energy_ratio = final/initial, iters, converged).
optimize_volume_mesh¶
optimize_volume_mesh(positions: ndarray[dtype=float64, order='C'], target_volumes: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], *, search_window: int = 5, max_iter: int = 60, tol: float = 1e-09, cg_iters: int = 300, use_weights: bool = False, method: str = 'jacobi') -> peclet.voro._voro.OptimizeResult
Move seeds (N,3) — and optionally the power weights — to minimise sum (V_i / V_ref,i - 1)^2 by
damped Gauss-Newton (Newton-Raphson + CG) on the periodic box `extent` (Lx, Ly, Lz).
target_volumes (N,) are the per-cell reference volumes V_ref (renormalised to the box
volume). method: the CG preconditioner, one of 'jacobi', 'colored_gs', 'graphamg', 'steepest' (default 'jacobi'; 'graphamg'
is the O(N) choice at large N, 'steepest' is plain descent). search_window (default 5), max_iter (60), tol (1e-09)
and cg_iters (300) are peclet.voro.defaults. Returns an OptimizeResult (positions, weights, iters,
max_vol_err, mean_vol_err, converged, num_empty). Pure Voronoi (use_weights=False)
reaches equal/graded volumes well; weights add fuller volume control but are limited by
the periodic tessellation's ~1% min-image floor.
peclet.voro._voro¶
peclet.voro (device/Kokkos): moving-particle Voronoi tessellation and dynamics.
Classes: Tessellation (cold build + incremental repair, volumes, neighbour counts, energy
forces), FlowSolver (static Navier-Stokes on the face mesh), Simulation (moving-cell
compressible-Euler / Navier-Stokes fluid); functions optimize_volume_mesh, minimize_interface;
the pore-space family under peclet.voro.pore_mesh; VoronoiHalo and DistributedTessellation
when built with MPI. Every instrument lives on the object's diagnostics. Arrays are NumPy:
positions/velocities (N,3) float64, scalars (N,). The backend (Serial/OpenMP/CUDA/HIP) is
fixed at build time; see peclet.voro.execution_space. peclet.voro.defaults lists the named
defaults the engine is driven with.
TessellationDiagnostics¶
Instruments and ablation switches of a Tessellation (reached as t.diagnostics).
| Method / property | Description |
|---|---|
build_report |
build_report(self) -> dict Validity counts of the last build: {'buried', 'reach_exceeded', 'empty', 'overflow', 'incomplete'} — all zero for a guaranteed-exact partition (build() already warns, or raises with strict=True, when they are not) — and 'over_buffer_rebuilds', the number of times the build's facet/edge over-buffer estimate was exceeded and the build pass re-run at the exact demand (0 normally; each one doubles that build's cost). |
set_gate |
set_gate(self, on: bool) -> None Ablation: the adaptive gate (default True) that routes high-churn steps straight to a full rebuild — the 'never much slower than a cold build' guard. Takes effect at the next build(). |
set_local_certificate |
set_local_certificate(self, on: bool) -> None Ablation: the cheap O(nt) Lawson local certificate (default True) vs the brute O(nt*np) form for detecting which cells changed. Both are complete; local is faster. Takes effect at the next build(). |
set_profile |
set_profile(self, on: bool = True) -> None Print the cold build's timing (grid / build / CSR), the worklist size, the over-buffer rebuilds and the max facets per cell on stderr (default off). Takes effect at the next build(). |
SimulationDiagnostics¶
Performance-path switches of a Simulation (reached as s.diagnostics).
| Method / property | Description |
|---|---|
set_profile |
set_profile(self, on: bool = True) -> None Print each cold build's timing and over-buffer report on stderr (default off). |
set_repair |
set_repair(self, on: bool = True) -> None Opt-in (default off): use the incremental moving-point repair + reeval-published force geometry each step instead of a full rebuild. Before init(). |
FlowSolverDiagnostics¶
Ablation switches of a FlowSolver (reached as f.diagnostics): the measured-worse alternatives kept for comparison.
| Method / property | Description |
|---|---|
set_skew_corrected |
set_skew_corrected(self, on: bool) -> None Collocated only: the centroid-consistent constraint pair (default True; the plain pair drops to first order on skewed meshes — README, rung C2b). |
set_wall_gradient_quadratic |
set_wall_gradient_quadratic(self, on: bool) -> None Wall viscous flux from the wall-anchored least-squares quadratic (default True; exact for Poiseuille) instead of the two-point (U_i - U_wall)/h_A (-13 % on the sphere drag). |
DistributedTessellationDiagnostics¶
Instruments of a DistributedTessellation (reached as d.diagnostics).
| Method / property | Description |
|---|---|
num_regathers |
Number of collective re-gather + cold-rebuild events since construction (establish counts as one). |
set_profile |
set_profile(self, on: bool = True) -> None Print each rank's cold-build timing and over-buffer report on stderr (default off). |
Module attributes¶
| Attribute | Value in this build |
|---|---|
execution_space |
'OpenMP' |
finalize¶
finalize() -> None
Release every live object and zero-copy array of this module, then Kokkos::finalize() (deterministic teardown; also run automatically at interpreter exit). Idempotent. After it, the module's solver objects and *_view arrays must not be used.
minimize_interface¶
minimize_interface(positions: ndarray[dtype=float64, order='C'], types: ndarray[dtype=int32, order='C'], extent: collections.abc.Sequence[float], *, sigma: float = 1.0, search_window: int = 5, max_iter: int = 60, tol: float = 1e-09) -> peclet.voro._voro.InterfaceResult
Surface-Evolver-style interfacial-tension minimiser: move seeds (N,3) on the periodic box
`extent` to minimise the total area of faces between cells of different integer type (N,),
E = sum sigma A_ij (sigma default 1). Steepest descent with a trust-region line search on
the (non-smooth) interfacial energy; search_window / max_iter / tol default to 5 / 60 / 1e-09.
Returns an InterfaceResult (positions, energy, energy_ratio = final/initial, iters, converged).
optimize_pore_mesh¶
optimize_pore_mesh(positions: ndarray[dtype=float64, order='C'], target_volumes: ndarray[dtype=float64, order='C'], sphere_centers: ndarray[dtype=float64, order='C'], sphere_radii: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], *, search_window: int = 6, max_iter: int = 80, tol: float = 1e-09, cg_iters: int = 400, method: str = 'graphamg', mu_barrier: float = 0.0, free_energy: bool = False) -> peclet.voro._voro.OptimizeResult
Relax interstitial seeds (N,3) so their SDF-clipped Voronoi cell volumes approach the per-cell
target_volumes (N,), with the sphere packing (sphere_centers (M,3), sphere_radii (M,)) as
periodic walls in the cubic box `extent` (Lx == Ly == Lz). method: one of 'jacobi', 'colored_gs', 'graphamg', 'steepest' (default
'graphamg'; 'steepest' is plain descent). free_energy=True uses E = -sum V_ref log V (pressure
V_ref/V, resists collapse); mu_barrier > 0 adds a log-barrier that decays by 0.7 per iteration.
search_window / max_iter / tol / cg_iters default to 6 / 80 / 1e-09 / 400. Returns an
OptimizeResult. Experimental (pore-space meshing; see the pore-mesh-voronoi example).
optimize_volume_mesh¶
optimize_volume_mesh(positions: ndarray[dtype=float64, order='C'], target_volumes: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], *, search_window: int = 5, max_iter: int = 60, tol: float = 1e-09, cg_iters: int = 300, use_weights: bool = False, method: str = 'jacobi') -> peclet.voro._voro.OptimizeResult
Move seeds (N,3) — and optionally the power weights — to minimise sum (V_i / V_ref,i - 1)^2 by
damped Gauss-Newton (Newton-Raphson + CG) on the periodic box `extent` (Lx, Ly, Lz).
target_volumes (N,) are the per-cell reference volumes V_ref (renormalised to the box
volume). method: the CG preconditioner, one of 'jacobi', 'colored_gs', 'graphamg', 'steepest' (default 'jacobi'; 'graphamg'
is the O(N) choice at large N, 'steepest' is plain descent). search_window (default 5), max_iter (60), tol (1e-09)
and cg_iters (300) are peclet.voro.defaults. Returns an OptimizeResult (positions, weights, iters,
max_vol_err, mean_vol_err, converged, num_empty). Pure Voronoi (use_weights=False)
reaches equal/graded volumes well; weights add fuller volume control but are limited by
the periodic tessellation's ~1% min-image floor.
sdf_voronoi_cells¶
sdf_voronoi_cells(positions: ndarray[dtype=float64, order='C'], sphere_centers: ndarray[dtype=float64, order='C'], sphere_radii: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], *, search_window: int = 6) -> dict
Reconstruct the SDF-clipped interstitial Voronoi cells (cubic periodic box `extent`, the
spheres as walls) on the device — the tessellator's own gather, one thread per cell — and
return their polyhedra as flat arrays (VTK_POLYHEDRON layout) in seed order: 'points' (Np,3),
'faces' + 'face_offsets' (per-cell face lists, global point ids, each face CCW about its
outward normal), 'volume' (Nc,), 'boundary' (Nc, 1 where the cell touches a sphere wall),
'seed' (Nc,). Seeds inside a sphere have no cell; 'num_overflow' counts cells skipped for
exceeding the cell capacity (peclet.voro.defaults max_planes / max_triangles) and 'num_incomplete' the cells whose
gather window (search_window grid blocks per axis, default 6) did not close — raise
search_window if it is not 0.
sdf_voronoi_section¶
sdf_voronoi_section(positions: ndarray[dtype=float64, order='C'], sphere_centers: ndarray[dtype=float64, order='C'], sphere_radii: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], point: collections.abc.Sequence[float], normal: collections.abc.Sequence[float], *, search_window: int = 6) -> dict
Cross-section of the SDF-clipped interstitial Voronoi mesh (cubic periodic box `extent`) by
the plane through `point` with `normal`, on the device: every cell cut directly
(ConvexCell::sectionPolygon, from the dual edges, so it tiles the plane exactly where a
face-by-face slice drops facets). Returns 'verts' (Nv,3, world coords, all on the plane, CCW
about the normal) + 'offsets' (Npoly+1, per-polygon vertex ranges) + 'volume' (Npoly, the 3-D
cell volume) + 'seed' (Npoly, the seed index), in seed order, plus 'num_overflow' /
'num_incomplete' as in sdf_voronoi_cells (search_window default 6). For a z=z0 slice pass
point=(0,0,z0), normal=(0,0,1) and plot verts[:, :2].
peclet.voro.pore_mesh¶
peclet.voro.pore_mesh — the SDF-walled pore-space (interstitial Voronoi) family.
The wall geometry is a periodic packing of spheres (sphere_centers (M,3), sphere_radii (M,))
in a CUBIC box extent = (L, L, L); every function takes the suite-wide extent triple and
checks it is cubic. Bound in _voro and re-exported here: :func:optimize_pore_mesh (the
position-only Gauss–Newton relaxation toward per-cell target volumes), :func:sdf_voronoi_cells
(the clipped polyhedra) and :func:sdf_voronoi_section (a plane cross-section). Implemented here:
:func:redistribute_pore_mesh, the topological split / merge / relax loop that drives a seeding to
a graded target (rung B2 of the Voronoi methods plan).
RedistributeResult¶
Result of :func:redistribute_pore_mesh.
optimize_pore_mesh¶
optimize_pore_mesh(positions: ndarray[dtype=float64, order='C'], target_volumes: ndarray[dtype=float64, order='C'], sphere_centers: ndarray[dtype=float64, order='C'], sphere_radii: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], *, search_window: int = 6, max_iter: int = 80, tol: float = 1e-09, cg_iters: int = 400, method: str = 'graphamg', mu_barrier: float = 0.0, free_energy: bool = False) -> peclet.voro._voro.OptimizeResult
Relax interstitial seeds (N,3) so their SDF-clipped Voronoi cell volumes approach the per-cell
target_volumes (N,), with the sphere packing (sphere_centers (M,3), sphere_radii (M,)) as
periodic walls in the cubic box `extent` (Lx == Ly == Lz). method: one of 'jacobi', 'colored_gs', 'graphamg', 'steepest' (default
'graphamg'; 'steepest' is plain descent). free_energy=True uses E = -sum V_ref log V (pressure
V_ref/V, resists collapse); mu_barrier > 0 adds a log-barrier that decays by 0.7 per iteration.
search_window / max_iter / tol / cg_iters default to 6 / 80 / 1e-09 / 400. Returns an
OptimizeResult. Experimental (pore-space meshing; see the pore-mesh-voronoi example).
redistribute_pore_mesh¶
Global redistribution of pore-space seeds toward the graded target volume
V_ref = s(φ)³, s(φ) = clip(φ, s_lo, s_hi) (φ = distance to the nearest sphere wall), by
TOPOLOGICAL moves the position-only optimiser cannot make (it cannot move seeds between
pores — rung B2 of the Voronoi methods plan):
* split: a cell with V > β V_ref gets a second seed (offset from its centroid by ~s(φ)),
* merge: a seed whose cell has V < V_ref/β, or no cell at all (dead / empty / buried), is
removed — its neighbours absorb the volume,
* relax: `lloyd_steps` Lloyd sweeps (seed → clipped-cell centroid, kept off the wall),
repeated until max |V/V_ref − 1| < tol (V_ref renormalised so Σ V_ref = the fluid volume) or
`max_rounds`; `max_change` caps the fraction of seeds changed per round. With `polish` the
position-only optimiser (:func:`optimize_pore_mesh`, GraphAMG Gauss–Newton) finishes from the
now-feasible start. Returns a :class:`RedistributeResult`.
The sphere packing is the periodic wall geometry (sphere_centers (M,3), sphere_radii (M,)) in
the cubic box `extent` = (L, L, L).
sdf_voronoi_cells¶
sdf_voronoi_cells(positions: ndarray[dtype=float64, order='C'], sphere_centers: ndarray[dtype=float64, order='C'], sphere_radii: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], *, search_window: int = 6) -> dict
Reconstruct the SDF-clipped interstitial Voronoi cells (cubic periodic box `extent`, the
spheres as walls) on the device — the tessellator's own gather, one thread per cell — and
return their polyhedra as flat arrays (VTK_POLYHEDRON layout) in seed order: 'points' (Np,3),
'faces' + 'face_offsets' (per-cell face lists, global point ids, each face CCW about its
outward normal), 'volume' (Nc,), 'boundary' (Nc, 1 where the cell touches a sphere wall),
'seed' (Nc,). Seeds inside a sphere have no cell; 'num_overflow' counts cells skipped for
exceeding the cell capacity (peclet.voro.defaults max_planes / max_triangles) and 'num_incomplete' the cells whose
gather window (search_window grid blocks per axis, default 6) did not close — raise
search_window if it is not 0.
sdf_voronoi_section¶
sdf_voronoi_section(positions: ndarray[dtype=float64, order='C'], sphere_centers: ndarray[dtype=float64, order='C'], sphere_radii: ndarray[dtype=float64, order='C'], extent: collections.abc.Sequence[float], point: collections.abc.Sequence[float], normal: collections.abc.Sequence[float], *, search_window: int = 6) -> dict
Cross-section of the SDF-clipped interstitial Voronoi mesh (cubic periodic box `extent`) by
the plane through `point` with `normal`, on the device: every cell cut directly
(ConvexCell::sectionPolygon, from the dual edges, so it tiles the plane exactly where a
face-by-face slice drops facets). Returns 'verts' (Nv,3, world coords, all on the plane, CCW
about the normal) + 'offsets' (Npoly+1, per-polygon vertex ranges) + 'volume' (Npoly, the 3-D
cell volume) + 'seed' (Npoly, the seed index), in seed order, plus 'num_overflow' /
'num_incomplete' as in sdf_voronoi_cells (search_window default 6). For a z=z0 slice pass
point=(0,0,z0), normal=(0,0,1) and plot verts[:, :2].
sphere_union_scene¶
Flat scene encoding ``(node_ints (n,3) int32, node_reals (n,16) float64, root)`` of the CSG
union of solid spheres — pass it to :meth:`Tessellation.set_geometry` as
``t.set_geometry(*sphere_union_scene(centers, radii))``. ``centers`` (M,3), ``radii`` (M,).
sphere_union_sdf¶
Signed distance of ``points`` (N,3) to the periodic union of spheres (``centers`` (M,3),
``radii`` (M,)) in the box ``extent`` (Lx, Ly, Lz): ``min_i(|x - c_i|_minimage - r_i)``, < 0
inside a sphere, > 0 in the fluid. The numpy twin of the scene from
:func:`sphere_union_scene`.
peclet.voro.scenes¶
peclet.voro.scenes — small SDF scene helpers for the tessellator's set_geometry.
The tessellator takes a core shape scene in the flat node encoding (node_ints (n,3) int32,
node_reals (n,16) float64, a root index) — what :meth:peclet.geom.SceneBuilder.encode
returns. These helpers build the two encodings the pore-space examples need without importing
peclet.core: the CSG union of solid spheres (a packed bed as walls) and its numpy evaluation.
sphere_union_scene¶
Flat scene encoding ``(node_ints (n,3) int32, node_reals (n,16) float64, root)`` of the CSG
union of solid spheres — pass it to :meth:`Tessellation.set_geometry` as
``t.set_geometry(*sphere_union_scene(centers, radii))``. ``centers`` (M,3), ``radii`` (M,).
sphere_union_sdf¶
Signed distance of ``points`` (N,3) to the periodic union of spheres (``centers`` (M,3),
``radii`` (M,)) in the box ``extent`` (Lx, Ly, Lz): ``min_i(|x - c_i|_minimage - r_i)``, < 0
inside a sphere, > 0 in the fluid. The numpy twin of the scene from
:func:`sphere_union_scene`.