|
peclet.voro 1.0.4
Device-native moving-particle Voronoi dynamics
|
Device-native Voronoi tessellation, geometry and finite-volume physics. More...
Namespaces | |
| namespace | detail |
| namespace | energy |
| namespace | fv |
| namespace | mpi |
| namespace | physics |
| namespace | pybind |
Classes | |
| struct | AuxMaps |
| struct | BuildReport |
| A2a validity diagnostics of a cold (re)build (counts over the maintained cells). More... | |
| struct | CellBuilder |
| struct | ConvexCell |
| struct | HostTessellation |
| Host-side CSR buffers — the conversion target and the round-trip oracle. More... | |
| struct | InterfaceResult |
| struct | Invariants |
| Per-step invariant residuals (all should be ~0 / ~machine-precision for a correct tessellation). More... | |
| struct | MovingTessellation |
| struct | NoSdf |
| Sentinel "no geometry" provider — the default; the clip stage is skipped. More... | |
| struct | OracleDiff |
| Result of comparing the current updated state against a fresh cold-build oracle. More... | |
| struct | OtResult |
| struct | PoreCellsResult |
| The clipped polyhedra, packed as flat arrays in seed order (VTK_POLYHEDRON layout). More... | |
| struct | PoreSectionResult |
| struct | Power |
| struct | RepairStats |
| Per-step repair telemetry. More... | |
| struct | SdfBox |
| struct | SdfGrid |
| struct | SdfHollowCylinder |
| struct | SdfScene |
| struct | SdfSphere |
| struct | SdfSpheres |
| struct | SubsetGatherResult |
| struct | TangentOnly |
| struct | TessellationView |
| struct | TessellatorResult |
| struct | TessGrid |
| struct | TopologyStore |
| struct | VerletSkin |
| struct | Voronoi |
| struct | WallStore |
| struct | WorklistCache |
Typedefs | |
| using | gid_t = std::int32_t |
Enumerations | |
| enum class | Precond { Jacobi , ColoredGS , GraphAMG , SteepestDescent } |
| enum | StatusBit { kOk = 0 , kOverflow = 1 , kEmpty = 2 , kIncomplete = 4 , kNegOffset = 8 , kBuried = 16 , kReachExceeded = 32 } |
| Per-cell status bits written by the build pass. More... | |
| enum | SkinTrigger : int { kSkinNone = 0 , kSkinMover = 1 } |
Functions | |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Policy = Voronoi> | |
| KOKKOS_INLINE_FUNCTION void | buildConvexCell (ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real L[3], const Real *relx, const Real *rely, const Real *relz, const int *ids, int nNbr, Real wSelf=Real(0), const Real *weights=nullptr) |
| template<class Real > | |
| Invariants | checkInvariants (const TessellationView< Real > &view, const AuxMaps< Real > &aux, double boxVolume) |
| template<class Real > | |
| void | compareVolumes (const Kokkos::View< Real *, peclet::core::MemSpace > &volCurrent, const TessellationView< Real > &oracle, OracleDiff &out) |
| Compare a current per-cell volume array against the oracle view's volumes (cell i == seed i). | |
| template<class Real > | |
| void | compareNeighbours (const Kokkos::View< int *, peclet::core::MemSpace > &storeNp, const Kokkos::View< int *, peclet::core::MemSpace > &storeNt, const Kokkos::View< int *, peclet::core::MemSpace > &storePnbr, const Kokkos::View< unsigned *, peclet::core::MemSpace > &storeTri, int MAXP, int MAXT, const TessellationView< Real > &oracle, OracleDiff &out) |
| template<class Real , bool Weighted = false, class Sdf = NoSdf> | |
| OtResult | meshVolumeOptimize (std::vector< Real > &pos, std::vector< Real > &weight, const std::vector< Real > &vsetIn, const Real L[3], int N, int sw, const Sdf &sdf, int maxNewton, Real tol, int cgIters=kOptimizerCgIters, Precond prec=Precond::Jacobi, bool verbose=false, Real muBarrier=0, Real muDecay=(Real) kBarrierDecay, bool freeEnergy=false) |
| template<class Real , class Sdf = NoSdf> | |
| InterfaceResult | interfaceMinimize (std::vector< Real > &pos, const std::vector< int > &type, double sigma, const Real L[3], int N, int sw, const Sdf &sdf, int maxIter, Real tol, bool verbose=false) |
| template<class Real , class Sdf = NoSdf> | |
| OtResult | meshVolumeOptimizeDevice (std::vector< Real > &posHost, const std::vector< Real > &vsetIn, const Real L[3], int N, int sw, const Sdf &sdf, int maxNewton, Real tol, int cgIters=kOptimizerCgIters, bool verbose=false) |
| template<class Real , class Sdf = NoSdf> | |
| OtResult | otVolumeControl (std::vector< Real > &pos, std::vector< Real > &weight, const std::vector< Real > &vsetIn, const Real L[3], int N, int sw, const Sdf &sdf, int maxNewton, Real tol, Real reg=Real(1e-6), Real damp=Real(1), bool verbose=false) |
| template<class Policy , class Cell , class Real > | |
| KOKKOS_INLINE_FUNCTION void | chainToDofs (const Cell &c, const Real seed[3], const Real *pos, Real wSelf, const Real *weight, Real L, const Real *gx, const Real *gy, const Real *gz, Real fSelf[3], Real &fwSelf, Real *fnx, Real *fny, Real *fnz, Real *fwn) |
| template<class Real , class Sdf , int MAXP = kMaxPlanes, int MAXT = kMaxTriangles> | |
| PoreCellsResult< Real > | buildPoreCells (const Kokkos::View< Real *, peclet::core::MemSpace > &posFlat, int N, const Real L[3], const Sdf &sdf, int sw=kSearchWindow) |
| template<class Real , class Sdf , int MAXP = kMaxPlanes, int MAXT = kMaxTriangles> | |
| PoreSectionResult< Real > | buildPoreSection (const Kokkos::View< Real *, peclet::core::MemSpace > &posFlat, int N, const Real L[3], const Sdf &sdf, const Real point[3], const Real normal[3], int sw=kSearchWindow) |
| template<class Real , int MAXP, int MAXT> | |
| TessellationView< Real > | reevalPublish (const TopologyStore< MAXP, MAXT > &store, const Kokkos::View< Real *, peclet::core::MemSpace > &pos, const Kokkos::View< Real *, peclet::core::MemSpace > &vol, int N, const Real L[3], WallStore< Real > wall={}, Kokkos::View< Real *, peclet::core::MemSpace > xRef={}, bool withAreaGrad=false, bool withMoments=false) |
| template<class Real , class Sdf > | |
| KOKKOS_INLINE_FUNCTION void | sdfGradient (const Sdf &s, Real x, Real y, Real z, Real g[3]) |
| Central-difference gradient of any provider with eval() (matches peclet::core::geom::gradient). | |
| template<class Real , class Sdf > | |
| KOKKOS_INLINE_FUNCTION void | sdfHessian (const Sdf &s, Real x, Real y, Real z, Real H[3][3]) |
| template<class Real , class Sdf > | |
| KOKKOS_INLINE_FUNCTION void | sdfWallChain (const Sdf &sdf, Real x, Real y, Real z, const double gw[3], double fSelf[3]) |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Sdf > | |
| KOKKOS_INLINE_FUNCTION void | addSdfWallForce (const ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf, const Real *gx, const Real *gy, const Real *gz, Real fSelf[3]) |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Sdf > | |
| KOKKOS_INLINE_FUNCTION int | sdfSagittaShifts (const ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf, const int *planes, const Real *tangency, int nPlanes, Real *delta) |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Sdf > | |
| KOKKOS_INLINE_FUNCTION bool | sdfCutPlane (const ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf, const Real probe[3], Real radius, Real pv[3], Real &off, Real surf[3]) |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Sdf > | |
| KOKKOS_INLINE_FUNCTION bool | sdfWouldClip (const ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf) |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Sdf > | |
| KOKKOS_INLINE_FUNCTION bool | clipCellAgainstSdf (ConvexCell< Real, MAXP, MAXT, TrackAdj > &c, const Real seed[3], const Sdf &sdf) |
| template<class Real , int MAXP, int MAXT, bool TrackAdj, class Sdf > | |
| KOKKOS_INLINE_FUNCTION void | sdfWallFD (const ConvexCell< Real, MAXP, MAXT, TrackAdj > &unclipped, const Real seed[3], const Sdf &sdf, Real h, Real dV[3], Real dA[3]) |
| template<class Real , bool Weighted = false, bool TrackAdj = false, class Sdf = NoSdf> | |
| SubsetGatherResult< Real > | subsetGather (const TessGrid< Real > &grid, const Kokkos::View< int *, peclet::core::MemSpace > &indices, int nSubset, const Kokkos::View< int *, peclet::core::MemSpace > &outNp, const Kokkos::View< int *, peclet::core::MemSpace > &outNt, const Kokkos::View< int *, peclet::core::MemSpace > &outPnbr, const Kokkos::View< unsigned *, peclet::core::MemSpace > &outTri, const Kokkos::View< Real *, peclet::core::MemSpace > &cellVol, const Kokkos::View< unsigned char *, peclet::core::MemSpace > &outPoke4={}, Sdf sdf={}, bool withForceGeom=false, WallStore< Real > outWall={}, Kokkos::View< int *, peclet::core::MemSpace > outNear={}, Kokkos::View< int *, peclet::core::MemSpace > outNearCnt={}, int nearCap=0, Real nearMargin=Real(0)) |
| KOKKOS_INLINE_FUNCTION int | morton3 (int x, int y, int z) |
| template<class Real , bool Weighted> | |
| TessGrid< Real > | buildTessGrid (const Kokkos::View< Real *, peclet::core::MemSpace > &posFlat, const Kokkos::View< Real *, peclet::core::MemSpace > &weight, int N, const Real L[3], int sw=kSearchWindow, int densityCount=-1, Kokkos::View< long *, peclet::core::MemSpace > gid={}, WorklistCache< Real > *wlc=nullptr) |
| gid_t | toGid (std::uint32_t id) |
| template<class Real > | |
| std::vector< int > | buildReciprocalMap (const HostTessellation< Real > &t) |
| template<class Real > | |
| TessellationView< Real > | upload (const HostTessellation< Real > &h) |
| Upload a HostTessellation to device Views. | |
| template<class Cell , int MAXF> | |
| KOKKOS_INLINE_FUNCTION int | areaGradEnumerate (const Cell &c, const int *faces, int nf, unsigned char *part, unsigned char *pcnt, bool &full) |
| template<class Cell , int MAXF, class IView , class RView > | |
| KOKKOS_INLINE_FUNCTION void | areaGradFill (const Cell &c, const int *faces, int nf, const unsigned char *part, const unsigned char *pcnt, int base, int ebase, const IView &oEdgeOff, const IView &oEdgeCnt, const IView &oEdgeFacet, const RView &oEdgeGrad, const RView &oEdgeLen) |
| template<class Real , bool Weighted, class Sdf = NoSdf, int MAXP = kMaxPlanes, int MAXT = kMaxTriangles> | |
| TessellatorResult< Real > | buildTessellation (const Kokkos::View< Real *, peclet::core::MemSpace > &posFlat, const Kokkos::View< Real *, peclet::core::MemSpace > &weight, int N, const Real L[3], int sw=kSearchWindow, int densityCount=-1, Kokkos::View< long *, peclet::core::MemSpace > gid={}, Sdf sdf={}, bool withForceGeom=true, int nBuild=-1, Kokkos::View< int *, peclet::core::MemSpace > outNp={}, Kokkos::View< int *, peclet::core::MemSpace > outNt={}, Kokkos::View< int *, peclet::core::MemSpace > outPnbr={}, Kokkos::View< unsigned *, peclet::core::MemSpace > outTri={}, Kokkos::View< int *, peclet::core::MemSpace > outCand={}, Kokkos::View< int *, peclet::core::MemSpace > outCandCnt={}, int candCap=0, WorklistCache< Real > *wlc=nullptr, WallStore< Real > outWall={}, bool withAreaGrad=false, Kokkos::View< int *, peclet::core::MemSpace > outNear={}, Kokkos::View< int *, peclet::core::MemSpace > outNearCnt={}, int nearCap=0, Real nearMargin=Real(0), bool withWallFD=false, bool withMoments=false, bool profile=false) |
| template<class Real > | |
| AuxMaps< Real > | buildAuxMaps (const TessellationView< Real > &view) |
| Build {recip, cellOfFacet} on device from a published view (dense single-domain). | |
| template<class Real > | |
| int | flagSkinMovers (const Kokkos::View< Real *, peclet::core::MemSpace > &pos, const Kokkos::View< Real *, peclet::core::MemSpace > &xRef, Real skin, const Real L[3], const Kokkos::View< int *, peclet::core::MemSpace > &outFlags) |
| template<class Real > | |
| Real | maxDisplacement (const Kokkos::View< Real *, peclet::core::MemSpace > &pos, const Kokkos::View< Real *, peclet::core::MemSpace > &xRef, const Real L[3]) |
Variables | |
| constexpr int | kMaxPlanes = 64 |
| constexpr int | kMaxTriangles = 112 |
| constexpr int | kPoreMaxPlanes = 128 |
| constexpr int | kPoreMaxTriangles = 256 |
| constexpr int | kSearchWindow = 4 |
| constexpr double | kCertificateTolerance = 1e-4 |
| constexpr double | kSkin = 0.25 |
| constexpr int | kOptimizerCgIters = 300 |
| constexpr double | kBarrierDecay = 0.7 |
| constexpr int | kBoundaryFacet = -2 |
| constexpr int | kMaxWallPlanes = 24 |
| constexpr int | kWlOffBias = 128 |
Device-native Voronoi tessellation, geometry and finite-volume physics.
| using peclet::voro::gid_t = typedef std::int32_t |
Seed/neighbour identifier in the published view. Signed so the unsigned sentinels map cleanly to negatives: 0xFFFFFFFF -> -1 (no neighbour), 0xFFFFFFFE -> -2 (boundary). Consumers treat facetNbr(f) < 0 as a boundary facet.
|
strong |
| enum peclet::voro::SkinTrigger : int |
Per-particle rebuild-trigger bits. Extensible: Phase 1 only ever sets kSkinMover; the deferred boundary trigger (Risk 1d) will add kSkinBoundary so a status-change near an SDF wall feeds the same Pass-1 set. Stored as int so the flag array doubles as a stream-compaction mask.
| Enumerator | |
|---|---|
| kSkinNone | |
| kSkinMover | |
| KOKKOS_INLINE_FUNCTION void peclet::voro::addSdfWallForce | ( | const ConvexCell< Real, MAXP, MAXT, TrackAdj > & | c, |
| const Real | seed[3], | ||
| const Sdf & | sdf, | ||
| const Real * | gx, | ||
| const Real * | gy, | ||
| const Real * | gz, | ||
| Real | fSelf[3] | ||
| ) |
Differentiable SDF wall force (Effort 2, Option A — the seed-foot model). A wall facet (pnbr == kBoundaryFacet) is modelled as the tangent plane at the seed's foot point on sdf=0, so its seed-relative foot-point normal is n_wall(s) = −φ(s) û(s), û = ∇φ/|∇φ|. Its Jacobian is J_wall = ∂n_wall/∂s = −|∇φ| û ûᵀ − (φ/|∇φ|)(I − û ûᵀ) H, H = ∇²φ, so the wall's contribution to dGeom/dseed is J_wallᵀ g summed over the cell's wall facets (g = dGeom/dn_k from geomVolumeGrad). EXACT for a flat wall (φ linear ⇒ H=0, one facet); first-order for a curved wall (the clip approximates the curve by several vertex-anchored tangent facets, modelled here as one effective seed-foot plane). Call AFTER chainToDofs<Policy> (which zeroes pnbr<0 planes); this adds the wall self-force into fSelf. No-op for NoSdf.
| KOKKOS_INLINE_FUNCTION int peclet::voro::areaGradEnumerate | ( | const Cell & | c, |
| const int * | faces, | ||
| int | nf, | ||
| unsigned char * | part, | ||
| unsigned char * | pcnt, | ||
| bool & | full | ||
| ) |
Per-cell build on the compact ConvexCell (dual-triangle) representation — one thread per cell (RangePolicy; the cell lives in the per-thread register/local frame). Holds the grid-sorted inputs, the published outputs, and the grid scalars; buildCell clips the worklist neighbours on the fly and emits the per-facet CSR (neighbour id + area vector + dV + connector) via ConvexCell::facetGeometry — the same quantities the retired half-edge ScratchCell published, now from the leaner cell whose geometry is a cheap separate pass (so re-eval over a fixed topology is possible: ConvexCell::reevalGeometry). Rung A3 — the facet-edge AREA-JACOBIAN CSR of one finalised cell (shared by the cold build's CellBuilder::publishAreaGrad and reevalPublish). Per triangle, ConvexCell::geomVolumeAreaGrad gives the 3x3 blocks ∂contrib_i/∂n_{pl[j]}; summed over the cell's triangles they are exactly ∂A_{pl[i]}/∂n_{pl[j]}, and (i, j) with i != j is always an edge pair (the two planes meet at that vertex), so the CSR is the union of {self} ∪ {edge partners} per face — enumerated from the triangle list (dedup by a short scan; part/pcnt are the caller's MAXF*kMaxFV / MAXF scratch), then filled by one scatter pass. Planes that publish no face (< 3 live triangles) are skipped as partners: no area, and their sliver dependence is below the published-face contract. faces[0..nf) = the cell's face planes in CSR order.
| KOKKOS_INLINE_FUNCTION void peclet::voro::areaGradFill | ( | const Cell & | c, |
| const int * | faces, | ||
| int | nf, | ||
| const unsigned char * | part, | ||
| const unsigned char * | pcnt, | ||
| int | base, | ||
| int | ebase, | ||
| const IView & | oEdgeOff, | ||
| const IView & | oEdgeCnt, | ||
| const IView & | oEdgeFacet, | ||
| const RView & | oEdgeGrad, | ||
| const RView & | oEdgeLen | ||
| ) |
Fill the CSR entries reserved at ebase (see areaGradEnumerate): offsets/counts per facet (facet g = base + idx), partner facet indices (slot 0 = self), and the accumulated blocks.
| AuxMaps< Real > peclet::voro::buildAuxMaps | ( | const TessellationView< Real > & | view | ) |
Build {recip, cellOfFacet} on device from a published view (dense single-domain).
| KOKKOS_INLINE_FUNCTION void peclet::voro::buildConvexCell | ( | ConvexCell< Real, MAXP, MAXT, TrackAdj > & | c, |
| const Real | L[3], | ||
| const Real * | relx, | ||
| const Real * | rely, | ||
| const Real * | relz, | ||
| const int * | ids, | ||
| int | nNbr, | ||
| Real | wSelf = Real(0), |
||
| const Real * | weights = nullptr |
||
| ) |
Build a cell from neighbour relative positions sorted by ascending distance (rSqHalf). Policy = Voronoi (default) clips closest-first with the security-radius early-out: once the next candidate's plane offset exceeds 2·max-vertex-rsq, no farther seed can cut. Policy = Power uses the radical-plane offset ½(|r|²+w_self−w_nbr) and — in this reference builder — applies EVERY candidate (no early-out; the bisector security certificate is invalid once the offset can go negative, so P1 keeps the trivially-correct apply-all path). weights is indexed like ids (neighbour weights); it may be null for Voronoi. Mirrors the half-edge buildVoronoiCell.
| PoreCellsResult< Real > peclet::voro::buildPoreCells | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | posFlat, |
| int | N, | ||
| const Real | L[3], | ||
| const Sdf & | sdf, | ||
| int | sw = kSearchWindow |
||
| ) |
The SDF-clipped interstitial polyhedra of every seed, on the device.
| posFlat | device seed positions, x-fastest (3·i + k), in [0, L). |
| N | seed count. |
| L | periodic box extent. |
| sdf | the wall solid (any provider with eval()/gradH(); NoSdf gives the bare cells). |
| sw | the gather window (grid blocks per axis; kPoreSearchWindow in the bindings). Seeds inside the solid (empty cell) and cells that overflow the capacity are skipped; the result counts the latter, and the cells whose gather coverage did not close (kIncomplete). |
| PoreSectionResult< Real > peclet::voro::buildPoreSection | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | posFlat, |
| int | N, | ||
| const Real | L[3], | ||
| const Sdf & | sdf, | ||
| const Real | point[3], | ||
| const Real | normal[3], | ||
| int | sw = kSearchWindow |
||
| ) |
The cross-section of the SDF-clipped interstitial mesh by the plane through point with normal: every cell cut directly (ConvexCell::sectionPolygon, from the dual edges, so the polygons tile the section exactly). Same gather and skip rules as buildPoreCells; a cell the plane misses (or grazes at fewer than three crossings) yields no polygon.
| std::vector< int > peclet::voro::buildReciprocalMap | ( | const HostTessellation< Real > & | t | ) |
Reciprocal-facet transpose (NbrsToFacets, plan §2.5). For each packed facet g (cell i -> seed j) returns the packed index of the facet in cell j that points back to seed i, or -1 for a boundary facet or if no reciprocal exists. This is the map the atomic-free gather force reads through: a cell fetches its neighbour's reciprocal-facet quantities without scattering (no atomics).
Periodic multi-image facets (several g in i -> same j) are disambiguated by area-vector negation (the reciprocal has the most opposite area vector).
| TessellatorResult< Real > peclet::voro::buildTessellation | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | posFlat, |
| const Kokkos::View< Real *, peclet::core::MemSpace > & | weight, | ||
| int | N, | ||
| const Real | L[3], | ||
| int | sw = kSearchWindow, |
||
| int | densityCount = -1, |
||
| Kokkos::View< long *, peclet::core::MemSpace > | gid = {}, |
||
| Sdf | sdf = {}, |
||
| bool | withForceGeom = true, |
||
| int | nBuild = -1, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outNp = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outNt = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outPnbr = {}, |
||
| Kokkos::View< unsigned *, peclet::core::MemSpace > | outTri = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outCand = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outCandCnt = {}, |
||
| int | candCap = 0, |
||
| WorklistCache< Real > * | wlc = nullptr, |
||
| WallStore< Real > | outWall = {}, |
||
| bool | withAreaGrad = false, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outNear = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outNearCnt = {}, |
||
| int | nearCap = 0, |
||
| Real | nearMargin = Real(0), |
||
| bool | withWallFD = false, |
||
| bool | withMoments = false, |
||
| bool | profile = false |
||
| ) |
Build the full tessellation on device.
| posFlat | device positions, x-fastest per seed (3*i + k), in [0,L). |
| weight | device per-seed weights (size N) for the Power policy; ignored (may be empty) when Weighted == false. |
| N | number of seeds. |
| L | periodic box extent. |
| sw | grid-block half-width (default 4; coverage = sw·cellSize). |
| densityCount | seed count to derive the grid spacing from (cellSize ~ mean spacing). Defaults to N. In the distributed case the seeds are a clustered owned+ghost subset, so pass the GLOBAL count to keep the grid at the true local density. |
| nBuild | build a cell only for seeds whose ORIGINAL index is < nBuild; the rest are still used as cut candidates (neighbours) but their own cell is skipped. Defaults to N (build all). In the distributed case the ghosts are appended after the nOwned owned seeds, so passing nOwned tessellates only the kept (owned) cells — the ghost cells are needed only as cutting seeds, so building them is wasted work (~the ghost fraction of the cold build). |
| profile | print the timing (grid / build / CSR), the worklist size, over-buffer rebuilds and max facets per cell on stderr (the API's profile switch; the result's overBufferRebuilds reports the rebuilds without it). |
| TessGrid< Real > peclet::voro::buildTessGrid | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | posFlat, |
| const Kokkos::View< Real *, peclet::core::MemSpace > & | weight, | ||
| int | N, | ||
| const Real | L[3], | ||
| int | sw = kSearchWindow, |
||
| int | densityCount = -1, |
||
| Kokkos::View< long *, peclet::core::MemSpace > | gid = {}, |
||
| WorklistCache< Real > * | wlc = nullptr |
||
| ) |
Build the counting-sort grid + worklist for the Voronoi gather (the first half of the old buildTessellation, unchanged). Weighted only affects the grid density (Power keeps 1 seed/cell; unweighted host uses 2/cell for cache locality). See buildTessellation for the argument semantics. wlc (optional) reuses/fills the step-invariant worklist table across calls (E3); nullptr rebuilds it every call (the original behaviour, byte-for-byte).
| KOKKOS_INLINE_FUNCTION void peclet::voro::chainToDofs | ( | const Cell & | c, |
| const Real | seed[3], | ||
| const Real * | pos, | ||
| Real | wSelf, | ||
| const Real * | weight, | ||
| Real | L, | ||
| const Real * | gx, | ||
| const Real * | gy, | ||
| const Real * | gz, | ||
| Real | fSelf[3], | ||
| Real & | fwSelf, | ||
| Real * | fnx, | ||
| Real * | fny, | ||
| Real * | fnz, | ||
| Real * | fwn | ||
| ) |
Chain a cell's per-plane geometry gradient (SoA gx/gy/gz, e.g. from geomVolumeGrad) to the physics DOFs under Policy. Accumulates the derivative w.r.t. the cell's OWN seed into fSelf (position) and fwSelf (weight), and writes the derivative w.r.t. each neighbour seed into (fnx,fny,fnz)[k] (position) and fwn[k] (weight) — the caller scatters those into the global per-seed arrays at index pnbr[k]. Box/SDF planes (pnbr < 0) contribute nothing here (zeroed); SDF-wall self-DOF forces are added by the SDF chain in sdf.hpp.
seed/pos/wSelf/weight/L recompute each plane's (r, ρ, c) for weighted policies; they are untouched for Voronoi (kHasWeightDof == false), so a caller with no weights may pass nullptr for pos/weight and 0 for wSelf on the Voronoi path.
| Invariants peclet::voro::checkInvariants | ( | const TessellationView< Real > & | view, |
| const AuxMaps< Real > & | aux, | ||
| double | boxVolume | ||
| ) |
Compute the per-step invariants of a published TessellationView. aux is its reciprocal map (buildAuxMaps(view)); pass the box volume Lx*Ly*Lz.
| KOKKOS_INLINE_FUNCTION bool peclet::voro::clipCellAgainstSdf | ( | ConvexCell< Real, MAXP, MAXT, TrackAdj > & | c, |
| const Real | seed[3], | ||
| const Sdf & | sdf | ||
| ) |
Clip a built scratch cell against the SDF solid. Port of clipCellAgainstBoundary (m_boundaryMaxCuts=24, m_boundaryTol=1e-8): empties the cell if its seed is in the solid; otherwise iteratively projects the most violating vertex onto sdf=0 and clips by the tangent plane there, so a curved surface is approximated by a few planar wall facets. Rung A0 added the chord-plane fallback for a tangent plane that would exclude the seed (see the body) — the legacy port committed such planes and produced the dead cells seen in pore meshing.
| seed | seed world position (the cell's vpos are relative to it). |
| void peclet::voro::compareNeighbours | ( | const Kokkos::View< int *, peclet::core::MemSpace > & | storeNp, |
| const Kokkos::View< int *, peclet::core::MemSpace > & | storeNt, | ||
| const Kokkos::View< int *, peclet::core::MemSpace > & | storePnbr, | ||
| const Kokkos::View< unsigned *, peclet::core::MemSpace > & | storeTri, | ||
| int | MAXP, | ||
| int | MAXT, | ||
| const TessellationView< Real > & | oracle, | ||
| OracleDiff & | out | ||
| ) |
Compare the stored topology against the oracle's neighbour sets, on FACE neighbours (a stored plane k counts only if ≥3 live triangles are incident — the raw pnbr also keeps non-face cutting planes, which are not neighbours). changedNbrFrac = cells whose face-neighbour SET differs (either direction); missedNbr = cells missing a TRUE neighbour (genuine staleness — what the repair must drive to zero). Needs the packed triangles (tri at stride MAXT) + nt to identify the faces.
| void peclet::voro::compareVolumes | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | volCurrent, |
| const TessellationView< Real > & | oracle, | ||
| OracleDiff & | out | ||
| ) |
Compare a current per-cell volume array against the oracle view's volumes (cell i == seed i).
| int peclet::voro::flagSkinMovers | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | pos, |
| const Kokkos::View< Real *, peclet::core::MemSpace > & | xRef, | ||
| Real | skin, | ||
| const Real | L[3], | ||
| const Kokkos::View< int *, peclet::core::MemSpace > & | outFlags | ||
| ) |
Flag every particle that has moved more than skin/2 from xRef (minimal image in box L), writing kSkinMover/kSkinNone into outFlags, and return the number flagged. outFlags must be sized N. The flag value is OR-combinable with future trigger bits; here it is overwritten each call (the only Phase-1 trigger). One reduce + write pass; no host round-trip beyond the final count.
| InterfaceResult peclet::voro::interfaceMinimize | ( | std::vector< Real > & | pos, |
| const std::vector< int > & | type, | ||
| double | sigma, | ||
| const Real | L[3], | ||
| int | N, | ||
| int | sw, | ||
| const Sdf & | sdf, | ||
| int | maxIter, | ||
| Real | tol, | ||
| bool | verbose = false |
||
| ) |
| Real peclet::voro::maxDisplacement | ( | const Kokkos::View< Real *, peclet::core::MemSpace > & | pos, |
| const Kokkos::View< Real *, peclet::core::MemSpace > & | xRef, | ||
| const Real | L[3] | ||
| ) |
Largest per-seed displacement from xRef (minimal image), in absolute units. Diagnostics / the Verlet rebuild decision (max-disp > skin/2 -> a global rebuild is the simplest safe response).
| OtResult peclet::voro::meshVolumeOptimize | ( | std::vector< Real > & | pos, |
| std::vector< Real > & | weight, | ||
| const std::vector< Real > & | vsetIn, | ||
| const Real | L[3], | ||
| int | N, | ||
| int | sw, | ||
| const Sdf & | sdf, | ||
| int | maxNewton, | ||
| Real | tol, | ||
| int | cgIters = kOptimizerCgIters, |
||
| Precond | prec = Precond::Jacobi, |
||
| bool | verbose = false, |
||
| Real | muBarrier = 0, |
||
| Real | muDecay = (Real)kBarrierDecay, |
||
| bool | freeEnergy = false |
||
| ) |
Minimise the DIMENSIONLESS relative volume energy E = Σ (V_i/V_ref,i − 1)² by damped Gauss-Newton over positions (and weights when Weighted). vsetIn is the per-cell reference volume V_ref (may be non-uniform — spatially-graded refinement); it is renormalised to the actual total cell volume so the residual has zero mean and E → 0 is achievable. pos (3N) and weight (N; used only when Weighted) are updated in place.
NOTE: with an SDF the per-cell volume gradient still uses only the published seed-seed facetConnect (it omits the SDF wall-facet term), so pore-space meshing does not yet fully equalise — the wall gradient needs to be produced inside the tessellator (see the study in tests/kokkos/bench_mesh_optimizer).
| prec | Jacobi / ColoredGS / GraphAMG CG preconditioner. |
| cgIters | inner CG iterations per Newton step; |
| tol | on the gradient ∞-norm. |
| OtResult peclet::voro::meshVolumeOptimizeDevice | ( | std::vector< Real > & | posHost, |
| const std::vector< Real > & | vsetIn, | ||
| const Real | L[3], | ||
| int | N, | ||
| int | sw, | ||
| const Sdf & | sdf, | ||
| int | maxNewton, | ||
| Real | tol, | ||
| int | cgIters = kOptimizerCgIters, |
||
| bool | verbose = false |
||
| ) |
| KOKKOS_INLINE_FUNCTION int peclet::voro::morton3 | ( | int | x, |
| int | y, | ||
| int | z | ||
| ) |
3D Morton (Z-order) code of a grid cell, via the suite's morton library (Morton<3,21>, software bit path on device — no BMI2; bit-identical to the former hand-rolled magic-bits spread). Used to order the cell grid so a cell's spatial neighbourhood is near it in memory — the gather then reads near-contiguous cellStart/posSorted instead of chasing z-neighbours dimx*dimy entries apart. Good to 21 bits/axis (grid indices are far below that).
| OtResult peclet::voro::otVolumeControl | ( | std::vector< Real > & | pos, |
| std::vector< Real > & | weight, | ||
| const std::vector< Real > & | vsetIn, | ||
| const Real | L[3], | ||
| int | N, | ||
| int | sw, | ||
| const Sdf & | sdf, | ||
| int | maxNewton, | ||
| Real | tol, | ||
| Real | reg = Real(1e-6), |
||
| Real | damp = Real(1), |
||
| bool | verbose = false |
||
| ) |
Drive the power weights weight (size N, updated in place) so the power-cell volumes match vsetIn (size N). pos (size 3N) are the fixed seeds. Returns convergence diagnostics.
| sw | grid coverage half-width for the tessellation (default 4). |
| maxNewton | max Newton iterations. |
| tol | convergence on max_i |V_i − V_set_i| (absolute volume). |
| reg | tiny Laplacian regularisation ε (lifts the constant nullspace so L+εI is SPD). |
| damp | Newton step scale α (1 = full Newton; <1 damps). |
| verbose | print per-iteration residual. |
vsetIn is normalised internally so Σ V_set = Σ V (the total tessellated volume) — the constant nullspace of L requires a compatible right-hand side (Σ residual = 0).
| TessellationView< Real > peclet::voro::reevalPublish | ( | const TopologyStore< MAXP, MAXT > & | store, |
| const Kokkos::View< Real *, peclet::core::MemSpace > & | pos, | ||
| const Kokkos::View< Real *, peclet::core::MemSpace > & | vol, | ||
| int | N, | ||
| const Real | L[3], | ||
| WallStore< Real > | wall = {}, |
||
| Kokkos::View< Real *, peclet::core::MemSpace > | xRef = {}, |
||
| bool | withAreaGrad = false, |
||
| bool | withMoments = false |
||
| ) |
Re-evaluate the geometry of every cell in store on positions pos and publish a force-geometry TessellationView (facet neighbour / area / dV / connector CSR), reusing vol for the per-cell volume. MAXP/MAXT are the store's ConvexCell capacities; N cells; L the (cubic) box. wall + xRef (optional, rung A0): the resident SDF wall planes and the per-cell positions at which they were saved, so a wall-clipped cell's planes are restored for the seed's current position before the re-eval (see WallStore). Leave both empty for a wall-free tessellation. withAreaGrad (rung A3): also publish the facet-edge area-Jacobian CSR (the same layout the cold build emits, with a deterministic prefix-sum reservation), so the energy layer runs on the incremental path too.
| KOKKOS_INLINE_FUNCTION bool peclet::voro::sdfCutPlane | ( | const ConvexCell< Real, MAXP, MAXT, TrackAdj > & | c, |
| const Real | seed[3], | ||
| const Sdf & | sdf, | ||
| const Real | probe[3], | ||
| Real | radius, | ||
| Real | pv[3], | ||
| Real & | off, | ||
| Real | surf[3] | ||
| ) |
The wall cut plane for a probe point (the seed for the first cut, a violating vertex after): closest point on φ = 0 + outward normal (oriented into the fluid), the half-space {x : pv·x ≤ off} in seed-relative coordinates with pv = −normal, plus the tangency point surf (world) for the sagitta post-pass. Shared by clipCellAgainstSdf and the moving-point boundary watch (sdfWouldClip), so both make the same decision. Returns false if the gradient is degenerate (no plane).
| KOKKOS_INLINE_FUNCTION void peclet::voro::sdfGradient | ( | const Sdf & | s, |
| Real | x, | ||
| Real | y, | ||
| Real | z, | ||
| Real | g[3] | ||
| ) |
Central-difference gradient of any provider with eval() (matches peclet::core::geom::gradient).
| KOKKOS_INLINE_FUNCTION void peclet::voro::sdfHessian | ( | const Sdf & | s, |
| Real | x, | ||
| Real | y, | ||
| Real | z, | ||
| Real | H[3][3] | ||
| ) |
Central-difference Hessian H_ab = ∂²φ/∂x_a∂x_b (symmetrised), via differences of the gradient (same stencil as sdfGradient, so host/device agree). Used by the differentiable SDF wall force.
| KOKKOS_INLINE_FUNCTION int peclet::voro::sdfSagittaShifts | ( | const ConvexCell< Real, MAXP, MAXT, TrackAdj > & | c, |
| const Real | seed[3], | ||
| const Sdf & | sdf, | ||
| const int * | planes, | ||
| const Real * | tangency, | ||
| int | nPlanes, | ||
| Real * | delta | ||
| ) |
Rung A1 — second-order wall placement. A tangent plane at a tangency point surf (unit normal into the fluid) is exact for a flat wall but INSCRIBED for a curved one: over its face the true surface deviates from the plane by h(p) = φ(surf + p)/|∇φ| ≈ ½ pᵀ H p / |∇φ| (p in-plane, H = ∇²φ), so the tangent cut removes the fluid sliver between plane and wall on a convex solid and leaves solid inside the cell on a concave one. Once the multi-plane tangent clip has settled the cell, each committed wall plane k gets the mean sliver depth over its FINAL face polygon, δ_k = V_sag / A_k, V_sag = ½ Σ_ab H_ab M_ab / |∇φ|, M = ∫_face p pᵀ dA about surf, and clipCellAgainstSdf RE-CLIPS the un-cut cell with every plane translated INTO the solid by its δ_k (a re-clip, not a plane move, so the result is a valid convex clip and the resident certificate stays clean). The planar cell then has the curved cell's volume to second order. Shifts below round-off of the Hessian stencil (|δ| < 1e-8·h_k, i.e. flat walls) are zeroed so a flat wall is bit-identical to the tangent clip. Writes δ_k into delta (0 for planes with no face); returns the number of nonzero shifts.
| KOKKOS_INLINE_FUNCTION void peclet::voro::sdfWallChain | ( | const Sdf & | sdf, |
| Real | x, | ||
| Real | y, | ||
| Real | z, | ||
| const double | gw[3], | ||
| double | fSelf[3] | ||
| ) |
The seed-foot SDF wall chain (rung A3 — the single source; see energy/wall.hpp): f_self += J_wallᵀ g_w with J_wall = dn/dx of the foot vector n = −φ∇φ/|∇φ|². Coordinates in Real, accumulation in double — the exact arithmetic of the optimiser's device kernel it replaces. No-op for NoSdf.
| KOKKOS_INLINE_FUNCTION void peclet::voro::sdfWallFD | ( | const ConvexCell< Real, MAXP, MAXT, TrackAdj > & | unclipped, |
| const Real | seed[3], | ||
| const Sdf & | sdf, | ||
| Real | h, | ||
| Real | dV[3], | ||
| Real | dA[3] | ||
| ) |
Rung A1 (force half) — the wall part of a cell's geometry gradient, exact for WHATEVER the clip does (tangent planes, chord planes, the sagitta re-clip): central differences of the clipped cell's volume and wall area with respect to the seed position, with the neighbour planes held fixed in the seed frame (the chain-rule split the energy layer uses: neighbour planes go through the plane policy, wall planes through this). unclipped is the cell BEFORE the SDF clip; six SDF clips of a copy at seed ± h e_d. Writes dV/dx and dA_wall/dx (3 each).
| KOKKOS_INLINE_FUNCTION bool peclet::voro::sdfWouldClip | ( | const ConvexCell< Real, MAXP, MAXT, TrackAdj > & | c, |
| const Real | seed[3], | ||
| const Sdf & | sdf | ||
| ) |
Would clipCellAgainstSdf commit at least one wall plane on this (un-clipped) cell? The exact decision the cold build makes, so the moving-point boundary watch flags precisely the cells whose cold rebuild would differ from a wall-free re-evaluation: the seed is in the solid (the cell would be emptied), OR the cell is within its circumradius of the surface AND (some vertex lies beyond the seed-foot tangent plane — the first cut — OR some vertex is inside the solid by more than the clip tolerance — a later cut). Reads the same tolerance and probe rule as the clip.
| SubsetGatherResult< Real > peclet::voro::subsetGather | ( | const TessGrid< Real > & | grid, |
| const Kokkos::View< int *, peclet::core::MemSpace > & | indices, | ||
| int | nSubset, | ||
| const Kokkos::View< int *, peclet::core::MemSpace > & | outNp, | ||
| const Kokkos::View< int *, peclet::core::MemSpace > & | outNt, | ||
| const Kokkos::View< int *, peclet::core::MemSpace > & | outPnbr, | ||
| const Kokkos::View< unsigned *, peclet::core::MemSpace > & | outTri, | ||
| const Kokkos::View< Real *, peclet::core::MemSpace > & | cellVol, | ||
| const Kokkos::View< unsigned char *, peclet::core::MemSpace > & | outPoke4 = {}, |
||
| Sdf | sdf = {}, |
||
| bool | withForceGeom = false, |
||
| WallStore< Real > | outWall = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outNear = {}, |
||
| Kokkos::View< int *, peclet::core::MemSpace > | outNearCnt = {}, |
||
| int | nearCap = 0, |
||
| Real | nearMargin = Real(0) |
||
| ) |
Gather + clip the nSubset cells named by indices (original seed indices) off grid, writing their topology into the caller's store views and their volume into the result.
| grid | a TessGrid built for the CURRENT positions (buildTessGrid). Reused, not rebuilt. |
| indices | device view of nSubset ORIGINAL seed indices to (re)build (values in [0,N)). |
| nSubset | number of indices to process. |
| outNp,outNt,outPnbr,outTri | topology store views, each sized as in TopologyStore::alloc(N) (N, N, N*MAXP, N*MAXT) with MAXP=CellBuilder::kMaxP, MAXT=CellBuilder::kMaxT. |
| cellVol | N-sized view; the volume of each rebuilt cell is written at its original index. |
| withForceGeom | if true also compute the per-facet area/dV/connector (kept for parity with the cold build); the facet CSR itself is not published here (the store is). Default false: the store + volume are what Phase-1 needs (geometry is re-derived on reload). |
|
inline |
| TessellationView< Real > peclet::voro::upload | ( | const HostTessellation< Real > & | h | ) |
Upload a HostTessellation to device Views.
|
constexpr |
|
constexpr |
Neighbour id stamped on a facet produced by an SDF cut (a wall). Distinct from the initial-cuboid boundary (-1); published as facetNbr < 0 either way.
|
constexpr |
Moving-point repair: the certificate tolerance and the Verlet skin, both as fractions of the mean spacing cbrt(V/N) (MovingTessellation::alloc takes the absolute values).
|
constexpr |
ConvexCell capacity of the resident (moving-point) tessellation: planes and dual triangles (= primal vertices) per cell — the production layout and the topology store's strides (README "Early wall clip"). The plane cap must fit a byte (ConvexCell's static_assert).
|
constexpr |
|
constexpr |
Upper bound on the wall planes one SDF clip can commit: clipCellAgainstSdf runs at most maxCuts (24) iterations and each commits at most one plane.
|
constexpr |
Mesh optimisers: the CG iteration cap of the Gauss–Newton solve, and the per-iteration decay of the pore-space optimiser's log-barrier weight.
|
constexpr |
Capacity of the pore-space (SDF-walled interstitial) cell reconstruction: wall-cut cells carry more planes than a Poisson–Voronoi cell.
|
constexpr |
|
constexpr |
Gather window of the tessellator's counting-sort grid: blocks per axis around a seed (coverage = window · block size); the moving-point path and the cold build share it.
|
constexpr |
|
constexpr |
Bias added to each signed block offset (dx,dy,dz) so it packs into one int (8 bits per axis) in the worklist table — a single load + bit-unpack in the hot gather loop instead of three scattered loads. Block offsets stay within [-sw,sw], sw << 128.