peclet.voro 1.0.0
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | List of all members
peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj > Struct Template Reference

#include <convex_cell.hpp>

Public Member Functions

KOKKOS_INLINE_FUNCTION void initBox (Real L0, Real L1, Real L2)
 
KOKKOS_INLINE_FUNCTION void computeVertex (int t)
 
KOKKOS_INLINE_FUNCTION void initBoxPlanes (Real L0, Real L1, Real L2)
 
template<class Policy = Voronoi>
KOKKOS_INLINE_FUNCTION void reevalGeometry (Real sx, Real sy, Real sz, const Real *pos, Real L, Real wSelf=Real(0), const Real *weight=nullptr)
 
KOKKOS_INLINE_FUNCTION bool isSelfConsistent (Real tol) const
 
KOKKOS_INLINE_FUNCTION bool isSelfConsistentPartners (Real tol, int *outPartners, int maxPartners, int &nPartners) const
 
KOKKOS_INLINE_FUNCTION int oppositePlane (int s, int x, int y) const
 
KOKKOS_INLINE_FUNCTION void computePoke4 (unsigned char *out) const
 
KOKKOS_INLINE_FUNCTION bool isLocallyConvex (const unsigned char *poke4, Real tol) const
 
KOKKOS_INLINE_FUNCTION bool isLocallyConvexPartners (const unsigned char *poke4, Real tol, int *outPartners, int maxPartners, int &nPartners) const
 
KOKKOS_INLINE_FUNCTION Real maxVertexRsq () const
 Largest squared dual-vertex radius over live triangles (drives the security radius).
 
KOKKOS_INLINE_FUNCTION int findSharing (int self, int x, int y) const
 
KOKKOS_INLINE_FUNCTION void rebuildAdjacency ()
 
KOKKOS_INLINE_FUNCTION bool checkAdjacencyInvariant () const
 
KOKKOS_INLINE_FUNCTION int allocTri ()
 
KOKKOS_INLINE_FUNCTION bool clip (const Real pdir[3], Real d, int nbr)
 
KOKKOS_INLINE_FUNCTION bool empty () const
 
KOKKOS_INLINE_FUNCTION int countFaces () const
 
KOKKOS_INLINE_FUNCTION int faceOrdered (int k, Real fx[MAXFV], Real fy[MAXFV], Real fz[MAXFV]) const
 
KOKKOS_INLINE_FUNCTION int sectionPolygon (const Real p0[3], const Real u[3], Real px[MAXSV], Real py[MAXSV], Real pz[MAXSV]) const
 
KOKKOS_INLINE_FUNCTION Real volume () const
 
KOKKOS_INLINE_FUNCTION void planeN (int k, Real out[3]) const
 
KOKKOS_INLINE_FUNCTION Real volumePerVertex () const
 
KOKKOS_INLINE_FUNCTION void facetAreasPerVertex (Real *area) const
 
KOKKOS_INLINE_FUNCTION void facetMomentsPerVertex (Real *area, Real *mx, Real *my, Real *mz) const
 
KOKKOS_INLINE_FUNCTION void geomVolumeGrad (Real &vol, Real *dgx, Real *dgy, Real *dgz) const
 
KOKKOS_INLINE_FUNCTION void geomVolumeArea (Real &vol, Real *avx, Real *avy, Real *avz, Real *dgx, Real *dgy, Real *dgz) const
 
KOKKOS_INLINE_FUNCTION void geomVolumeAreaGrad (int t, int pl[3], Real contrib[3], Real grad[3][3][3]) const
 
KOKKOS_INLINE_FUNCTION void geomVolumeAreaGradAD (int t, int pl[3], Real contrib[3], Real grad[3][3][3]) const
 
KOKKOS_INLINE_FUNCTION void geometryPerVertex (Real &vol, Real *area, Real *mx, Real *my, Real *mz) const
 
KOKKOS_INLINE_FUNCTION bool facetGeometry (int k, Real areaVec[3], Real dv[3], Real conn[3]) const
 

Static Public Member Functions

static KOKKOS_INLINE_FUNCTION void polyAreaVec (const Real fx[], const Real fy[], const Real fz[], int m, Real A[3])
 Polygon area vector (0.5 Σ vi × v(i+1)) of an ordered face.
 
static KOKKOS_INLINE_FUNCTION void xprod (const Real a[3], const Real b[3], Real o[3])
 
static KOKKOS_INLINE_FUNCTION Real dot3 (const Real a[3], const Real b[3])
 
static KOKKOS_INLINE_FUNCTION Real det3 (const Real a[3], const Real b[3], const Real c[3])
 
static KOKKOS_INLINE_FUNCTION void edgeFoot (const Real v[3], const Real ck[3], Real f[3])
 foot of the perpendicular from v onto the edge line of direction ck: v − (v·ck/ck·ck) ck.
 
static KOKKOS_INLINE_FUNCTION void scatterFacetMoment (int ki, const Real ni[3], const Real ff[3], const Real fl[3], const Real v[3], Real *area, Real *mx, Real *my, Real *mz)
 
static KOKKOS_INLINE_FUNCTION void scatterGradRaw (int ki, const Real ni[3], const Real ff[3], const Real fl[3], const Real v[3], Real *dgx, Real *dgy, Real *dgz)
 
static KOKKOS_INLINE_FUNCTION void scatterAreaMomentRaw (int ki, const Real ni[3], const Real ff[3], const Real fl[3], const Real v[3], Real *sa_acc, Real *smx, Real *smy, Real *smz)
 
static KOKKOS_INLINE_FUNCTION void edgeCrossAdj (int j, int p, int q, const Real Nn[3][3], const Real w[3], Real out[3])
 

Public Attributes

Real n [MAXP][3]
 
Real nn [MAXP]
 cached n·n, i.e. the half-space offset (so the cull test is n·x <= nn)
 
int pnbr [MAXP]
 neighbour seed id per plane (<0 => bounding box)
 
int np
 number of planes
 
unsigned char t0 [MAXT]
 
unsigned char t1 [MAXT]
 
unsigned char t2 [MAXT]
 triangle = triple of plane indices
 
Real vx [MAXT]
 
Real vy [MAXT]
 
Real vz [MAXT]
 cached dual-vertex position per triangle
 
bool alive [MAXT]
 triangle live flag
 
int nt
 triangle high-water mark
 
bool overflow
 set if MAXP/MAXT exceeded -> cell invalid, caller falls back
 
Kokkos::Array< int,(TrackAdj ? MAXT :0) *3 > adj
 

Static Public Attributes

static constexpr bool kTrackAdj
 lets templated consumers (store save/load) branch at compile time
 
static constexpr int MAXFV = 28
 
static constexpr int MAXSV = 2 * MAXFV
 max vertices on a cross-section polygon
 

Detailed Description

template<class Real, int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
struct peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >

Compact convex Voronoi cell. MAXP planes (<=255 so a plane index fits in a byte), MAXT dual triangles (= primal vertices). Trivially default-constructible (POD) so it lives in registers / a per-thread stack.

Member Function Documentation

◆ allocTri()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::allocTri ( )
inline

◆ checkAdjacencyInvariant()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::checkAdjacencyInvariant ( ) const
inline

DEBUG oracle: true iff adj is internally consistent for all live triangles (every entry points to a live triangle that actually shares the edge, and the back-link is symmetric). Every incremental stitch in clip must leave this true; assert it after each clip in debug builds. Trivially true when !TrackAdj.

◆ clip()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::clip ( const Real  pdir[3],
Real  d,
int  nbr 
)
inline

Add a plane for neighbour nbr and clip the cell by it. The plane is passed in (direction, offset) form {x : pdir·x <= d}; it is stored internally as its foot-point normal nf = (d/|pdir|²)·pdir (so {x : nf·x <= nf·nf} is the same half-space). Returns true if the cell was modified. The plane is only committed if it actually cuts (so redundant candidates don't grow np).

◆ computePoke4()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::computePoke4 ( unsigned char *  out) const
inline

Compute the packed per-triangle "poke4" plane set the local certificate reads: for each live triangle, out[t*4 + 0..2] = the three edge-opposite planes (from adj, no findSharing) and out[t*4 + 3] = the dual Delaunay tet's FOURTH face (the one not incident to the seed) — the non-defining, non-edge-opposite plane the vertex is nearest to from inside (smallest positive slack). 0xff = none. Including the fourth face makes the local cert match the brute flag set (complete, not a subset). Dead triangles get all-0xff. Requires adj populated + the cached vertices; call once after the cell is finalised (gather / rebuild) and persist out — the cert then reads it directly each re-eval step, with NO per-vertex adj derivation.

◆ computeVertex()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::computeVertex ( int  t)
inline

Compute and cache the dual vertex of triangle t (where its three planes meet, Cramer's rule). Called once when a triangle is created; all later reads use the cache (vx/vy/vz), so the per-cell vertex solves are O(#triangles), not O(#clips · #triangles) — the difference between compute-bound and not.

◆ countFaces()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::countFaces ( ) const
inline

◆ det3()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::det3 ( const Real  a[3],
const Real  b[3],
const Real  c[3] 
)
inlinestatic

◆ dot3()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::dot3 ( const Real  a[3],
const Real  b[3] 
)
inlinestatic

◆ edgeCrossAdj()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::edgeCrossAdj ( int  j,
int  p,
int  q,
const Real  Nn[3][3],
const Real  w[3],
Real  out[3] 
)
inlinestatic

Adjoint of a cross-product edge direction: (∂(N[p]×N[q])/∂n_j)^T w. Used by the analytic geomVolumeAreaGrad.

◆ edgeFoot()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::edgeFoot ( const Real  v[3],
const Real  ck[3],
Real  f[3] 
)
inlinestatic

foot of the perpendicular from v onto the edge line of direction ck: v − (v·ck/ck·ck) ck.

◆ empty()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::empty ( ) const
inline

◆ faceOrdered()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::faceOrdered ( int  k,
Real  fx[MAXFV],
Real  fy[MAXFV],
Real  fz[MAXFV] 
) const
inline

Gather face k's vertices (the alive dual triangles containing plane k) and order them CCW around the face normal (insertion sort by in-plane angle). Returns the count, or <3 if k is not a (≥triangle) face. Shared by volume() and facetGeometry() — the G0/G1/G2 geometry tiers all start here.

◆ facetAreasPerVertex()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::facetAreasPerVertex ( Real *  area) const
inline

Per-facet areas by the same vertex-local scatter (area[k] zeroed by caller, size np). Each vertex scatters into its 3 incident facets; |n_i| is the only sqrt (per facet). Order/adjacency-free.

◆ facetGeometry()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::facetGeometry ( int  k,
Real  areaVec[3],
Real  dv[3],
Real  conn[3] 
) const
inline

Per-facet physics geometry (G2 tier) for plane k: the outward face area VECTOR, the volume gradient dV = ∂V/∂r_k, and the connecting vector r_k (= the plane normal). Matches the half-edge facetArea / facetConnect / facetConnVec. Returns false if k is not a face.

Derivation of dV: the cell is { r_k·x ≤ ½|r_k|² }. Perturbing r_k → r_k+δ moves a point x on face k off the plane by δ·(x−r_k); the outward normal displacement is −δ·(x−r_k)/|r_k|, so δV = ∫_face (−δ·(x−r_k)/|r_k|) dA = (area/|r_k|) δ·(r_k − c_k), with c_k the face centroid. Holding all other planes fixed, this is first-order exact ⇒ dV = ∂V/∂r_k = (area/|r_k|)·(r_k − c_k).

◆ facetMomentsPerVertex()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::facetMomentsPerVertex ( Real *  area,
Real *  mx,
Real *  my,
Real *  mz 
) const
inline

Per-facet area + first moment ∫x dA by the same vertex-local scatter (caller zeroes the np-sized arrays). The area-weighted facet centroid is c_k = (mx,my,mz)[k]/area[k]; the volume gradient (force) is then dV_k = ∂V/∂r_k = (area_k/|r_k|)(r_k − c_k) with connector r_k = 2·n[k] — sort/adjacency-free.

◆ findSharing()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::findSharing ( int  self,
int  x,
int  y 
) const
inline

Find a live triangle != self that contains both plane indices x and y. In a valid triangulation an interior edge is shared by exactly two triangles. Dead triangles (alive==false) keep stale plane indices, so they MUST be skipped or they create phantom horizon edges (the cascade bug). During a clip the about-to-be-removed triangles are still alive==true (removed only after horizon collection), so they are correctly considered here and rejected by the caller's kill[] test.

◆ geometryPerVertex()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::geometryPerVertex ( Real &  vol,
Real *  area,
Real *  mx,
Real *  my,
Real *  mz 
) const
inline

MERGED vertex-local geometry: cell volume + per-facet area + per-facet first moment ∫x dA, all in ONE pass (shares n,c,D,v,feet per vertex). The production G1+G2 kernel — sort-free, adjacency-free. Caller zeroes the np-sized arrays. With connector r_k = 2·n[k] (so |r_k| = 2·sqrt(nn[k])), derive per facet k: areaVec_k = area[k] · r_k/|r_k| = area[k] · n[k]/|n[k]| (outward, toward the neighbour) centroid_k = (mx,my,mz)[k]/area[k] force dV_k = (area[k]/|r_k|)·(r_k − centroid_k)

◆ geomVolumeArea()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::geomVolumeArea ( Real &  vol,
Real *  avx,
Real *  avy,
Real *  avz,
Real *  dgx,
Real *  dgy,
Real *  dgz 
) const
inline

geomVolumeArea tier (Phase 2): cell volume + the outward area-VECTOR A_k·n_k/|n_k| AND the volume gradient dV/dn_k per plane — the full G2 physics set (areas for fluxes/momentum, gradient for force). Like geomVolumeGrad it is fully SQRT-FREE: both outputs are |n|²-normalized — areaVec_k = S_a·n_k/(2·nn[k]) and dV/dn_k = (2·S_a·n_k − S_m)/(2·nn[k]) — with the raw S_a (=2|n_k|·A_k) and S_m (=2|n_k|·m_k) scattered per vertex. No extra scratch: during the scatter avx holds S_a and (dgx,dgy,dgz) hold S_m; the per-facet fold overwrites them in place (so the compact-cell stack stays at the 6 caller arrays). Caller zeroes all six. The facet centroid, if wanted, is c_k = S_m/S_a (also sqrt-free) — derivable but not exposed here. Matches facetGeometry's areaVec/dv to round-off.

◆ geomVolumeAreaGrad()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::geomVolumeAreaGrad ( int  t,
int  pl[3],
Real  contrib[3],
Real  grad[3][3][3] 
) const
inline

geomFull primitive: the per-dual-triangle ("subtetrahedron") area-Jacobian block — the building block of the FULL coupled dA_k/dn_l (the OT/power-diagram Hessian), with NO ordering and NO adjacency. ANALYTIC, no-recompute version: it reuses the CACHED vertex v and computes the per-triangle intermediates (edge directions, feet) once in Real, then forms the derivatives in closed form. The vertex derivative is the rank-1 ∂v/∂n_j = (c_j/D)(2n_j − v)^T (c_j the cofactor, D the determinant); the area numerator N_i=det3(n_i,g_i,v) is differentiated trilinearly (∂/∂n_i = g_i×v, ∂/∂g via the foot adjoints, ∂/∂v via the rank-1 above), and the 1/(2|n_i|) factor adds the −δ_ij A_i n_i/nn_i term. Outputs: pl[3] = the (canonically ordered) plane indices; contrib[3] = the area contributions (Σ over triangles reproduces facetAreasPerVertex's area[k]); grad[i][j][c] = ∂contrib_i/∂n_{pl[j]}[c]. Consumer gathers A_{pl[i]} += contrib[i], dA_{pl[i]}/dn_{pl[j]} += grad[i][j], in any order.

◆ geomVolumeAreaGradAD()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::geomVolumeAreaGradAD ( int  t,
int  pl[3],
Real  contrib[3],
Real  grad[3][3][3] 
) const
inline

Reference (forward-AD) implementation of the per-triangle area-Jacobian, kept only as the machine-precision ORACLE for the analytic geomVolumeAreaGrad (it recomputes everything in dual arithmetic, including the vertex — the redundancy the analytic version removes). Same outputs as geomVolumeAreaGrad.

◆ geomVolumeGrad()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::geomVolumeGrad ( Real &  vol,
Real *  dgx,
Real *  dgy,
Real *  dgz 
) const
inline

geomVolumeGrad tier (Phase 2): cell volume + the volume gradient dV/dn_k per plane, with NO area/ centroid arrays exposed, NO sqrt anywhere, and only the 3 output arrays touched (so it keeps the compact cell's GPU occupancy). dV/dn_k = (2·A_k·n_k − m_k)/|n_k|; scattering the raw numerator 2·S_a·n_k − S_m per vertex (S_a = 2|n_k|·A_k, S_m = 2|n_k|·m_k), the per-facet fold is dV/dn_k = (numerator)/(2·nn[k]) — the |n_k| cancels into the stored nn=|n|². Caller zeroes the np-sized dgx/dgy/dgz (accumulate the numerator, then overwritten in place by the fold). Matches geometryPerVertex's closed form to round-off. Voronoi position force dV/dr_k = ½·(dgx,dgy,dgz)[k]; the policy layer (Phase 3) owns that chain.

◆ initBox()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::initBox ( Real  L0,
Real  L1,
Real  L2 
)
inline

Seed the cell with the big cuboid of extent (L0,L1,L2) centred on the seed. Planes 0:+x 1:-x 2:+y 3:-y 4:+z 5:-z; the 8 corners are the dual triangles.

◆ initBoxPlanes()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::initBoxPlanes ( Real  L0,
Real  L1,
Real  L2 
)
inline

Set ONLY the six bounding-box planes (0:+x 1:-x 2:+y 3:-y 4:+z 5:-z), np=6, no triangles. Used to rebuild a cell from a compact stored topology: the caller then overwrites np/nt and the triangle structure and calls reevalGeometry() (which fills the neighbour planes + all vertices).

◆ isLocallyConvex()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::isLocallyConvex ( const unsigned char *  poke4,
Real  tol 
) const
inline

Local convexity certificate (Lawson), O(nt). Per dual vertex, test it against its four precomputed poke4 planes (the three edge-opposite + the fourth-face plane): the cell is locally Voronoi iff no vertex pokes past any of them. With the fourth face included this matches the brute certificate's flag set (Delaunay's lemma over the full dual tet), so it is complete, not a subset. Reads the planes from poke4 (no adj), so it runs on ANY cell — the cert path keeps a lean cell + this persisted table.

◆ isLocallyConvexPartners()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::isLocallyConvexPartners ( const unsigned char *  poke4,
Real  tol,
int *  outPartners,
int  maxPartners,
int &  nPartners 
) const
inline

Partner-emitting form of isLocallyConvex — same poke4 test, additionally emitting the violated-plane partner seed(s) (the pnbr id of each plane a vertex pokes past), deduplicated into outPartners. These are the gaining cells of a flip (the §1 repair signal) so the gather repair seeds Pass 1 from them.

◆ isSelfConsistent()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::isSelfConsistent ( Real  tol) const
inline

Part II detection (D2 — the "convexity"/self-consistency certificate). After a re-eval on the FIXED stored topology, the cell is the intersection of its half-spaces ONLY if every dual vertex still lies inside every OTHER plane of the cell: n_k·v ≤ nn_k. If some vertex pokes out past a plane k (by more than tol, an absolute distance), that plane should have cut it ⇒ the stored topology is stale (a face was lost / an internal flip happened) ⇒ this cell needs a topology rebuild. This is purely cell-local (no neighbour data): it catches LOST faces directly. A GAINED face (an external seed that has moved close enough to cut this cell) is NOT visible here — the conjecture (to be tested empirically) is that such an event makes the PARTNER cell self-inconsistent, so a global sweep of this test still flags it. Exception: an SDF/boundary plane has no partner cell, so boundary cells need a separate boundary watch.

◆ isSelfConsistentPartners()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::isSelfConsistentPartners ( Real  tol,
int *  outPartners,
int  maxPartners,
int &  nPartners 
) const
inline

Part-II repair signal (Phase 1): the convexity/in-sphere certificate above, additionally emitting the violated-plane partner seed(s) — the pnbr id of each stored plane k a re-evaluated vertex pokes past. By the §1 analysis (dynamic_update_decision_and_plan.md) these partners are exactly the gaining cells of a 2→3 flip (cells i,m that never flag themselves), so they are the cheap, local, connectivity-free signal that reaches them — necessary for a complete one-pass repair. Partners are deduplicated into outPartners[0..nPartners) (capped at maxPartners; the rare overflow just truncates — the periodic oracle is the backstop). A violated plane with pnbr<0 (box/SDF wall) has no partner cell: it still marks the cell inconsistent (so the cell itself is rebuilt) but emits no partner — the SDF boundary-contact trigger (Risk 1d) is the deferred complement that catches gained wall faces. Returns true iff the cell is self-consistent (no violation past tol).

WEIGHTED/POWER (deferred, see [[vorflow-power-cells-deferred]]): for a Laguerre cell the in-sphere test n_k·v ≤ nn_k must become the empty-**orthosphere** (power-distance) predicate so completeness carries to the regular triangulation. The ConvexCell device path is Voronoi-only today (no radical-plane geometry), so only the unweighted form is implemented; the orthosphere form plugs in here when the Power policy lands.

◆ maxVertexRsq()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::maxVertexRsq ( ) const
inline

Largest squared dual-vertex radius over live triangles (drives the security radius).

◆ oppositePlane()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::oppositePlane ( int  s,
int  x,
int  y 
) const
inline

Edge-opposite plane of the triangle s across shared edge {x,y}: the one vertex (plane index) of s that is neither x nor y. Helper for the Lawson local certificate.

◆ planeN()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::planeN ( int  k,
Real  out[3] 
) const
inline

Foot-point normal of plane k — now stored directly, so just a copy (the reconstruction divide is gone).

◆ polyAreaVec()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::polyAreaVec ( const Real  fx[],
const Real  fy[],
const Real  fz[],
int  m,
Real  A[3] 
)
inlinestatic

Polygon area vector (0.5 Σ vi × v(i+1)) of an ordered face.

◆ rebuildAdjacency()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::rebuildAdjacency ( )
inline

Brute O(nt²) rebuild of the edge-adjacency table from triangle topology (via findSharing). Bootstrap (initBox) + fallback only, never in the hot path. No-op when !TrackAdj.

◆ reevalGeometry()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
template<class Policy = Voronoi>
KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::reevalGeometry ( Real  sx,
Real  sy,
Real  sz,
const Real *  pos,
Real  L,
Real  wSelf = Real(0),
const Real *  weight = nullptr 
)
inline

Part II (moving points): re-evaluate this cell's geometry IN PLACE after the seeds moved, REUSING the resident topology (the surviving plane set pnbr + the dual-triangle structure t0/t1/t2/alive). No gather, no clip: each neighbour plane is rebuilt from the neighbour's new position (box planes pnbr<0 are fixed), then every live vertex is recomputed. Correct exactly when the topology is unchanged (the common case for small per-step displacement); a topology flip must be detected + repaired separately (Phase 1.5). pos is the global seed array (x- fastest, 3*N); L the periodic box length for min-imaging.

Policy = Voronoi (default) rebuilds the bisector foot point n = ½r (byte-identical to the historical path). Policy = Power rebuilds the radical foot point n = α r with offset d = ½(|r|²+w_self−w_nbr); pass the cell's own weight wSelf and the global weight array (indexed by pnbr[k]). weight may be null for Voronoi.

◆ scatterAreaMomentRaw()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::scatterAreaMomentRaw ( int  ki,
const Real  ni[3],
const Real  ff[3],
const Real  fl[3],
const Real  v[3],
Real *  sa_acc,
Real *  smx,
Real *  smy,
Real *  smz 
)
inlinestatic

Scatter one facet's RAW area S_a (=Σdet3) and RAW first moment S_m (=Σdet3·centroid_tri) AT a vertex — scatterFacetMoment without the 1/(2|n|) factor (so NO sqrt). geomVolumeArea defers the shared 1/(2|n|) to its per-facet fold, where it cancels against |n| for the area-vector and the gradient.

◆ scatterFacetMoment()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::scatterFacetMoment ( int  ki,
const Real  ni[3],
const Real  ff[3],
const Real  fl[3],
const Real  v[3],
Real *  area,
Real *  mx,
Real *  my,
Real *  mz 
)
inlinestatic

Scatter one facet's area + first moment (∫x dA) at a vertex into the per-facet accumulators. Facet i's local boundary at v is the path f_first → v → f_last with apex n_i: two signed triangles (n_i,f_first,v) and (n_i,v,f_last). |n_i| is the one sqrt (per facet).

◆ scatterGradRaw()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::scatterGradRaw ( int  ki,
const Real  ni[3],
const Real  ff[3],
const Real  fl[3],
const Real  v[3],
Real *  dgx,
Real *  dgy,
Real *  dgz 
)
inlinestatic

Scatter one facet's contribution to the volume-gradient NUMERATOR 2·S_a·n_k − S_m AT a vertex, with NO sqrt and into just the 3 output arrays. The trick: n_k is the SAME normal (= ni) at every vertex of facet k, so the per-vertex term 2·da·ni − mom already carries the facet normal; summed over the facet's vertices it is exactly 2·(Σda)·n_k − Σmom = 2·S_a·n_k − S_m. da, mom are RAW (no 1/(2|n|) factor); geomVolumeGrad's fold supplies the shared 1/(2·nn[k]) once per facet (also sqrt-free).

◆ sectionPolygon()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::sectionPolygon ( const Real  p0[3],
const Real  u[3],
Real  px[MAXSV],
Real  py[MAXSV],
Real  pz[MAXSV] 
) const
inline

Cross-section of the cell by the plane {x : (x - p0)·u = 0}: the convex polygon the plane cuts out. Enumerates the cell's primal EDGES straight from the dual triangles — an edge is a pair of alive triangles sharing exactly two planes (each edge is then their two endpoints, found exactly once) — and collects the point where each edge crosses the plane, then orders the crossings CCW in the plane (same in-plane basis + diamond pseudo-angle as faceOrdered). This never relies on face watertightness, so it tiles a cross-section exactly where a face-by-face slice drops facets. Coordinates are in the cell's own frame (dual-vertex frame, i.e. seed-relative). Returns the vertex count m (0 or <3 if the plane misses/grazes the cell; -1 on MAXSV overflow — caller skips).

◆ volume()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::volume ( ) const
inline

Cell volume (G1): V = (1/3) Σ_faces support_k · area_k. Seed (origin) is interior so every support distance is positive.

◆ volumePerVertex()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
KOKKOS_INLINE_FUNCTION Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::volumePerVertex ( ) const
inline

Cell volume (G1) by the vertex-local flag/divergence sum — NO ordering, NO adjacency, NO atan2, NO findSharing. One pass over vertices; each contributes 3 signed determinants.

◆ xprod()

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
static KOKKOS_INLINE_FUNCTION void peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::xprod ( const Real  a[3],
const Real  b[3],
Real  o[3] 
)
inlinestatic

Member Data Documentation

◆ adj

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
Kokkos::Array<int, (TrackAdj ? MAXT : 0) * 3> peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::adj

Per-triangle edge adjacency, maintained incrementally in clip when TrackAdj — the input to the O(nt) Lawson local-convexity certificate (isLocallyConvex). Zero-footprint when !TrackAdj (Kokkos::Array<int,0> is the intended empty case, so sizeof(ConvexCell<...,false>) is unchanged). adj[t*3 + e] = index of the live triangle sharing edge-slot e of triangle t. Edge-slot convention (must match findSharing / fan enumeration): slot 0 = edge {vtx0, vtx1}, slot 1 = edge {vtx1, vtx2}, slot 2 = edge {vtx2, vtx0}, where (vtx0,vtx1,vtx2) = (t0[t], t1[t], t2[t]). The cell surface is a closed triangulation (topological sphere), so every edge is shared by exactly two live triangles; adj entries for live triangles are never -1 in a valid state. Killed triangles keep stale adj (they are alive==false, so the oracle ignores them and clip never follows into them).

◆ alive

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::alive[MAXT]

triangle live flag

◆ kTrackAdj

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
constexpr bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::kTrackAdj
staticconstexpr
Initial value:
=
TrackAdj

lets templated consumers (store save/load) branch at compile time

◆ MAXFV

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
constexpr int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::MAXFV = 28
staticconstexpr

◆ MAXSV

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
constexpr int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::MAXSV = 2 * MAXFV
staticconstexpr

max vertices on a cross-section polygon

◆ n

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::n[MAXP][3]

foot-point normal of each plane: half-space {x : n·x <= n·n}, so x=n is the foot of the perpendicular from the seed (origin) and |n| the seed->plane dist (= ½·(neighbour rel-pos) for Voronoi; the connector r = 2n).

◆ nn

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::nn[MAXP]

cached n·n, i.e. the half-space offset (so the cull test is n·x <= nn)

◆ np

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::np

number of planes

◆ nt

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::nt

triangle high-water mark

◆ overflow

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
bool peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::overflow

set if MAXP/MAXT exceeded -> cell invalid, caller falls back

◆ pnbr

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
int peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::pnbr[MAXP]

neighbour seed id per plane (<0 => bounding box)

◆ t0

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
unsigned char peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::t0[MAXT]

◆ t1

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
unsigned char peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::t1[MAXT]

◆ t2

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
unsigned char peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::t2[MAXT]

triangle = triple of plane indices

◆ vx

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::vx[MAXT]

◆ vy

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::vy[MAXT]

◆ vz

template<class Real , int MAXP = 64, int MAXT = 96, bool TrackAdj = false>
Real peclet::voro::ConvexCell< Real, MAXP, MAXT, TrackAdj >::vz[MAXT]

cached dual-vertex position per triangle


The documentation for this struct was generated from the following file: