peclet-dem 0.4.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
Loading...
Searching...
No Matches
peclet::dem Namespace Reference

Namespaces

namespace  detail
 
namespace  mldetail
 

Classes

struct  ContactC
 Portable mirror of ParticleSystem.cuh ContactConstraint (the fields this reduction touches). More...
 
struct  ContactHierarchy
 Host-side description of one built hierarchy (offsets into the packed group pools). More...
 
struct  CudaIterGraph
 
struct  Domain
 
struct  F3
 
struct  F4
 
struct  FusedLoopSpec
 Device-side iteration loop: run up to maxIters sweeps of the colour classes inside ONE kernel, evaluating the adaptive stop on-device (the same residual the host loop read back between launches — the readback round trip and the CUDA-graph capture disappear entirely). More...
 
struct  FusedSweepCtx
 Device-side context for a fused colour sweep: the colour offsets (numColors+1, uploaded from buildColorBucketsKokkos's host vector), the barrier counter, and the largest colour bucket (grid sizing). More...
 
struct  HertzMindlinLaw
 Hertz–Mindlin force-law policy (the first force law; see file comment). More...
 
struct  KE2
 Berendsen thermostat: reduce translational + rotational KE over real particles, compute the two scaling factors, and rescale linear/angular velocities. More...
 
struct  ManifoldC
 Portable mirror of ManifoldConstraint. More...
 
struct  MlCoarseSweep
 The per-manifold coarse-PGS body (translation-only, e = 0, shared fine accumulator) lives in MlCoarseSweep so the per-colour launch loop and the fused whole-cycle kernel share it verbatim. More...
 
struct  MlFusedCtx
 Fused-coarse-cycle context: flat per-level colour offsets on device + barrier + meta. More...
 
struct  MlFusedMeta
 Host-POD description of a built hierarchy for the fused coarse-cycle kernel (fixed-size arrays: kernel argument by value). More...
 
struct  MlScratch
 Device scratch for the multilevel pass, sized once (see Particles::allocate). More...
 
struct  Particles
 
struct  PGSManifoldSweep
 One full colored PGS sweep. More...
 
struct  PlaneP
 
struct  PositionContactSweep
 The per-contact overlap-projection body lives in PositionContactSweep so the colored launch loop and the fused colour sweep (solver_fused.hpp) share it verbatim: solveOne(idx) must only run concurrently on contacts that are body-disjoint within one launch (a colour class). More...
 
struct  ShapeDesc
 Portable mirror of ShapeDescriptor (analytic fields + a flat-array point shell). More...
 
class  Simulation
 Host-facing facade with std::vector setters/getters (binding-agnostic). More...
 
struct  SoloForceHooks
 Single-GPU hooks: no ghosts, reductions are already global. Everything inlines away. More...
 
struct  SoloSolveHooks
 Single-GPU hooks: no ghost refresh, residuals are already global. Everything inlines away. More...
 
struct  WallSdf
 Static, world-space SDF container/geometry the particles collide against (a drum barrel, a hopper, a vibrating tray, ...). More...
 

Typedefs

using BpExec = Kokkos::DefaultExecutionSpace
 
using BpMem = BpExec::memory_space
 
using CpExec = Kokkos::DefaultExecutionSpace
 
using CpMem = CpExec::memory_space
 
using V3 = Kokkos::View< float *[3], CpMem >
 
using V4 = Kokkos::View< float *[4], CpMem >
 
using Vf = Kokkos::View< float *, CpMem >
 
using Vi = Kokkos::View< int *, CpMem >
 
using PairTableView = Kokkos::View< const float *, CpMem >
 
using MatIdView = Kokkos::View< const unsigned char *, CpMem >
 
using PosView = Kokkos::View< const float *[3], CpMem >
 
using QuatView = Kokkos::View< const float *[4], CpMem >
 
using ScalarF = Kokkos::View< const float *, CpMem >
 
using ScalarI = Kokkos::View< const int *, CpMem >
 
using ShellView = Kokkos::View< const float *[3], CpMem >
 
using GridView = Kokkos::View< const float *, CpMem >
 
using FrManifoldCounts = Kokkos::View< float *[2], CpMem >
 

Enumerations

enum  ShapeKind { SHAPE_GRID_SDF = 0 , SPHERE = 1 , HOLLOW_CYLINDER = 2 , BOX = 3 }
 

Functions

template<class PosV , class RadV , class PairsV , class CountV >
int findCollisionsArborX (PosV pos, RadV rad, int numParticles, int numReal, float margin, PairsV outPairs, CountV outCount, float boxCap=0.0f)
 Emit candidate collision pairs (i<j) for real particles into outPairs/outCount.
 
unsigned long long pairKeyOf (const ManifoldC &m, Kokkos::View< const int *, CpMem > realIdx)
 Persistent-contact detection for the gravity-gated restitution rule.
 
void markPersistentManifoldsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > keyIdx, Kokkos::View< const unsigned long long *, CpMem > prevKeys, int prevCount, Kokkos::View< unsigned long long *, CpMem > outKeys, Kokkos::View< unsigned char *, CpMem > outFlags)
 keyIdx maps a body slot to the identity the pair key is built from: the REAL index map on the single-GPU path (stable within a run), or the GLOBAL particle id under MPI (stable across ranks, halo rebuilds and ownership migration — local slots are neither).
 
void gatherWarmLambdaKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > keyIdx, Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const float *, CpMem > prevLambda, Kokkos::View< const float *[3], CpMem > prevLambdaT, Kokkos::View< const float *, CpMem > prevPosImpulse, Kokkos::View< const float *, CpMem > prevRestBank, Kokkos::View< const float *, CpMem > prevRestVPeak, int prevCount, Kokkos::View< unsigned long long *, CpMem > outKeys, Kokkos::View< float *, CpMem > outWarm, Kokkos::View< float *[3], CpMem > outWarmT, Kokkos::View< float *, CpMem > outPosImpulse, Kokkos::View< float *, CpMem > outRestBank, Kokkos::View< float *, CpMem > outRestVPeak, Kokkos::View< unsigned char *, CpMem > outMatched={})
 Warm-start gather for the PGS velocity solve: per manifold, write its pair key and look up the previous substep's converged push impulse (0 for a new contact).
 
void commitPairKeysLambdaKokkos (Kokkos::View< const unsigned long long *, CpMem > keys, Kokkos::View< const float *, CpMem > lambda, Kokkos::View< const float *[3], CpMem > lambdaT, Kokkos::View< const float *, CpMem > restBank, Kokkos::View< const float *, CpMem > restVPeak, Kokkos::View< unsigned long long *, CpMem > prevKeys, Kokkos::View< float *, CpMem > prevLambda, Kokkos::View< float *[3], CpMem > prevLambdaT, Kokkos::View< float *, CpMem > prevRestBank, Kokkos::View< float *, CpMem > prevRestVPeak, Kokkos::View< int *, CpMem > perm, int numManifolds, Kokkos::View< const int *, CpMem > color={}, Kokkos::View< int *, CpMem > prevColor={})
 Save this substep's keys + converged impulses (normal AND tangential) and key-sort them for next substep's gather.
 
void commitPairKeysKokkos (Kokkos::View< const unsigned long long *, CpMem > keys, Kokkos::View< unsigned long long *, CpMem > prevKeys, int numManifolds)
 Copy this substep's keys into prevKeys and sort them for next substep's binary search.
 
void updateGroundedLevelsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *[3], CpMem > posPred, F3 gHat, Kokkos::View< unsigned char *, CpMem > grounded, int numReal, int sweeps, int decay)
 Guendelman support levels, warm-started: decay every body's level by decay, re-seed 255 at wall/plane contacts, then sweeps monotone propagation passes lower -> upper (255 -> 254 -> ...) through the manifold graph.
 
void computeHeightLevelsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *[3], CpMem > posPred, F3 gHat, Kokkos::View< int *, CpMem > heights, int numReal)
 
void buildColorBucketsKokkos (Kokkos::View< const int *, CpMem > colorOf, int n, int numColors, Kokkos::View< int *, CpMem > perm, Kokkos::View< int *, CpMem > cursor, std::vector< int > &offs)
 Dense colour buckets (numColors <= 64): perm[offs[c] .
 
long long colorKey (int idx)
 splitmix32 finalizer: a well-mixed pseudo-random priority per edge index.
 
std::uint64_t pairKey (const ContactC &c)
 Canonical pair key: (min<<32)|max, or (idA<<32)|0xFFFFFFFF for a boundary (idB<0) contact.
 
void decodeKey (std::uint64_t key, int &bodyA, int &bodyB)
 Decode the canonical (bodyA, bodyB) from a pair key (bodyB = -1 for boundary).
 
ManifoldC transformContact (const ContactC &c)
 Per-contact transform to a single-point manifold, aligned to the canonical pair.
 
int reduceContactsToManifoldsKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int n, Kokkos::View< ManifoldC *, CpMem > outManifolds, Kokkos::View< int, CpMem > outCount, Kokkos::View< int *, CpMem > contactSlot={})
 Reduce n contacts to manifolds (one per unique canonical pair).
 
void frictionBoundFromLambdaKokkos (Kokkos::View< ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const int *, CpMem > contactSlot, Kokkos::View< const ManifoldC *, CpMem > manifolds, Kokkos::View< const float *, CpMem > lambdaAcc)
 PGS friction bound: overwrite each contact's friction_lambda_n with its manifold's converged PGS push impulse (lambdaAcc, shared equally over the manifold's contact points).
 
void commitPosImpulseKokkos (Kokkos::View< const float *, CpMem > posLambdaContact, int numContacts, Kokkos::View< const int *, CpMem > contactSlot, Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const unsigned long long *, CpMem > keys, Kokkos::View< const unsigned long long *, CpMem > prevKeysSorted, int prevCount, float dt, Kokkos::View< float *, CpMem > scratchManifold, Kokkos::View< float *, CpMem > prevPosImpulse)
 After the position solve: convert the per-contact positional lambdas into an impulse- equivalent per manifold (lambda_pos / dt has force units; x dt back to impulse => just lambda_pos * m_eff... the positional lambda already carries 1/w mass weighting, so the impulse equivalent over the substep is lambda_pos / dt * dt = lambda_pos / (w*...) – we store lambda_pos/dt * dt = lambda_pos scaled by 1/dt to velocity-impulse units) and write it into the sorted prev-store so next substep's warm gather can top up the Coulomb bound.
 
F3 add3 (F3 a, F3 b)
 
F3 sub3 (F3 a, F3 b)
 
F3 scale3 (F3 a, float s)
 
float dot3 (F3 a, F3 b)
 
float len3 (F3 v)
 
F3 cross3v (F3 a, F3 b)
 
F4 cross3 (F4 a, F4 b)
 
template<class V >
F3 ldF3 (const V &v, int i)
 
template<class V >
F4 ldF4 (const V &v, int i)
 
F3 rotateVector (F4 q, F3 v)
 
F3 invRotateVector (F4 q, F3 v)
 
F4 quatInverse (F4 q)
 
F4 quatMult (F4 a, F4 b)
 
float sdfSphere (F3 p, F4 params)
 
float sdfHollowCylinder (F3 p, F4 params)
 
float sdfBox (F3 p, F4 params)
 
float sdfEval (F3 p, int type, F4 params)
 
void predictVelocityKokkos (int n, V3 pos, Vf invMass, V3 vel, V4 quat, V3 angVel, V3 invInertia, V3 posPred, V4 quatPred, V3 velPred, V3 angVelPred, V3 deltaPos, V4 deltaQuat, V3 deltaVel, V3 deltaAngVel, Vi constraintCounts, F3 gravity, float dt, V3 extForce)
 Predict velocity (gravity + gyroscopic precession), speculative position, and clear all deltas.
 
void applyVelocityDeltasKokkos (int n, V3 velPred, V3 angVelPred, V3 deltaVel, V3 deltaAngVel)
 Add accumulated velocity/angular deltas onto the predicted velocity, then clear the delta buffers.
 
void applyVelocityAndPredictPositionKokkos (int n, V3 pos, Vf invMass, V3 vel, V4 quat, V3 velPred, V3 angVelPred, V3 posPred, V4 quatPred, V3 angVel, float dt)
 Re-integration: persist solved velocity, trapezoidal position predict, quaternion integrate.
 
void computeContactCountsKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Vi constraintCounts)
 Per-contact constraint-count pre-pass (active contacts, dist <= 0).
 
void applyUpdatesKokkos (int n, V3 posPred, V3 velPred, V3 deltaPos, V3 deltaVel, Vi constraintCounts)
 Jacobi count-averaged apply of position/velocity deltas, then clear deltas + counts.
 
void finalCommitKokkos (int n, V3 pos, Vf invMass, V3 posPred, V4 quat, V4 quatPred, Domain dom)
 Final commit: periodic wrap of the predicted position into the domain, commit position + quat.
 
void applyThermostatKokkos (int numReal, V3 vel, Vf invMass, V3 angVel, V3 invInertia, V4 quat, double kB, double tau, double Ttarget, float dt)
 
void updateGrowthScalesKokkos (int n, Vf scale, Vf targetScale, float factor)
 Growth mode: scale = target * factor (when active).
 
void writeLammpsDump (const std::string &filename, int step, const std::vector< float > &pos, const std::vector< float > &vel, const std::vector< float > &quat, const std::vector< float > &radii, const float *boxMin, const float *boxMax, bool pbcEnabled)
 
void writeSdfVti (const std::string &filename, const std::vector< float > &grid, int rx, int ry, int rz, const float *minB, const float *maxB)
 
F3 loadF3 (PosView v, int i)
 
F4 loadF4 (QuatView v, int i)
 
float sampleGridSdf (F3 p, const ShapeDesc &d, GridView grid)
 Trilinearly sample an imported grid SDF at canonical point p.
 
float sampleWallSdf (F3 p, const WallSdf &w, GridView grid)
 Trilinearly sample a static world-space wall SDF at world point p.
 
float sdfEvalShape (F3 p, const ShapeDesc &d, GridView grid)
 Canonical-space SDF of a shape: analytic dispatch, or a trilinear grid sample for an imported grid SDF.
 
void detectContactsKokkos (Kokkos::View< const int *[2], CpMem > pairs, int numPairs, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, float globalScale, float margin, Kokkos::View< ContactC *, CpMem > outContacts, Kokkos::View< int, CpMem > outCount, Kokkos::View< float, CpMem > maxOverlap, GridView sdfGrid=GridView{}, MatIdView matId=MatIdView{}, PairTableView pairTable=PairTableView{})
 Pair point-shell vs SDF contacts.
 
void detectWallSdfKokkos (int numReal, int numWalls, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, Kokkos::View< const WallSdf *, CpMem > walls, GridView wallGrid, float globalScale, float margin, Kokkos::View< ContactC *, CpMem > outContacts, Kokkos::View< int, CpMem > outCount, Kokkos::View< float, CpMem > maxOverlap, MatIdView matId=MatIdView{}, PairTableView pairTable=PairTableView{})
 Per-real-particle contacts against a static world-space wall SDF set (a drum barrel, hopper, vibrating tray, ...).
 
void detectBoundaryKokkos (int numReal, int numPlanes, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, Kokkos::View< const PlaneP *, CpMem > planes, float globalScale, float margin, Kokkos::View< ContactC *, CpMem > outContacts, Kokkos::View< int, CpMem > outCount, Kokkos::View< float, CpMem > maxOverlap)
 Per-real-particle contacts against explicit planes (point-shell shapes test each surface point; analytic spheres use centre-minus-radius).
 
std::vector< float > generateSdfKokkos (int rx, int ry, int rz, F3 dmin, F3 dmax, int numReal, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, bool px, bool py, bool pz, GridView sdfGrid=GridView{})
 
int calculateGhostCapacity (int nReal, Domain dom, float skin)
 Padded particle-array capacity that leaves room for the periodic ghosts generateGhostsKokkos will emit: the real count plus an estimate of the boundary-shell ghost population, gated on which axes are actually periodic.
 
void generateGhostsKokkos (int numReal, int capacity, Domain dom, float skin, V3 pos, Vf invMass, V3 posPred, V3 vel, V3 velPred, V4 quat, V4 quatPred, V3 angVel, V3 angVelPred, Vf scale, Vi shapeId, Vi realIndices, Kokkos::View< int, CpMem > topGhost, Vi gid=Vi{}, Kokkos::View< unsigned char *, CpMem > materialId={})
 Generate periodic ghosts for particles [0,numReal).
 
std::vector< F3genCylinderShell (float radius, float height, float thickness, float spacing)
 
std::vector< F3genBoxShell (float hx, float hy, float hz, float spacing)
 
void demStep (Particles &P)
 One full XPBD DEM substep over the particle SoA (mirrors simulation.cpp Simulation::step()).
 
float computeOverlapsKokkos (Particles &P)
 Max pair interpenetration on the committed state (faithful to CUDA Simulation::compute_overlaps): copy committed pos/quat into the predicted buffers, regenerate the periodic ghosts from that state, then run the same broad/narrow phase as demStep and return the recorded max overlap.
 
void freezeAsleepKokkos (int numReal, Kokkos::View< const unsigned char *, CpMem > asleep, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > posPred, Kokkos::View< float *[4], CpMem > quatPred, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred)
 After predictVelocity: re-freeze the currently-asleep bodies so gravity/prediction do not move them — velPred = angVelPred = 0, posPred = pos, quatPred = quat.
 
void buildInvMassEffKokkos (int numBodies, Kokkos::View< const unsigned char *, CpMem > asleep, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *, CpMem > invMassEff, float sleeperFrac)
 Effective inverse mass for the solve: a sleeping body (real, or a periodic ghost whose real is asleep) is immovable — invMassEff = 0.
 
void computeManifoldSleepKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const unsigned char *, CpMem > asleep, Kokkos::View< unsigned char *, CpMem > manifoldSleep)
 Per-manifold "both endpoints asleep" flag (a static wall, bodyB < 0, counts as asleep).
 
void computeContactSleepKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const unsigned char *, CpMem > asleep, Kokkos::View< unsigned char *, CpMem > contactSleep)
 Per-contact twin of computeManifoldSleepKokkos for the position colouring.
 
void wakeDisturbedKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *[3], CpMem > velPred, float wakeSpeed, Kokkos::View< unsigned char *, CpMem > asleep, Kokkos::View< unsigned char *, CpMem > sleepCounter, Kokkos::View< unsigned char *, CpMem > movingWall, Kokkos::View< int *, CpMem > curCount, int numReal)
 Wake pass (before the solve): a sleeper is woken when actually disturbed.
 
void wakeContactChangeKokkos (int numReal, Kokkos::View< const int *, CpMem > curCount, Kokkos::View< int *, CpMem > prevCount, Kokkos::View< const unsigned char *, CpMem > movingWall, Kokkos::View< unsigned char *, CpMem > asleep, Kokkos::View< unsigned char *, CpMem > sleepCounter, bool wakeOnChange)
 Contact-set-change wake rule (b): wake any still-asleep body whose live contact count differs from the stored one (a support gained or lost), then refresh the store.
 
void updateSleepKokkos (int numReal, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > rad, Kokkos::View< const unsigned char *, CpMem > grounded, Kokkos::View< const unsigned char *, CpMem > movingWall, Kokkos::View< unsigned char *, CpMem > asleep, Kokkos::View< unsigned char *, CpMem > sleepCounter, float sleepSpeed, int K, Kokkos::View< float *[3], CpMem > velOut, Kokkos::View< float *[3], CpMem > angVelOut)
 Sleep detection (after the commit): an AWAKE, grounded body whose linear AND angular motion has stayed below sleepSpeed for K consecutive substeps is put to sleep (velocity + spin zeroed).
 
int readInt (Kokkos::View< int, CpMem > v)
 
float readFloat (Kokkos::View< float, CpMem > v)
 
void fillGidBaseKokkos (Vi gid, int n, int base)
 gid(i) = base + i over [0, n) — the per-rank global-id re-base of the distributed step (namespace scope: nvcc forbids KOKKOS_LAMBDA in member functions).
 
float maxOwnedRadius (const Particles &P)
 Largest effective particle radius over the owned set (= max scale × globalScale, growth included).
 
int findCollisionsGrow (Particles &P, float margin)
 Broad phase with an automatically-grown pair buffer.
 
int findCollisionsVerlet (Particles &P, float margin, float maxRad)
 Verlet-cached impulse broadphase (single-GPU, non-periodic).
 
template<class Hooks >
void demSolveContacts (Particles &P, int nc, int nm, int nBodies, Kokkos::View< const int *, CpMem > keyIdx, const Hooks &hooks)
 One full velocity + position contact solve over the already-built contacts/manifolds (see file comment).
 
void hertzRebuildPairs (Particles &P, float skin)
 Rebuild the Hertz cached pair list with margin skin, carrying the Mindlin shear history across by pair key (permutation sort of the OLD list, binary search from the NEW).
 
void hertzCommitHistory (Particles &P)
 Save the current list (sorted by key) so the NEXT rebuild can carry the history.
 
void zeroForceScratchKokkos (V3 dv, V3 dw, int lo, int hi)
 Zero the force/torque accumulator rows [lo, hi) — under MPI the pair kernels atomically accumulate onto ghost slots too (Newton's third law), but only owned rows are consumed and cleared by the integrator; without this the ghost rows grow without bound.
 
void fillWorldRadiiKokkos (Vf scale, Vf rad, float gs, float bR, int n)
 World radii rad(i) = scale(i) * globalScale * baseRadius over [0, n) (n = owned + ghosts after a halo gather; the driver's own preamble fills the owned span).
 
template<class Law , class Hooks >
void demStepForce (Particles &P, float dt, int nsteps, float skinFrac, const Law &law, const Hooks &hooks)
 nsteps explicit force-based DEM steps of size dt with force law Law (see file comment).
 
void demStepHertz (Particles &P, float dt, int nsteps, float skinFrac)
 nsteps of the soft-sphere Hertz-Mindlin engine — the single-GPU instantiation of the force-based driver (kept as the historical entry point; see demStepForce).
 
void accumulateNormalImpulseKokkos (Kokkos::View< ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate)
 Force-chain normal load, accumulated over the velocity iterations: contacts(idx).friction_lambda_n += approach / w_n.
 
void computePlaneLoadKokkos (Kokkos::View< ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, FrManifoldCounts planeFriction)
 Plane (idB<0) one-shot loads.
 
void countFrictionContactsKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const int *, CpMem > realIdx, FrManifoldCounts planeFriction)
 Per-body active-contact count into planeFriction(:,1).
 
void solveContactFrictionKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, FrManifoldCounts planeFriction, float frictionDynamic, Kokkos::View< float *[3], CpMem > deltaVel, Kokkos::View< float *[3], CpMem > deltaAngVel)
 One count-averaged Coulomb friction sweep.
 
bool demFusedWanted (bool graphReplayAvailable)
 Fused-sweep policy (read once).
 
FusedSweepCtx demMakeFusedCtx (CpExec &space, const std::vector< int > &offs, Kokkos::View< int *, CpMem > offsDev, Kokkos::View< unsigned *, CpMem > bar)
 Fill a FusedSweepCtx from buildColorBucketsKokkos's host offsets: async-upload them into the pooled device view and record the largest bucket.
 
void hertzPairEMu (int matA, int matB, PairTableView pairTable, float eGlobal, float muGlobal, float &e, float &mu)
 Pairwise (e, mu) lookup shared with the narrowphase convention: pair table if present, global fallback otherwise.
 
float hertzBetaD (float e)
 Restitution -> damping ratio beta_d = ln e / sqrt(ln^2 e + pi^2) (e in (0, 1]; e <= 0 -> -1, the critically-damped limit used by LIGGGHTS for e -> 0).
 
F3 hertzForce (float delta, F3 nhat, F3 vrel, float rStar, float mStar, float eStar, float gStar, float e, float mu, float dt, F3 &xi)
 One Hertz–Mindlin force evaluation for a sphere-sphere or sphere-wall contact.
 
void hertzPairForcesKokkos (Kokkos::View< const int *[2], CpMem > pairs, int numPairs, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > rad, Kokkos::View< const float *, CpMem > invMass, MatIdView matId, PairTableView pairTable, float eGlobal, float muGlobal, Kokkos::View< const float *, CpMem > hertzE, Kokkos::View< const float *, CpMem > hertzNu, float dt, Kokkos::View< float *[3], CpMem > xi, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque)
 Cached-pair forces: overlap from current positions; history resets when a cached pair is currently separated.
 
void hertzWallForcesKokkos (Kokkos::View< const int *, CpMem > candSlots, int numCand, Kokkos::View< const WallSdf *, CpMem > walls, GridView wallGrid, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > rad, Kokkos::View< const float *, CpMem > invMass, MatIdView matId, PairTableView pairTable, float eGlobal, float muGlobal, Kokkos::View< const float *, CpMem > hertzE, Kokkos::View< const float *, CpMem > hertzNu, float dt, Kokkos::View< float *[3], CpMem > xiWall, int maxWalls, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque, Kokkos::View< const float *[4], CpMem > quat={}, Kokkos::View< const float *, CpMem > scale={}, ScalarI shapeId={}, Kokkos::View< const ShapeDesc *, CpMem > shapes={}, ShellView shell={}, float globalScale=1.0f, float contactRadiusFrac=0.5f, bool hasShapes=false, Kokkos::View< float *, CpMem > snWall={})
 SDF-wall forces (per particle x wall).
 
int hertzBuildWallCandidatesKokkos (int numReal, int numWalls, Kokkos::View< const WallSdf *, CpMem > walls, GridView wallGrid, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *, CpMem > rad, float skin, Kokkos::View< int *, CpMem > outSlots, Kokkos::View< int, CpMem > outCount)
 Build the wall candidate list: particles within (radius + skin) of any wall's zero level.
 
void hertzIntegrateKokkos (int numReal, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, F3 gravity, float dt, Kokkos::View< float *[3], CpMem > vel, Kokkos::View< float *[3], CpMem > angVel, Kokkos::View< float *[3], CpMem > pos, Kokkos::View< float *[4], CpMem > quat={}, bool integrateOrientation=false)
 Symplectic-Euler kick-drift (MUSEN-style) + displacement tracking for the Verlet rebuild.
 
float hertzMaxDisp2Kokkos (int numReal, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[3], CpMem > refPos)
 Max squared displacement since the last pair build (called only at rebuild checks – keeping this out of the integrate kernel avoids a per-step single-address atomic).
 
void hertzShapePairForcesKokkos (Kokkos::View< const int *[2], CpMem > pairs, int numPairs, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, GridView sdfGrid, float globalScale, float contactRadiusFrac, Kokkos::View< const float *, CpMem > invMass, MatIdView matId, PairTableView pairTable, float eGlobal, float muGlobal, Kokkos::View< const float *, CpMem > hertzE, Kokkos::View< const float *, CpMem > hertzNu, float dt, Kokkos::View< float *[3], CpMem > xi, Kokkos::View< float *, CpMem > snPrev, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque)
 Non-spherical pairs: per-point Hertz springs over A's point shell against B's SDF (the same one-sided sampling convention as the narrowphase), ONE Mindlin patch history per pair.
 
ContactHierarchy buildContactHierarchyKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > mColor, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const float *[3], CpMem > vt0, Kokkos::View< const unsigned char *, CpMem > persistent, Kokkos::View< const float *[3], CpMem > posPred, F3 gHat, Kokkos::View< const float *, CpMem > invMass, float qsThr, int gateMask, int numReal, MlScratch &S, Kokkos::View< long long *, CpMem > winner, Kokkos::View< std::uint64_t *, CpMem > colorMask, bool excludeImmovable=false, Kokkos::View< const unsigned char *, CpMem > asleep={})
 Build the aggregation hierarchy + per-level crossing-manifold colorings.
 
void buildCoarseBucketsKokkos (const ContactHierarchy &H, MlScratch &S, int numManifolds, Kokkos::View< int *, CpMem > colorScratch, Kokkos::View< int *, CpMem > perm, Kokkos::View< int *, CpMem > cursor, std::vector< std::vector< int > > &offs)
 One multilevel stabilization cycle over an already-built hierarchy: fine colored smoothing is the caller's business; this runs the coarse leg (fine -> coarse), updating velPred in place.
 
MlFusedCtx demMakeMlFusedCtx (CpExec &space, const ContactHierarchy &H, const std::vector< std::vector< int > > &bkOffs, int numManifolds, int numReal, int coarseSweeps, Kokkos::View< int *, CpMem > offsDev, Kokkos::View< unsigned *, CpMem > bar)
 Build the fused-coarse-cycle context from an already-built hierarchy + its dense buckets: flatten the per-level colour offsets into the pooled device view (async upload) and record the grid-sizing work bound.
 
void multilevelCoarseCycleKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< float, CpMem > maxApproach, int numReal, const ContactHierarchy &H, MlScratch &S, int coarseSweeps, Kokkos::View< const float *, CpMem > restRel={}, const std::vector< std::vector< int > > *bkOffs=nullptr, Kokkos::View< const int *, CpMem > bkPerm={}, const MlFusedCtx *fused=nullptr)
 
void solvePositionKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > posPred, Kokkos::View< const float *[4], CpMem > quatPred, Kokkos::View< const float *[4], CpMem > quatStatic, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< float *[3], CpMem > deltaPos, Kokkos::View< float *[4], CpMem > deltaQuat, Kokkos::View< int *, CpMem > constraintCounts, Kokkos::View< float, CpMem > maxOverlap, Kokkos::View< const int *, CpMem > onlyColor={}, int colorFilter=0)
 Accumulate XPBD position corrections for numContacts contacts.
 
int colorContactsKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, int numBodies, Kokkos::View< int *, CpMem > cColor, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
 Greedy graph-colour the contacts (raw bodyA/bodyB): no two contacts sharing a body get the same colour.
 
int colorContactsIncrementalKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, int numBodies, Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const int *, CpMem > prevColor, int prevCount, Kokkos::View< int *, CpMem > cColor, Kokkos::View< unsigned long long *, CpMem > keysOut, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, bool forceFull, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
 Incremental (warm-started) contact colouring for the single-GPU PGS position solve.
 
void commitContactColorKokkos (Kokkos::View< const unsigned long long *, CpMem > keys, Kokkos::View< const int *, CpMem > color, Kokkos::View< unsigned long long *, CpMem > prevKeys, Kokkos::View< int *, CpMem > prevColor, Kokkos::View< int *, CpMem > perm, int numContacts)
 Commit this substep's per-contact (key, colour) sorted by key, for next substep's warm gather.
 
bool solvePositionColoredGSKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const int *, CpMem > cColor, int numColors, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *[3], CpMem > posPred, Kokkos::View< const float *[4], CpMem > quatPred, Kokkos::View< const float *[4], CpMem > quatStatic, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< float, CpMem > maxOverlap, Kokkos::View< float *, CpMem > posLambdaAcc={}, Kokkos::View< const int *, CpMem > colorPerm={}, const std::vector< int > *colorOffs=nullptr, const FusedSweepCtx *fused=nullptr, const FusedLoopSpec *loop=nullptr)
 Colored Gauss–Seidel XPBD overlap solve: sweep the numColors colour classes in order, applying each contact's non-penetration correction directly to posPred (in place, translation only).
 
void solveVelocityKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float *[3], CpMem > deltaVel, Kokkos::View< float *[3], CpMem > deltaAngVel, Kokkos::View< int *, CpMem > velCounts, Kokkos::View< const int *, CpMem > onlyColor={}, int colorFilter=0, Kokkos::View< const unsigned char *, CpMem > persistent={}, Kokkos::View< const float *[3], CpMem > posPred={}, F3 gHat={}, Kokkos::View< const unsigned char *, CpMem > grounded={})
 Accumulate normal-restitution velocity deltas for numManifolds manifolds.
 
template<class V3 , class Vi >
void applyVelocityDeltasAveragedKokkos (int n, V3 velPred, V3 angVelPred, V3 deltaVel, V3 deltaAngVel, Vi velCounts)
 Apply the accumulated velocity deltas AVERAGED by the per-body manifold count — the velocity- solve twin of the position solve's constraint-count averaging (applyUpdatesKokkos).
 
int colorManifoldsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, int numReal, Kokkos::View< int *, CpMem > mColor, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
 Greedy graph-colour the manifolds: no two manifolds sharing a real body get the same colour.
 
int colorManifoldsIncrementalKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, int numReal, Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const int *, CpMem > prevColor, int prevCount, Kokkos::View< int *, CpMem > mColor, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, bool forceFull, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
 Incremental (warm-started) manifold colouring for the single-GPU PGS path.
 
void computeVn0Kokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, Kokkos::View< float *, CpMem > vn0, Kokkos::View< float *[3], CpMem > vt0)
 -— Warm-started projected Gauss-Seidel (PGS) velocity solve -— Nonsmooth contact dynamics (Moreau-Jean; Stewart-Trinkle LCP): per manifold an ACCUMULATED push impulse p >= 0 along the manifold normal, updated by colored GS sweeps and projected to p >= 0 (a contact may push, never pull; over-push is retracted in later sweeps).
 
void updateRestitutionBankKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const float *, CpMem > lambdaAcc, Kokkos::View< const float *, CpMem > restRel, Kokkos::View< float *, CpMem > restBank, Kokkos::View< float *, CpMem > restVPeak)
 Event-level (Poisson) restitution bookkeeping, once per substep AFTER all velocity phases (restitutionModel == 1 only).
 
void decayBodyOrphanKokkos (Kokkos::View< float *, CpMem > orphan, Kokkos::View< float *, CpMem > orphanVPeak, int numOwned, float restVelThreshold)
 Orphan-account aging, once per substep over the OWNED bodies: both the balance and the carried event peak decay 1/64 per substep (e-fold ~3 ms at dt = 5e-5 — long enough for the rebound payout, which completes within ~2 ms of turnaround, short enough that a BURIED impactor's slowly re-fed credit cannot keep fluidizing its crater: with the pair-state 1/256 decay the 100k Dosta plateau crept 0.007 deeper), and once the peak ages below the resting threshold the whole account evaporates — stranded credit on a settling body never pops the pile later.
 
void scatterOrphanBanksKokkos (Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const float *, CpMem > prevRestBank, Kokkos::View< const float *, CpMem > prevRestVPeak, Kokkos::View< const unsigned char *, CpMem > matched, int prevCount, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *, CpMem > orphan, Kokkos::View< float *, CpMem > orphanVPeak, Kokkos::View< const int *, CpMem > gidSorted={}, Kokkos::View< const int *, CpMem > slotSorted={})
 Orphan transfer: previous-ledger entries NOT matched by any current manifold (their pair died this substep) credit their remaining owed budget to the endpoint BODIES, mass-weighted — the heavier endpoint keeps the larger share (energy of a later release scales J^2/2m, so the light grain is the dangerous store and the heavy impactor is both the safe one and the event's physical carrier); boundary pairs (wall endpoint) credit everything to the particle.
 
std::tuple< double, float, int > restBankStatsKokkos (Kokkos::View< const float *, CpMem > bank, int n)
 Poisson-restitution diagnostics: (sum, max, count>0) over the committed owed-impulse store (namespace scope: nvcc forbids KOKKOS_LAMBDA in member functions).
 
void computeSideFlagsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const unsigned char *, CpMem > persistent, Kokkos::View< const unsigned char *, CpMem > grounded, Kokkos::View< const float *[3], CpMem > posPred, Kokkos::View< const float *[3], CpMem > velPred, F3 gHat, float riseThr, Kokkos::View< unsigned char *, CpMem > sideFlag, Kokkos::View< const float *, CpMem > vn0, float approachThr)
 Decide each persistent contact's treatment ONCE per substep (before any impulse is applied): 0 = symmetric momentum-conserving PGS, 1 = one-sided with B as the held ground side, 2 = A held.
 
void warmStartApplyKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *, CpMem > warmP, Kokkos::View< float *[3], CpMem > warmT)
 Apply the warm-start impulses up front (order-independent: fixed impulses, atomic adds).
 
PGSManifoldSweep makePGSManifoldSweep (Kokkos::View< const ManifoldC *, CpMem > manifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< float, CpMem > maxApproachQS, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const unsigned char *, CpMem > sideFlag, Kokkos::View< float *[3], CpMem > lambdaT, float frictionDynamic, Kokkos::View< const float *[3], CpMem > vt0, float restitutionTangent, Kokkos::View< const float *, CpMem > posImpulse, Kokkos::View< float *, CpMem > restBank, Kokkos::View< float *, CpMem > restRel, Kokkos::View< const unsigned char *, CpMem > restPersistent, Kokkos::View< const float *, CpMem > restVPeak, F3 restGHat, Kokkos::View< const unsigned char *, CpMem > restGrounded, bool restNewtonOff, bool restOneSided, Kokkos::View< float *, CpMem > restOrphan, Kokkos::View< const float *, CpMem > restOrphanVPeak)
 Build the shared per-manifold sweep functor (the colored launch loop, the fused kernels and the fused multilevel iteration loop all run this one body).
 
bool solveVelocityPGSKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > mColor, int numColors, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const unsigned char *, CpMem > sideFlag, Kokkos::View< float *[3], CpMem > lambdaT, float frictionDynamic, Kokkos::View< const float *[3], CpMem > vt0={}, float restitutionTangent=0.0f, Kokkos::View< const float *, CpMem > posImpulse={}, Kokkos::View< float, CpMem > maxApproachQS={}, Kokkos::View< float *, CpMem > restBank={}, Kokkos::View< float *, CpMem > restRel={}, Kokkos::View< const unsigned char *, CpMem > restPersistent={}, Kokkos::View< const float *, CpMem > restVPeak={}, F3 restGHat={}, Kokkos::View< const unsigned char *, CpMem > restGrounded={}, bool restNewtonOff=false, bool restOneSided=false, Kokkos::View< float *, CpMem > restOrphan={}, Kokkos::View< const float *, CpMem > restOrphanVPeak={}, Kokkos::View< const int *, CpMem > colorPerm={}, const std::vector< int > *colorOffs=nullptr, const FusedSweepCtx *fused=nullptr, const FusedLoopSpec *loop=nullptr)
 Returns true when the sweep (or, with loop, the whole iteration loop) was submitted; false ONLY in loop mode when the fused path is unavailable — the caller then runs its own host-side iteration loop (which calls back in per-iteration mode).
 
void buildLevelColorBucketsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > mColor, Kokkos::View< const int *, CpMem > heights, Kokkos::View< int *, CpMem > keys, Kokkos::View< int *, CpMem > perm, std::vector< std::pair< int, int > > &buckets)
 Bucket the active coloured manifolds by (support level, colour) for the level-ordered ("multilevel") stabilization sweeps.
 
void solveVelocityPGSBucketsKokkos (const PGSManifoldSweep &f, Kokkos::View< const int *, CpMem > perm, const std::vector< std::pair< int, int > > &buckets, bool topDown)
 Level-ordered symmetric sweep: launch one PGS kernel per (level, colour) bucket, ascending (bottom-up: a chain's load drains towards the floor in ~one pass) or descending (top-down: the return pass carries rebound waves back up).
 
void solveVelocityColoredGSKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > mColor, int numColors, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< const unsigned char *, CpMem > persistent={}, Kokkos::View< const float *[3], CpMem > posPred={}, F3 gHat={}, Kokkos::View< const unsigned char *, CpMem > grounded={})
 Colored Gauss–Seidel normal-restitution solve: sweep the numColors colour classes in order, applying each manifold's impulse directly to velPred/angVelPred (in place).
 

Variables

constexpr int kLevelInf = 1 << 28
 Height-from-floor BFS levels for the level-ordered ("multilevel") stabilization pass: 0 at a wall/plane contact, else 1 + min over supporting contacts, kLevelInf with no contact path to the floor.
 
constexpr int kMaxMaterials = 8
 Pair-material lookup: flat [K*K*2] table, entry ((a*K + b)*2) = restitution, +1 = friction.
 
constexpr int kMlMaxLevels = 10
 6-bit colour slots per level in the packed word; slot value 63 = not crossing / not eligible at that level (skipped by the coarse sweeps).
 
constexpr int kMlSlotSkip = 63
 

Typedef Documentation

◆ BpExec

using peclet::dem::BpExec = typedef Kokkos::DefaultExecutionSpace

Definition at line 21 of file broadphase_arborx.hpp.

◆ BpMem

using peclet::dem::BpMem = typedef BpExec::memory_space

Definition at line 22 of file broadphase_arborx.hpp.

◆ CpExec

using peclet::dem::CpExec = typedef Kokkos::DefaultExecutionSpace

Definition at line 27 of file contact_preprocessing.hpp.

◆ CpMem

using peclet::dem::CpMem = typedef CpExec::memory_space

Definition at line 28 of file contact_preprocessing.hpp.

◆ V3

using peclet::dem::V3 = typedef Kokkos::View<float* [3], CpMem>

Definition at line 24 of file integration.hpp.

◆ V4

using peclet::dem::V4 = typedef Kokkos::View<float* [4], CpMem>

Definition at line 25 of file integration.hpp.

◆ Vf

using peclet::dem::Vf = typedef Kokkos::View<float*, CpMem>

Definition at line 26 of file integration.hpp.

◆ Vi

using peclet::dem::Vi = typedef Kokkos::View<int*, CpMem>

Definition at line 27 of file integration.hpp.

◆ PairTableView

using peclet::dem::PairTableView = typedef Kokkos::View<const float*, CpMem>

Definition at line 80 of file narrowphase.hpp.

◆ MatIdView

using peclet::dem::MatIdView = typedef Kokkos::View<const unsigned char*, CpMem>

Definition at line 81 of file narrowphase.hpp.

◆ PosView

using peclet::dem::PosView = typedef Kokkos::View<const float* [3], CpMem>

Definition at line 84 of file narrowphase.hpp.

◆ QuatView

using peclet::dem::QuatView = typedef Kokkos::View<const float* [4], CpMem>

Definition at line 85 of file narrowphase.hpp.

◆ ScalarF

using peclet::dem::ScalarF = typedef Kokkos::View<const float*, CpMem>

Definition at line 86 of file narrowphase.hpp.

◆ ScalarI

using peclet::dem::ScalarI = typedef Kokkos::View<const int*, CpMem>

Definition at line 87 of file narrowphase.hpp.

◆ ShellView

using peclet::dem::ShellView = typedef Kokkos::View<const float* [3], CpMem>

Definition at line 88 of file narrowphase.hpp.

◆ GridView

using peclet::dem::GridView = typedef Kokkos::View<const float*, CpMem>

Definition at line 89 of file narrowphase.hpp.

◆ FrManifoldCounts

using peclet::dem::FrManifoldCounts = typedef Kokkos::View<float* [2], CpMem>

Definition at line 25 of file solver_friction.hpp.

Enumeration Type Documentation

◆ ShapeKind

Enumerator
SHAPE_GRID_SDF 
SPHERE 
HOLLOW_CYLINDER 
BOX 

Definition at line 77 of file dem_portable.hpp.

Function Documentation

◆ findCollisionsArborX()

template<class PosV , class RadV , class PairsV , class CountV >
int peclet::dem::findCollisionsArborX ( PosV  pos,
RadV  rad,
int  numParticles,
int  numReal,
float  margin,
PairsV  outPairs,
CountV  outCount,
float  boxCap = 0.0f 
)
inline

Emit candidate collision pairs (i<j) for real particles into outPairs/outCount.

pos[numParticles][3] positions of all particles (real first, then ghosts) rad[numParticles] effective radius per particle (scale * global_scale) numReal only particles [0,numReal) issue queries (own real particles) margin safety margin added to every box half-width (cuBQL uses 0.1*global_scale) outPairs[maxPairs][2] preallocated output; outCount is the (clamped) number found Returns the number of pairs found (may exceed maxPairs if the buffer is too small).

Definition at line 36 of file broadphase_arborx.hpp.

References PECLET_DEM_SANE_BOX.

Referenced by findCollisionsGrow().

◆ pairKeyOf()

unsigned long long peclet::dem::pairKeyOf ( const ManifoldC m,
Kokkos::View< const int *, CpMem realIdx 
)

Persistent-contact detection for the gravity-gated restitution rule.

Key = (min real body, max real body) packed in 64 bits; boundary manifolds (bodyB = -1: planes + SDF walls, merged per particle) use lo = 0xFFFFFFFF. Flags each manifold whose pair already existed in the PREVIOUS substep (prevKeys sorted, device binary search). Real indices are stable within a single-GPU run, so the key identifies the physical pair across substeps.

Definition at line 71 of file contact_preprocessing.hpp.

References peclet::dem::ManifoldC::bodyA, and peclet::dem::ManifoldC::bodyB.

Referenced by markPersistentManifoldsKokkos().

◆ markPersistentManifoldsKokkos()

void peclet::dem::markPersistentManifoldsKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const int *, CpMem keyIdx,
Kokkos::View< const unsigned long long *, CpMem prevKeys,
int  prevCount,
Kokkos::View< unsigned long long *, CpMem outKeys,
Kokkos::View< unsigned char *, CpMem outFlags 
)
inline

keyIdx maps a body slot to the identity the pair key is built from: the REAL index map on the single-GPU path (stable within a run), or the GLOBAL particle id under MPI (stable across ranks, halo rebuilds and ownership migration — local slots are neither).

Definition at line 82 of file contact_preprocessing.hpp.

References peclet::dem::ManifoldC::num_points, and pairKeyOf().

Referenced by demSolveContacts().

◆ gatherWarmLambdaKokkos()

void peclet::dem::gatherWarmLambdaKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const int *, CpMem keyIdx,
Kokkos::View< const unsigned long long *, CpMem prevKeys,
Kokkos::View< const float *, CpMem prevLambda,
Kokkos::View< const float *[3], CpMem prevLambdaT,
Kokkos::View< const float *, CpMem prevPosImpulse,
Kokkos::View< const float *, CpMem prevRestBank,
Kokkos::View< const float *, CpMem prevRestVPeak,
int  prevCount,
Kokkos::View< unsigned long long *, CpMem outKeys,
Kokkos::View< float *, CpMem outWarm,
Kokkos::View< float *[3], CpMem outWarmT,
Kokkos::View< float *, CpMem outPosImpulse,
Kokkos::View< float *, CpMem outRestBank,
Kokkos::View< float *, CpMem outRestVPeak,
Kokkos::View< unsigned char *, CpMem outMatched = {} 
)
inline

Warm-start gather for the PGS velocity solve: per manifold, write its pair key and look up the previous substep's converged push impulse (0 for a new contact).

Periodic-ghost duplicate manifolds (realA > realB twin) get key ~0 and warm 0 – the canonical twin carries the impulse. keyIdx: see markPersistentManifoldsKokkos (realIdx keeps the periodic-dedup role; keyIdx builds the cross-substep pair identity).

Definition at line 119 of file contact_preprocessing.hpp.

Referenced by demSolveContacts().

◆ commitPairKeysLambdaKokkos()

void peclet::dem::commitPairKeysLambdaKokkos ( Kokkos::View< const unsigned long long *, CpMem keys,
Kokkos::View< const float *, CpMem lambda,
Kokkos::View< const float *[3], CpMem lambdaT,
Kokkos::View< const float *, CpMem restBank,
Kokkos::View< const float *, CpMem restVPeak,
Kokkos::View< unsigned long long *, CpMem prevKeys,
Kokkos::View< float *, CpMem prevLambda,
Kokkos::View< float *[3], CpMem prevLambdaT,
Kokkos::View< float *, CpMem prevRestBank,
Kokkos::View< float *, CpMem prevRestVPeak,
Kokkos::View< int *, CpMem perm,
int  numManifolds,
Kokkos::View< const int *, CpMem color = {},
Kokkos::View< int *, CpMem prevColor = {} 
)
inline

Save this substep's keys + converged impulses (normal AND tangential) and key-sort them for next substep's gather.

A permutation sort carries both value arrays through one key sort.

Definition at line 172 of file contact_preprocessing.hpp.

Referenced by demSolveContacts().

◆ commitPairKeysKokkos()

void peclet::dem::commitPairKeysKokkos ( Kokkos::View< const unsigned long long *, CpMem keys,
Kokkos::View< unsigned long long *, CpMem prevKeys,
int  numManifolds 
)
inline

Copy this substep's keys into prevKeys and sort them for next substep's binary search.

Definition at line 220 of file contact_preprocessing.hpp.

◆ updateGroundedLevelsKokkos()

void peclet::dem::updateGroundedLevelsKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const float *[3], CpMem posPred,
F3  gHat,
Kokkos::View< unsigned char *, CpMem grounded,
int  numReal,
int  sweeps,
int  decay 
)
inline

Guendelman support levels, warm-started: decay every body's level by decay, re-seed 255 at wall/plane contacts, then sweeps monotone propagation passes lower -> upper (255 -> 254 -> ...) through the manifold graph.

Warm start makes a few sweeps per substep track slowly-moving support fronts; the decay retires groundedness ~32 substeps after lift-off. Geometry-only (no persistence / velocity condition): grounded means "has a contact path down to the floor".

Definition at line 238 of file contact_preprocessing.hpp.

References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, dot3(), ldF3(), peclet::dem::ManifoldC::num_points, sub3(), peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by demSolveContacts().

◆ computeHeightLevelsKokkos()

void peclet::dem::computeHeightLevelsKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const float *[3], CpMem posPred,
F3  gHat,
Kokkos::View< int *, CpMem heights,
int  numReal 
)
inline

◆ buildColorBucketsKokkos()

void peclet::dem::buildColorBucketsKokkos ( Kokkos::View< const int *, CpMem colorOf,
int  n,
int  numColors,
Kokkos::View< int *, CpMem perm,
Kokkos::View< int *, CpMem cursor,
std::vector< int > &  offs 
)
inline

Dense colour buckets (numColors <= 64): perm[offs[c] .

. offs[c+1]) lists the item indices of colour c. Histogram + host prefix + scatter — two small kernels and one 64-int readback, amortized over every sweep that would otherwise scan ALL n items per colour per iteration (measured 25k multilevel: the per-colour full scans were 40% of GPU time and the step is host-submission-bound). Within a colour the scatter order is arbitrary — colour classes are body-disjoint, so the sweep result is bit-identical. Items with colour < 0 (inactive, dups, mask-saturation leftovers) are excluded, exactly like the scan-mode colour filter.

Definition at line 338 of file contact_preprocessing.hpp.

Referenced by buildCoarseBucketsKokkos(), and demSolveContacts().

◆ colorKey()

long long peclet::dem::colorKey ( int  idx)

splitmix32 finalizer: a well-mixed pseudo-random priority per edge index.

Random priorities make the Jones-Plassmann arbitration finish in O(log n) rounds w.h.p.; RAW indices are adversarial for lattice-ordered dense packs (monotone index chains -> one win per round -> O(chain) rounds).

Definition at line 374 of file contact_preprocessing.hpp.

◆ pairKey()

std::uint64_t peclet::dem::pairKey ( const ContactC c)

Canonical pair key: (min<<32)|max, or (idA<<32)|0xFFFFFFFF for a boundary (idB<0) contact.

Definition at line 384 of file contact_preprocessing.hpp.

References peclet::dem::ContactC::bodyA, and peclet::dem::ContactC::bodyB.

◆ decodeKey()

void peclet::dem::decodeKey ( std::uint64_t  key,
int &  bodyA,
int &  bodyB 
)

Decode the canonical (bodyA, bodyB) from a pair key (bodyB = -1 for boundary).

Definition at line 394 of file contact_preprocessing.hpp.

◆ transformContact()

ManifoldC peclet::dem::transformContact ( const ContactC c)

Per-contact transform to a single-point manifold, aligned to the canonical pair.

Inactive contacts (dist > 0) contribute a zero manifold with num_points = 0. Mirrors ContactToManifold + TransformAndFilter from contact_preprocessing.cu.

Definition at line 403 of file contact_preprocessing.hpp.

References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, peclet::dem::ContactC::boundaryFriction, peclet::dem::ContactC::boundaryRestitution, peclet::dem::ContactC::boundaryVel, cross3(), peclet::dem::ContactC::dist, peclet::dem::ContactC::normal, peclet::dem::ContactC::rA, peclet::dem::ContactC::rB, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

◆ reduceContactsToManifoldsKokkos()

int peclet::dem::reduceContactsToManifoldsKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  n,
Kokkos::View< ManifoldC *, CpMem outManifolds,
Kokkos::View< int, CpMem outCount,
Kokkos::View< int *, CpMem contactSlot = {} 
)
inline

Reduce n contacts to manifolds (one per unique canonical pair).

outManifolds must hold at least the number of unique pairs; returns that count (also written to outCount).

Definition at line 442 of file contact_preprocessing.hpp.

Referenced by demStep().

◆ frictionBoundFromLambdaKokkos()

void peclet::dem::frictionBoundFromLambdaKokkos ( Kokkos::View< ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const int *, CpMem contactSlot,
Kokkos::View< const ManifoldC *, CpMem manifolds,
Kokkos::View< const float *, CpMem lambdaAcc 
)
inline

PGS friction bound: overwrite each contact's friction_lambda_n with its manifold's converged PGS push impulse (lambdaAcc, shared equally over the manifold's contact points).

The legacy accumulateNormalImpulse bound derives from approach velocities, which the PGS warm start has already cancelled – without this the Coulomb bound is ~0 and friction is inert.

Definition at line 541 of file contact_preprocessing.hpp.

References peclet::dem::ManifoldC::num_points.

◆ commitPosImpulseKokkos()

void peclet::dem::commitPosImpulseKokkos ( Kokkos::View< const float *, CpMem posLambdaContact,
int  numContacts,
Kokkos::View< const int *, CpMem contactSlot,
Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const unsigned long long *, CpMem keys,
Kokkos::View< const unsigned long long *, CpMem prevKeysSorted,
int  prevCount,
float  dt,
Kokkos::View< float *, CpMem scratchManifold,
Kokkos::View< float *, CpMem prevPosImpulse 
)
inline

After the position solve: convert the per-contact positional lambdas into an impulse- equivalent per manifold (lambda_pos / dt has force units; x dt back to impulse => just lambda_pos * m_eff... the positional lambda already carries 1/w mass weighting, so the impulse equivalent over the substep is lambda_pos / dt * dt = lambda_pos / (w*...) – we store lambda_pos/dt * dt = lambda_pos scaled by 1/dt to velocity-impulse units) and write it into the sorted prev-store so next substep's warm gather can top up the Coulomb bound.

Definition at line 563 of file contact_preprocessing.hpp.

Referenced by demSolveContacts().

◆ add3()

◆ sub3()

◆ scale3()

◆ dot3()

◆ len3()

float peclet::dem::len3 ( F3  v)

Definition at line 37 of file dem_portable.hpp.

References dot3().

Referenced by hertzShapePairForcesKokkos(), and sdfSphere().

◆ cross3v()

◆ cross3()

F4 peclet::dem::cross3 ( F4  a,
F4  b 
)

Definition at line 43 of file dem_portable.hpp.

References peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

Referenced by transformContact().

◆ ldF3()

◆ ldF4()

template<class V >
F4 peclet::dem::ldF4 ( const V &  v,
int  i 
)

◆ rotateVector()

◆ invRotateVector()

◆ quatInverse()

F4 peclet::dem::quatInverse ( F4  q)

◆ quatMult()

F4 peclet::dem::quatMult ( F4  a,
F4  b 
)

◆ sdfSphere()

float peclet::dem::sdfSphere ( F3  p,
F4  params 
)

Definition at line 79 of file dem_portable.hpp.

References len3(), and peclet::dem::F4::x.

Referenced by sdfEval().

◆ sdfHollowCylinder()

float peclet::dem::sdfHollowCylinder ( F3  p,
F4  params 
)

◆ sdfBox()

float peclet::dem::sdfBox ( F3  p,
F4  params 
)

◆ sdfEval()

float peclet::dem::sdfEval ( F3  p,
int  type,
F4  params 
)

Definition at line 105 of file dem_portable.hpp.

References BOX, HOLLOW_CYLINDER, sdfBox(), sdfHollowCylinder(), sdfSphere(), and SPHERE.

Referenced by sdfEvalShape().

◆ predictVelocityKokkos()

void peclet::dem::predictVelocityKokkos ( int  n,
V3  pos,
Vf  invMass,
V3  vel,
V4  quat,
V3  angVel,
V3  invInertia,
V3  posPred,
V4  quatPred,
V3  velPred,
V3  angVelPred,
V3  deltaPos,
V4  deltaQuat,
V3  deltaVel,
V3  deltaAngVel,
Vi  constraintCounts,
F3  gravity,
float  dt,
V3  extForce 
)
inline

Predict velocity (gravity + gyroscopic precession), speculative position, and clear all deltas.

Definition at line 44 of file integration.hpp.

References add3(), cross3v(), invRotateVector(), ldF3(), ldF4(), rotateVector(), scale3(), peclet::dem::detail::st3(), peclet::dem::detail::st4(), peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by demStep().

◆ applyVelocityDeltasKokkos()

void peclet::dem::applyVelocityDeltasKokkos ( int  n,
V3  velPred,
V3  angVelPred,
V3  deltaVel,
V3  deltaAngVel 
)
inline

Add accumulated velocity/angular deltas onto the predicted velocity, then clear the delta buffers.

Definition at line 97 of file integration.hpp.

References add3(), ldF3(), and peclet::dem::detail::st3().

Referenced by demSolveContacts().

◆ applyVelocityAndPredictPositionKokkos()

void peclet::dem::applyVelocityAndPredictPositionKokkos ( int  n,
V3  pos,
Vf  invMass,
V3  vel,
V4  quat,
V3  velPred,
V3  angVelPred,
V3  posPred,
V4  quatPred,
V3  angVel,
float  dt 
)
inline

Re-integration: persist solved velocity, trapezoidal position predict, quaternion integrate.

Definition at line 112 of file integration.hpp.

References add3(), ldF3(), ldF4(), scale3(), peclet::dem::detail::st3(), peclet::dem::detail::st4(), peclet::dem::F4::w, peclet::dem::F3::x, peclet::dem::F4::x, peclet::dem::F3::y, peclet::dem::F4::y, peclet::dem::F3::z, and peclet::dem::F4::z.

Referenced by demSolveContacts().

◆ computeContactCountsKokkos()

void peclet::dem::computeContactCountsKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
Vi  constraintCounts 
)
inline

Per-contact constraint-count pre-pass (active contacts, dist <= 0).

Definition at line 151 of file integration.hpp.

References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, and peclet::dem::ContactC::dist.

◆ applyUpdatesKokkos()

void peclet::dem::applyUpdatesKokkos ( int  n,
V3  posPred,
V3  velPred,
V3  deltaPos,
V3  deltaVel,
Vi  constraintCounts 
)
inline

Jacobi count-averaged apply of position/velocity deltas, then clear deltas + counts.

Definition at line 168 of file integration.hpp.

References add3(), ldF3(), scale3(), and peclet::dem::detail::st3().

Referenced by demSolveContacts().

◆ finalCommitKokkos()

void peclet::dem::finalCommitKokkos ( int  n,
V3  pos,
Vf  invMass,
V3  posPred,
V4  quat,
V4  quatPred,
Domain  dom 
)
inline

◆ applyThermostatKokkos()

void peclet::dem::applyThermostatKokkos ( int  numReal,
V3  vel,
Vf  invMass,
V3  angVel,
V3  invInertia,
V4  quat,
double  kB,
double  tau,
double  Ttarget,
float  dt 
)
inline

◆ updateGrowthScalesKokkos()

void peclet::dem::updateGrowthScalesKokkos ( int  n,
Vf  scale,
Vf  targetScale,
float  factor 
)
inline

Growth mode: scale = target * factor (when active).

Definition at line 275 of file integration.hpp.

Referenced by demStep(), and peclet::dem::Simulation::setGrowthParams().

◆ writeLammpsDump()

void peclet::dem::writeLammpsDump ( const std::string &  filename,
int  step,
const std::vector< float > &  pos,
const std::vector< float > &  vel,
const std::vector< float > &  quat,
const std::vector< float > &  radii,
const float *  boxMin,
const float *  boxMax,
bool  pbcEnabled 
)
inline

Definition at line 23 of file io.hpp.

Referenced by peclet::dem::Simulation::exportLammps(), and NB_MODULE().

◆ writeSdfVti()

void peclet::dem::writeSdfVti ( const std::string &  filename,
const std::vector< float > &  grid,
int  rx,
int  ry,
int  rz,
const float *  minB,
const float *  maxB 
)
inline

Definition at line 86 of file io.hpp.

Referenced by peclet::dem::Simulation::exportSdf().

◆ loadF3()

F3 peclet::dem::loadF3 ( PosView  v,
int  i 
)

◆ loadF4()

F4 peclet::dem::loadF4 ( QuatView  v,
int  i 
)

Definition at line 94 of file narrowphase.hpp.

Referenced by detectBoundaryKokkos(), and hertzShapePairForcesKokkos().

◆ sampleGridSdf()

float peclet::dem::sampleGridSdf ( F3  p,
const ShapeDesc d,
GridView  grid 
)

Trilinearly sample an imported grid SDF at canonical point p.

The query is clamped into the sample lattice and the Euclidean distance from p to that clamped point is added back, so a probe outside the stored box gets a monotonically growing (positive) distance instead of a flat clamped value — the standard "clamp + residual" extension that keeps the far field well-signed and the central-difference normal sane near the grid boundary. Interior samples are exact trilinear. Requires nx,ny,nz >= 2 (the shape builder guarantees this).

Definition at line 104 of file narrowphase.hpp.

References peclet::dem::ShapeDesc::gridInvSpacing, peclet::dem::ShapeDesc::gridOffset, peclet::dem::ShapeDesc::gridOrigin, peclet::dem::ShapeDesc::nx, peclet::dem::ShapeDesc::ny, peclet::dem::ShapeDesc::nz, peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by sdfEvalShape().

◆ sampleWallSdf()

float peclet::dem::sampleWallSdf ( F3  p,
const WallSdf w,
GridView  grid 
)

Trilinearly sample a static world-space wall SDF at world point p.

Positive in the void, negative in the wall. The off-grid extension SUBTRACTS the clamp residual — the OPPOSITE of sampleGridSdf's object convention — because a wall SDF is a CONTAINER: the void is bounded and everything beyond the stored box is wall-side, so a probe outside the box must read an ever more negative (deeper-in-the-wall) distance. Adding the residual here (the old behaviour) made a grain pushed past the box boundary — e.g. squeezed through the floor plane, whose zero level sits exactly on the grid's lower face — read "clear" and free-fall out of the simulation forever: a 180k glass-bead pile lost 71k grains through the distributor during settling.

Definition at line 141 of file narrowphase.hpp.

References peclet::dem::WallSdf::gridOffset, peclet::dem::WallSdf::invSpacing, peclet::dem::WallSdf::nx, peclet::dem::WallSdf::ny, peclet::dem::WallSdf::nz, peclet::dem::WallSdf::origin, peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by hertzBuildWallCandidatesKokkos().

◆ sdfEvalShape()

float peclet::dem::sdfEvalShape ( F3  p,
const ShapeDesc d,
GridView  grid 
)

Canonical-space SDF of a shape: analytic dispatch, or a trilinear grid sample for an imported grid SDF.

grid may be an empty View when no grid shape is present.

Definition at line 171 of file narrowphase.hpp.

References peclet::dem::ShapeDesc::params, sampleGridSdf(), sdfEval(), SHAPE_GRID_SDF, and peclet::dem::ShapeDesc::type.

Referenced by hertzShapePairForcesKokkos().

◆ detectContactsKokkos()

void peclet::dem::detectContactsKokkos ( Kokkos::View< const int *[2], CpMem pairs,
int  numPairs,
PosView  pos,
QuatView  quat,
ScalarF  scale,
ScalarI  shapeId,
Kokkos::View< const ShapeDesc *, CpMem shapes,
ShellView  shell,
float  globalScale,
float  margin,
Kokkos::View< ContactC *, CpMem outContacts,
Kokkos::View< int, CpMem outCount,
Kokkos::View< float, CpMem maxOverlap,
GridView  sdfGrid = GridView{},
MatIdView  matId = MatIdView{},
PairTableView  pairTable = PairTableView{} 
)
inline

Pair point-shell vs SDF contacts.

pairs[numPairs][2] are (idA,idB) from the broad-phase; emits ContactC into outContacts guarded by atomic outCount (clamped to outContacts.extent(0)).

Definition at line 179 of file narrowphase.hpp.

Referenced by computeOverlapsKokkos(), and demStep().

◆ detectWallSdfKokkos()

void peclet::dem::detectWallSdfKokkos ( int  numReal,
int  numWalls,
PosView  pos,
QuatView  quat,
ScalarF  scale,
ScalarI  shapeId,
Kokkos::View< const ShapeDesc *, CpMem shapes,
ShellView  shell,
Kokkos::View< const WallSdf *, CpMem walls,
GridView  wallGrid,
float  globalScale,
float  margin,
Kokkos::View< ContactC *, CpMem outContacts,
Kokkos::View< int, CpMem outCount,
Kokkos::View< float, CpMem maxOverlap,
MatIdView  matId = MatIdView{},
PairTableView  pairTable = PairTableView{} 
)
inline

Per-real-particle contacts against a static world-space wall SDF set (a drum barrel, hopper, vibrating tray, ...).

Mirrors detectBoundaryKokkos but the boundary is the wall's zero level set: each surface point (or the sphere centre) is tested against sampleWallSdf, the outward gradient is the contact normal, and every emitted contact carries the wall's rigid-body surface velocity at the contact point plus the wall's binary (particle–wall) restitution/friction — so the moving-wall terms flow through the manifold velocity solve and the per-contact friction sweep. bodyB = -1 (a boundary, like a plane); the wall surface point is stored in rB for the position solve's plane-linearised non-penetration constraint.

Definition at line 278 of file narrowphase.hpp.

Referenced by computeOverlapsKokkos(), and demStep().

◆ detectBoundaryKokkos()

void peclet::dem::detectBoundaryKokkos ( int  numReal,
int  numPlanes,
PosView  pos,
QuatView  quat,
ScalarF  scale,
ScalarI  shapeId,
Kokkos::View< const ShapeDesc *, CpMem shapes,
ShellView  shell,
Kokkos::View< const PlaneP *, CpMem planes,
float  globalScale,
float  margin,
Kokkos::View< ContactC *, CpMem outContacts,
Kokkos::View< int, CpMem outCount,
Kokkos::View< float, CpMem maxOverlap 
)
inline

Per-real-particle contacts against explicit planes (point-shell shapes test each surface point; analytic spheres use centre-minus-radius).

bodyB = -1; plane anchor stored in rB.

Definition at line 371 of file narrowphase.hpp.

References add3(), peclet::dem::ContactC::bodyA, dot3(), loadF3(), loadF4(), peclet::dem::PlaneP::normal, peclet::dem::ShapeDesc::numPoints, peclet::dem::ShapeDesc::params, peclet::dem::PlaneP::point, rotateVector(), scale3(), peclet::dem::ShapeDesc::shellOffset, sub3(), peclet::dem::F3::x, peclet::dem::F4::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by computeOverlapsKokkos(), and demStep().

◆ generateSdfKokkos()

std::vector< float > peclet::dem::generateSdfKokkos ( int  rx,
int  ry,
int  rz,
F3  dmin,
F3  dmax,
int  numReal,
PosView  pos,
QuatView  quat,
ScalarF  scale,
ScalarI  shapeId,
Kokkos::View< const ShapeDesc *, CpMem shapes,
bool  px,
bool  py,
bool  pz,
GridView  sdfGrid = GridView{} 
)
inline

Definition at line 25 of file output_sdf.hpp.

Referenced by peclet::dem::Simulation::getSdfGrid().

◆ calculateGhostCapacity()

int peclet::dem::calculateGhostCapacity ( int  nReal,
Domain  dom,
float  skin 
)
inline

Padded particle-array capacity that leaves room for the periodic ghosts generateGhostsKokkos will emit: the real count plus an estimate of the boundary-shell ghost population, gated on which axes are actually periodic.

Faithful port of the CUDA Simulation::calculate_capacity (small/dense box -> full 26-neighbour headroom; large box -> a few times the boundary-shell volume fraction), with the periodicity gating added so a closed or partly-periodic box is not over-allocated. skin is the ghost band width at each periodic face (1.0*globalScale in the solver).

Definition at line 25 of file periodicity.hpp.

References peclet::dem::Domain::periodic_x, peclet::dem::Domain::periodic_y, peclet::dem::Domain::periodic_z, peclet::dem::Domain::size, peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by computeOverlapsKokkos(), and demStep().

◆ generateGhostsKokkos()

void peclet::dem::generateGhostsKokkos ( int  numReal,
int  capacity,
Domain  dom,
float  skin,
V3  pos,
Vf  invMass,
V3  posPred,
V3  vel,
V3  velPred,
V4  quat,
V4  quatPred,
V3  angVel,
V3  angVelPred,
Vf  scale,
Vi  shapeId,
Vi  realIndices,
Kokkos::View< int, CpMem topGhost,
Vi  gid = Vi{},
Kokkos::View< unsigned char *, CpMem materialId = {} 
)
inline

Generate periodic ghosts for particles [0,numReal).

topGhost must be pre-seeded to numReal (the first free slot); on return it holds the total particle count. Slots beyond capacity are dropped. skin is the ghost band width at each periodic face.

Definition at line 43 of file periodicity.hpp.

Referenced by computeOverlapsKokkos(), and demStep().

◆ genCylinderShell()

std::vector< F3 > peclet::dem::genCylinderShell ( float  radius,
float  height,
float  thickness,
float  spacing 
)
inline

Definition at line 21 of file shapes_portable.hpp.

Referenced by peclet::dem::Simulation::initializeShape().

◆ genBoxShell()

std::vector< F3 > peclet::dem::genBoxShell ( float  hx,
float  hy,
float  hz,
float  spacing 
)
inline

Definition at line 80 of file shapes_portable.hpp.

Referenced by peclet::dem::Simulation::initializeShape().

◆ demStep()

void peclet::dem::demStep ( Particles P)
inline

One full XPBD DEM substep over the particle SoA (mirrors simulation.cpp Simulation::step()).

Definition at line 49 of file sim.hpp.

References peclet::dem::Particles::angVel, peclet::dem::Particles::angVelPred, applyThermostatKokkos(), peclet::dem::Particles::asleep, peclet::dem::Particles::baseRadius, buildInvMassEffKokkos(), calculateGhostCapacity(), peclet::dem::Particles::capacity, computeContactSleepKokkos(), computeManifoldSleepKokkos(), peclet::dem::Particles::constraintCounts, peclet::dem::Particles::contactCount, peclet::dem::Particles::contacts, peclet::dem::Particles::contactSleep, peclet::dem::Particles::contactSlot, peclet::dem::Particles::deltaAngVel, peclet::dem::Particles::deltaPos, peclet::dem::Particles::deltaQuat, peclet::dem::Particles::deltaVel, demSolveContacts(), detectBoundaryKokkos(), detectContactsKokkos(), detectWallSdfKokkos(), peclet::dem::Particles::domain, peclet::dem::Particles::dt, peclet::dem::Particles::ensureCapacity(), peclet::dem::Particles::extForce, peclet::dem::Particles::extForceActive, finalCommitKokkos(), findCollisionsGrow(), findCollisionsVerlet(), freezeAsleepKokkos(), generateGhostsKokkos(), peclet::dem::Particles::gid, peclet::dem::Particles::globalScale, peclet::dem::Particles::gravity, peclet::dem::Particles::groundedLevel, peclet::dem::Particles::growthFactor, peclet::dem::Particles::growthRate, peclet::dem::Particles::invInertia, peclet::dem::Particles::invMass, peclet::dem::Particles::invMassEff, peclet::dem::Particles::manifoldCount, peclet::dem::Particles::manifolds, peclet::dem::Particles::manifoldSleep, peclet::dem::Particles::materialId, peclet::dem::Particles::maxOverlap, maxOwnedRadius(), peclet::dem::Particles::numParticles, peclet::dem::Particles::numPlanes, peclet::dem::Particles::numReal, peclet::dem::Particles::numWalls, peclet::dem::Particles::pairMaterials, peclet::dem::Particles::pairs, peclet::dem::Domain::periodic_x, peclet::dem::Domain::periodic_y, peclet::dem::Domain::periodic_z, peclet::dem::Particles::planes, peclet::dem::Particles::pos, peclet::dem::Particles::posPred, predictVelocityKokkos(), peclet::dem::Particles::quat, peclet::dem::Particles::quatPred, peclet::dem::Particles::rad, readInt(), peclet::dem::Particles::realIndices, reduceContactsToManifoldsKokkos(), peclet::dem::Particles::scale, peclet::dem::Particles::sdfGrid, peclet::dem::Particles::shapeId, peclet::dem::Particles::shapes, peclet::dem::Particles::shell, peclet::dem::Particles::sleepCounter, peclet::dem::Particles::sleepCurCount, peclet::dem::Particles::sleepImmovableFrac, peclet::dem::Particles::sleepingEnabled, peclet::dem::Particles::sleepK, peclet::dem::Particles::sleepMovingWall, peclet::dem::Particles::sleepPrevCount, peclet::dem::Particles::sleepScale, peclet::dem::Particles::sleepWakeLostContact, peclet::dem::Particles::targetScale, peclet::dem::Particles::thermostatKB, peclet::dem::Particles::thermostatTau, peclet::dem::Particles::thermostatTemp, peclet::dem::Particles::topGhost, updateGrowthScalesKokkos(), updateSleepKokkos(), peclet::dem::Particles::vel, peclet::dem::Particles::velPred, peclet::dem::Particles::verletSkinFrac, wakeContactChangeKokkos(), wakeDisturbedKokkos(), peclet::dem::Particles::wakeScale, peclet::dem::Particles::wallGrid, peclet::dem::Particles::walls, peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by peclet::dem::Simulation::step().

◆ computeOverlapsKokkos()

float peclet::dem::computeOverlapsKokkos ( Particles P)
inline

Max pair interpenetration on the committed state (faithful to CUDA Simulation::compute_overlaps): copy committed pos/quat into the predicted buffers, regenerate the periodic ghosts from that state, then run the same broad/narrow phase as demStep and return the recorded max overlap.

No solve.

Definition at line 185 of file sim.hpp.

References peclet::dem::Particles::angVel, peclet::dem::Particles::angVelPred, peclet::dem::Particles::baseRadius, calculateGhostCapacity(), peclet::dem::Particles::capacity, peclet::dem::Particles::contactCount, peclet::dem::Particles::contacts, detectBoundaryKokkos(), detectContactsKokkos(), detectWallSdfKokkos(), peclet::dem::Particles::domain, peclet::dem::Particles::ensureCapacity(), findCollisionsGrow(), generateGhostsKokkos(), peclet::dem::Particles::gid, peclet::dem::Particles::globalScale, peclet::dem::Particles::invMass, peclet::dem::Particles::materialId, peclet::dem::Particles::maxOverlap, maxOwnedRadius(), peclet::dem::Particles::numParticles, peclet::dem::Particles::numPlanes, peclet::dem::Particles::numReal, peclet::dem::Particles::numWalls, peclet::dem::Particles::pairMaterials, peclet::dem::Particles::pairs, peclet::dem::Particles::planes, peclet::dem::Particles::pos, peclet::dem::Particles::posPred, peclet::dem::Particles::quat, peclet::dem::Particles::quatPred, peclet::dem::Particles::rad, readInt(), peclet::dem::Particles::realIndices, peclet::dem::Particles::scale, peclet::dem::Particles::sdfGrid, peclet::dem::Particles::shapeId, peclet::dem::Particles::shapes, peclet::dem::Particles::shell, peclet::dem::Particles::topGhost, peclet::dem::Particles::vel, peclet::dem::Particles::velPred, peclet::dem::Particles::wallGrid, and peclet::dem::Particles::walls.

Referenced by peclet::dem::Simulation::computeOverlaps().

◆ freezeAsleepKokkos()

void peclet::dem::freezeAsleepKokkos ( int  numReal,
Kokkos::View< const unsigned char *, CpMem asleep,
Kokkos::View< const float *[3], CpMem pos,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< float *[3], CpMem posPred,
Kokkos::View< float *[4], CpMem quatPred,
Kokkos::View< float *[3], CpMem velPred,
Kokkos::View< float *[3], CpMem angVelPred 
)
inline

After predictVelocity: re-freeze the currently-asleep bodies so gravity/prediction do not move them — velPred = angVelPred = 0, posPred = pos, quatPred = quat.

Definition at line 31 of file sleeping.hpp.

Referenced by demStep().

◆ buildInvMassEffKokkos()

void peclet::dem::buildInvMassEffKokkos ( int  numBodies,
Kokkos::View< const unsigned char *, CpMem asleep,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< float *, CpMem invMassEff,
float  sleeperFrac 
)
inline

Effective inverse mass for the solve: a sleeping body (real, or a periodic ghost whose real is asleep) is immovable — invMassEff = 0.

Everything else keeps its real invMass. Built over the full body-slot span (owned + ghosts); the driver's swap points every solve kernel at it.

Definition at line 58 of file sleeping.hpp.

Referenced by demStep().

◆ computeManifoldSleepKokkos()

void peclet::dem::computeManifoldSleepKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const unsigned char *, CpMem asleep,
Kokkos::View< unsigned char *, CpMem manifoldSleep 
)
inline

Per-manifold "both endpoints asleep" flag (a static wall, bodyB < 0, counts as asleep).

Such manifolds are excluded from colouring / sweeps / the multilevel hierarchy but STILL carry their frozen force network through the warm-start ledger (the caller never skips the ledger kernels).

Definition at line 74 of file sleeping.hpp.

References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, and peclet::dem::ManifoldC::num_points.

Referenced by demStep().

◆ computeContactSleepKokkos()

void peclet::dem::computeContactSleepKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const unsigned char *, CpMem asleep,
Kokkos::View< unsigned char *, CpMem contactSleep 
)
inline

Per-contact twin of computeManifoldSleepKokkos for the position colouring.

Definition at line 95 of file sleeping.hpp.

References peclet::dem::ContactC::bodyA, and peclet::dem::ContactC::bodyB.

Referenced by demStep().

◆ wakeDisturbedKokkos()

void peclet::dem::wakeDisturbedKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const float *[3], CpMem velPred,
float  wakeSpeed,
Kokkos::View< unsigned char *, CpMem asleep,
Kokkos::View< unsigned char *, CpMem sleepCounter,
Kokkos::View< unsigned char *, CpMem movingWall,
Kokkos::View< int *, CpMem curCount,
int  numReal 
)
inline

Wake pass (before the solve): a sleeper is woken when actually disturbed.

Over this substep's manifolds — (a) a manifold pairing it with an AWAKE body whose speed exceeds wakeSpeed wakes it; (c) a contact with a MOVING wall (wallVel != 0) wakes it (and flags it never-sleep this substep). Also tallies each real body's live contact count into curCount for the caller's contact-set-change wake rule (b). velPred is the post-predict / post-freeze velocity (awake bodies carry their real speed, sleepers carry 0).

Definition at line 117 of file sleeping.hpp.

References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, peclet::dem::ManifoldC::num_points, peclet::dem::ManifoldC::wallVel_sum, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

Referenced by demStep().

◆ wakeContactChangeKokkos()

void peclet::dem::wakeContactChangeKokkos ( int  numReal,
Kokkos::View< const int *, CpMem curCount,
Kokkos::View< int *, CpMem prevCount,
Kokkos::View< const unsigned char *, CpMem movingWall,
Kokkos::View< unsigned char *, CpMem asleep,
Kokkos::View< unsigned char *, CpMem sleepCounter,
bool  wakeOnChange 
)
inline

Contact-set-change wake rule (b): wake any still-asleep body whose live contact count differs from the stored one (a support gained or lost), then refresh the store.

Also clears the counter of a moving-wall body so it can never accumulate toward sleep.

Definition at line 176 of file sleeping.hpp.

Referenced by demStep().

◆ updateSleepKokkos()

void peclet::dem::updateSleepKokkos ( int  numReal,
Kokkos::View< const float *[3], CpMem vel,
Kokkos::View< const float *[3], CpMem angVel,
Kokkos::View< const float *, CpMem rad,
Kokkos::View< const unsigned char *, CpMem grounded,
Kokkos::View< const unsigned char *, CpMem movingWall,
Kokkos::View< unsigned char *, CpMem asleep,
Kokkos::View< unsigned char *, CpMem sleepCounter,
float  sleepSpeed,
int  K,
Kokkos::View< float *[3], CpMem velOut,
Kokkos::View< float *[3], CpMem angVelOut 
)
inline

Sleep detection (after the commit): an AWAKE, grounded body whose linear AND angular motion has stayed below sleepSpeed for K consecutive substeps is put to sleep (velocity + spin zeroed).

Any body at/above the threshold, ungrounded, or on a moving wall resets its counter. vel / angVel are the committed velocities of this substep.

Definition at line 205 of file sleeping.hpp.

Referenced by demStep().

◆ readInt()

◆ readFloat()

float peclet::dem::readFloat ( Kokkos::View< float, CpMem v)
inline

Definition at line 47 of file solve_driver.hpp.

Referenced by demSolveContacts().

◆ fillGidBaseKokkos()

void peclet::dem::fillGidBaseKokkos ( Vi  gid,
int  n,
int  base 
)
inline

gid(i) = base + i over [0, n) — the per-rank global-id re-base of the distributed step (namespace scope: nvcc forbids KOKKOS_LAMBDA in member functions).

Definition at line 55 of file solve_driver.hpp.

◆ maxOwnedRadius()

float peclet::dem::maxOwnedRadius ( const Particles P)
inline

Largest effective particle radius over the owned set (= max scale × globalScale, growth included).

The ghost band + broadphase margin are sized off THIS, not globalScale directly, so they scale with the actual grain size — set particles in SI (radius = 1e-3, globalScale left at 1) and the halo layer follows automatically. For the usual convention (globalScale ≈ grain size, scale ≈ 1) it is numerically identical to the old 1.0*globalScale.

Definition at line 67 of file solve_driver.hpp.

References peclet::dem::Particles::baseRadius, peclet::dem::Particles::globalScale, peclet::dem::Particles::numReal, and peclet::dem::Particles::scale.

Referenced by computeOverlapsKokkos(), and demStep().

◆ findCollisionsGrow()

int peclet::dem::findCollisionsGrow ( Particles P,
float  margin 
)
inline

Broad phase with an automatically-grown pair buffer.

findCollisionsArborX guards its pair WRITES at maxPairs but returns the RAW candidate count, which can exceed P.pairs' capacity once a bed compacts (more neighbour pairs than the buffer holds — e.g. a fluidized bed driven denser by the CFD-DEM drag). Feeding that raw count straight into detectContactsKokkos as its loop bound makes the narrowphase read P.pairs out of bounds → cudaErrorIllegalAddress. Here we detect the overflow, reallocate P.pairs (with headroom so an oscillating count doesn't realloc every step) and re-run once so no candidate pair is silently dropped, then clamp defensively so the returned count is ALWAYS ≤ the buffer extent — the narrowphase can never walk off the end regardless.

Definition at line 88 of file solve_driver.hpp.

References peclet::dem::Particles::crad(), peclet::dem::Particles::domain, findCollisionsArborX(), peclet::dem::Particles::maxPairs, peclet::dem::Particles::numParticles, peclet::dem::Particles::numReal, peclet::dem::Particles::pairCount, peclet::dem::Particles::pairs, peclet::dem::Particles::posPred, peclet::dem::Domain::size, peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by computeOverlapsKokkos(), demStep(), findCollisionsVerlet(), and hertzRebuildPairs().

◆ findCollisionsVerlet()

int peclet::dem::findCollisionsVerlet ( Particles P,
float  margin,
float  maxRad 
)
inline

Verlet-cached impulse broadphase (single-GPU, non-periodic).

Reuse the last ArborX candidate list while no particle's predicted position has moved more than skin/2 since the build; the list is built at margin + skin, so every within-margin pair is still present between rebuilds — a SUPERSET, so the narrowphase yields identical contacts (order differs -> run-scatter, like the colouring/fused paths). Rebuilds on an invalid cache, growth beyond the skin, or the displacement bound. Composes with sleeping: a frozen bed has zero displacement, so it never rebuilds. The caller guarantees non-periodic (no per-step ghost-slot churn) and verletSkinFrac > 0.

Definition at line 110 of file solve_driver.hpp.

References findCollisionsGrow(), peclet::dem::Particles::impNumPairs, peclet::dem::Particles::impRefMaxRad, peclet::dem::Particles::impRefPos, peclet::dem::Particles::numReal, peclet::dem::Particles::posPred, and peclet::dem::Particles::verletSkinFrac.

Referenced by demStep().

◆ demSolveContacts()

template<class Hooks >
void peclet::dem::demSolveContacts ( Particles P,
int  nc,
int  nm,
int  nBodies,
Kokkos::View< const int *, CpMem keyIdx,
const Hooks &  hooks 
)
inline

One full velocity + position contact solve over the already-built contacts/manifolds (see file comment).

Runs between the narrow phase and finalCommit; the caller owns ghost construction, broad/narrow phase and the commit.

Definition at line 224 of file solve_driver.hpp.

References accumulateNormalImpulseKokkos(), peclet::dem::Particles::angVel, peclet::dem::Particles::angVelPred, applyUpdatesKokkos(), applyVelocityAndPredictPositionKokkos(), applyVelocityDeltasAveragedKokkos(), applyVelocityDeltasKokkos(), peclet::dem::Particles::asleep, peclet::dem::Particles::baseRadius, peclet::dem::Particles::bodyColorMask, peclet::dem::Particles::bodyOrphan, peclet::dem::Particles::bodyOrphanVPeak, peclet::dem::Particles::bodyWinner, peclet::dem::Particles::bucketCursor, buildCoarseBucketsKokkos(), buildColorBucketsKokkos(), buildContactHierarchyKokkos(), buildLevelColorBucketsKokkos(), colorContactsIncrementalKokkos(), colorContactsKokkos(), colorManifoldsIncrementalKokkos(), colorManifoldsKokkos(), commitContactColorKokkos(), commitPairKeysLambdaKokkos(), peclet::dem::Particles::commitPerm, commitPosImpulseKokkos(), computeHeightLevelsKokkos(), computePlaneLoadKokkos(), computeSideFlagsKokkos(), computeVn0Kokkos(), peclet::dem::Particles::constraintCounts, peclet::dem::Particles::contactColor, peclet::dem::Particles::contactKeys, peclet::dem::Particles::contacts, peclet::dem::Particles::contactSleep, peclet::dem::Particles::contactSlot, countFrictionContactsKokkos(), decayBodyOrphanKokkos(), peclet::dem::Particles::deltaAngVel, peclet::dem::Particles::deltaPos, peclet::dem::Particles::deltaQuat, peclet::dem::Particles::deltaVel, demFusedWanted(), demMakeFusedCtx(), demMakeMlFusedCtx(), peclet::dem::Particles::dt, peclet::dem::Particles::extForceActive, peclet::dem::Particles::frictionDynamic, peclet::dem::Particles::fusedBar, gatherWarmLambdaKokkos(), peclet::dem::Particles::gid, peclet::dem::Particles::globalScale, peclet::dem::Particles::graphCache, peclet::dem::Particles::gravity, peclet::dem::Particles::groundedLevel, peclet::dem::Particles::growthRate, peclet::dem::Particles::heightLevel, peclet::dem::Particles::invInertia, peclet::dem::Particles::invMass, peclet::dem::mldetail::kGateSlip, peclet::dem::Particles::lambdaAcc, peclet::dem::Particles::lambdaT, peclet::dem::Particles::levelKey, peclet::dem::Particles::levelPerm, makePGSManifoldSweep(), peclet::dem::Particles::manifoldColor, peclet::dem::Particles::manifoldPersistent, peclet::dem::Particles::manifolds, peclet::dem::Particles::manifoldSleep, markPersistentManifoldsKokkos(), peclet::dem::Particles::maxApproach, peclet::dem::Particles::maxApproachQS, peclet::dem::FusedSweepCtx::maxBucket, peclet::dem::Particles::maxOverlap, peclet::dem::MlFusedCtx::maxWork, peclet::dem::Particles::mlBucketPerm, peclet::dem::Particles::mlColorPacked, peclet::dem::Particles::mlGrp, peclet::dem::Particles::mlInvMassG, peclet::dem::Particles::mlMassG, peclet::dem::Particles::mlMate, peclet::dem::Particles::mlOffsDev, peclet::dem::Particles::mlParent, peclet::dem::Particles::mlVelG, peclet::dem::Particles::mlVelG0, multilevelCoarseCycleKokkos(), peclet::dem::ContactHierarchy::numLevels, peclet::dem::Particles::numParticles, peclet::dem::Particles::numReal, peclet::dem::Particles::pairKeys, PECLET_DEM_GRAPH_LOOP, peclet::dem::Particles::planeFriction, peclet::dem::Particles::pos, peclet::dem::Particles::posCommitPerm, peclet::dem::Particles::posImpulse, peclet::dem::Particles::positionIterations, peclet::dem::Particles::posLambdaContact, peclet::dem::Particles::posLastFullColors, peclet::dem::Particles::posOffsDev, peclet::dem::Particles::posPerm, peclet::dem::Particles::posPred, peclet::dem::Particles::posPrevContactCount, peclet::dem::Particles::prevContactColor, peclet::dem::Particles::prevContactKeys, peclet::dem::Particles::prevLambda, peclet::dem::Particles::prevLambdaT, peclet::dem::Particles::prevManifoldColor, peclet::dem::Particles::prevMatched, peclet::dem::Particles::prevPairCount, peclet::dem::Particles::prevPairKeys, peclet::dem::Particles::prevPosImpulse, peclet::dem::Particles::prevRestBank, peclet::dem::Particles::prevRestVPeak, peclet::dem::Particles::quat, peclet::dem::Particles::quatPred, readFloat(), peclet::dem::Particles::realIndices, peclet::dem::Particles::restBank, peclet::dem::Particles::restitutionModel, peclet::dem::Particles::restitutionNormal, peclet::dem::Particles::restitutionTangent, peclet::dem::Particles::restRel, peclet::dem::Particles::restVPeak, scatterOrphanBanksKokkos(), peclet::dem::Particles::sideFlags, peclet::dem::Particles::sleepingEnabled, solveContactFrictionKokkos(), solvePositionColoredGSKokkos(), solvePositionKokkos(), solveVelocityColoredGSKokkos(), solveVelocityKokkos(), solveVelocityPGSBucketsKokkos(), solveVelocityPGSKokkos(), peclet::dem::Particles::stabilizationMode, updateGroundedLevelsKokkos(), updateRestitutionBankKokkos(), peclet::dem::Particles::vel, peclet::dem::Particles::velLastFullColors, peclet::dem::Particles::velocityIterations, peclet::dem::Particles::velocityUseGS, peclet::dem::Particles::velOffsDev, peclet::dem::Particles::velPerm, peclet::dem::Particles::velPred, peclet::dem::Particles::vn0, peclet::dem::Particles::vt0, peclet::dem::Particles::wallFrictionMax, warmStartApplyKokkos(), peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by demStep().

◆ hertzRebuildPairs()

void peclet::dem::hertzRebuildPairs ( Particles P,
float  skin 
)
inline

Rebuild the Hertz cached pair list with margin skin, carrying the Mindlin shear history across by pair key (permutation sort of the OLD list, binary search from the NEW).

Keys are built from GLOBAL ids (identity == local index single-rank, so single-GPU behaviour is unchanged; under MPI ghost slots are not stable identities, gids are).

Definition at line 50 of file solve_driver_force.hpp.

References findCollisionsGrow(), peclet::dem::Particles::gid, peclet::dem::Particles::hertzDispMax, peclet::dem::Particles::hertzKeys, peclet::dem::Particles::hertzNumPairs, peclet::dem::Particles::hertzPrevCount, peclet::dem::Particles::hertzPrevKeys, peclet::dem::Particles::hertzPrevXi, peclet::dem::Particles::hertzRefPos, peclet::dem::Particles::hertzSnPair, peclet::dem::Particles::hertzXi, peclet::dem::Particles::pairs, peclet::dem::Particles::pos, and peclet::dem::Particles::posPred.

Referenced by peclet::dem::HertzMindlinLaw::rebuild().

◆ hertzCommitHistory()

void peclet::dem::hertzCommitHistory ( Particles P)
inline

◆ zeroForceScratchKokkos()

void peclet::dem::zeroForceScratchKokkos ( V3  dv,
V3  dw,
int  lo,
int  hi 
)
inline

Zero the force/torque accumulator rows [lo, hi) — under MPI the pair kernels atomically accumulate onto ghost slots too (Newton's third law), but only owned rows are consumed and cleared by the integrator; without this the ghost rows grow without bound.

Definition at line 190 of file solve_driver_force.hpp.

◆ fillWorldRadiiKokkos()

void peclet::dem::fillWorldRadiiKokkos ( Vf  scale,
Vf  rad,
float  gs,
float  bR,
int  n 
)
inline

World radii rad(i) = scale(i) * globalScale * baseRadius over [0, n) (n = owned + ghosts after a halo gather; the driver's own preamble fills the owned span).

Definition at line 207 of file solve_driver_force.hpp.

◆ demStepForce()

◆ demStepHertz()

void peclet::dem::demStepHertz ( Particles P,
float  dt,
int  nsteps,
float  skinFrac 
)
inline

nsteps of the soft-sphere Hertz-Mindlin engine — the single-GPU instantiation of the force-based driver (kept as the historical entry point; see demStepForce).

Definition at line 338 of file solve_driver_force.hpp.

References demStepForce().

Referenced by peclet::dem::Simulation::stepHertz().

◆ accumulateNormalImpulseKokkos()

void peclet::dem::accumulateNormalImpulseKokkos ( Kokkos::View< ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[3], CpMem velPred,
Kokkos::View< const float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate 
)
inline

Force-chain normal load, accumulated over the velocity iterations: contacts(idx).friction_lambda_n += approach / w_n.

Body-body AND wall (boundary) contacts — a grain buried under the bed thus gets the WEIGHT TRANSMITTED FROM ABOVE pressing it into the wall, not just its own one-shot gravity approach (computePlaneLoad). Without this a deep bed slips against a moving wall instead of being dragged up (a rotating drum stays flat).

Definition at line 32 of file solver_friction.hpp.

References add3(), peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, peclet::dem::ContactC::boundaryVel, peclet::dem::detail::computeW(), cross3v(), dot3(), ldF3(), peclet::dem::ContactC::normal, peclet::dem::ContactC::rA, peclet::dem::ContactC::rB, scale3(), sub3(), peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

Referenced by demSolveContacts().

◆ computePlaneLoadKokkos()

void peclet::dem::computePlaneLoadKokkos ( Kokkos::View< ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[3], CpMem velPred,
Kokkos::View< const float *[3], CpMem angVelPred,
FrManifoldCounts  planeFriction 
)
inline

Plane (idB<0) one-shot loads.

Zeros planeFriction first (both columns), then sets the per-contact friction_lambda_n and the per-body max plane load (.x).

Definition at line 87 of file solver_friction.hpp.

References add3(), peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, peclet::dem::ContactC::boundaryVel, peclet::dem::detail::computeW(), cross3v(), dot3(), ldF3(), peclet::dem::ContactC::normal, peclet::dem::ContactC::rA, sub3(), peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

Referenced by demSolveContacts().

◆ countFrictionContactsKokkos()

void peclet::dem::countFrictionContactsKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const int *, CpMem realIdx,
FrManifoldCounts  planeFriction 
)
inline

Per-body active-contact count into planeFriction(:,1).

Definition at line 123 of file solver_friction.hpp.

References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, and peclet::dem::ContactC::friction_lambda_n.

Referenced by demSolveContacts().

◆ solveContactFrictionKokkos()

void peclet::dem::solveContactFrictionKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[3], CpMem velPred,
Kokkos::View< const float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
FrManifoldCounts  planeFriction,
float  frictionDynamic,
Kokkos::View< float *[3], CpMem deltaVel,
Kokkos::View< float *[3], CpMem deltaAngVel 
)
inline

◆ demFusedWanted()

bool peclet::dem::demFusedWanted ( bool  graphReplayAvailable)
inline

Fused-sweep policy (read once).

PECLET_DEM_NO_FUSED=1 forces the launch path everywhere; PECLET_DEM_FUSED=1 forces the fused path everywhere it applies. Default: fused only where CUDA-graph replay is unavailable — the distributed step (ghost syncs inside the loops forbid capture) and PECLET_DEM_NO_GRAPH runs. Measured on the 25k/100k Dosta beds (RTX 5080): graph replay beats the fused kernels by 2-4% on the solo GPU (pipelined graph-node transitions are cheaper than software grid barriers once the step is GPU-bound), while capture-less paths pay the full per-launch submission storm that fusion removes (25k multilevel: 17.4 -> 16.2 ms/step with graphs off).

Definition at line 59 of file solver_fused.hpp.

Referenced by demSolveContacts().

◆ demMakeFusedCtx()

FusedSweepCtx peclet::dem::demMakeFusedCtx ( CpExec space,
const std::vector< int > &  offs,
Kokkos::View< int *, CpMem offsDev,
Kokkos::View< unsigned *, CpMem bar 
)
inline

Fill a FusedSweepCtx from buildColorBucketsKokkos's host offsets: async-upload them into the pooled device view and record the largest bucket.

The caller owns the policy decision (demFusedWanted); no-CUDA / empty / oversize => inactive ctx.

Definition at line 246 of file solver_fused.hpp.

References peclet::dem::FusedSweepCtx::bar, peclet::dem::FusedSweepCtx::maxBucket, and peclet::dem::FusedSweepCtx::offsDev.

Referenced by demSolveContacts().

◆ hertzPairEMu()

void peclet::dem::hertzPairEMu ( int  matA,
int  matB,
PairTableView  pairTable,
float  eGlobal,
float  muGlobal,
float &  e,
float &  mu 
)

Pairwise (e, mu) lookup shared with the narrowphase convention: pair table if present, global fallback otherwise.

Definition at line 27 of file solver_hertz.hpp.

References kMaxMaterials.

Referenced by hertzPairForcesKokkos(), and hertzShapePairForcesKokkos().

◆ hertzBetaD()

float peclet::dem::hertzBetaD ( float  e)

Restitution -> damping ratio beta_d = ln e / sqrt(ln^2 e + pi^2) (e in (0, 1]; e <= 0 -> -1, the critically-damped limit used by LIGGGHTS for e -> 0).

Definition at line 41 of file solver_hertz.hpp.

Referenced by hertzForce(), and hertzShapePairForcesKokkos().

◆ hertzForce()

F3 peclet::dem::hertzForce ( float  delta,
F3  nhat,
F3  vrel,
float  rStar,
float  mStar,
float  eStar,
float  gStar,
float  e,
float  mu,
float  dt,
F3 xi 
)

One Hertz–Mindlin force evaluation for a sphere-sphere or sphere-wall contact.

Returns the force ON body A applied at the contact point (linear) and updates xi in place. nhat points from B to A (push direction on A). vrel = contact velocity of A relative to B.

Definition at line 53 of file solver_hertz.hpp.

References add3(), dot3(), hertzBetaD(), scale3(), and sub3().

Referenced by hertzPairForcesKokkos().

◆ hertzPairForcesKokkos()

void peclet::dem::hertzPairForcesKokkos ( Kokkos::View< const int *[2], CpMem pairs,
int  numPairs,
Kokkos::View< const float *[3], CpMem pos,
Kokkos::View< const float *[3], CpMem vel,
Kokkos::View< const float *[3], CpMem angVel,
Kokkos::View< const float *, CpMem rad,
Kokkos::View< const float *, CpMem invMass,
MatIdView  matId,
PairTableView  pairTable,
float  eGlobal,
float  muGlobal,
Kokkos::View< const float *, CpMem hertzE,
Kokkos::View< const float *, CpMem hertzNu,
float  dt,
Kokkos::View< float *[3], CpMem xi,
Kokkos::View< float *[3], CpMem force,
Kokkos::View< float *[3], CpMem torque 
)
inline

Cached-pair forces: overlap from current positions; history resets when a cached pair is currently separated.

Forces/torques accumulate atomically (a body appears in many pairs).

Definition at line 88 of file solver_hertz.hpp.

References add3(), cross3v(), dot3(), force(), hertzForce(), hertzPairEMu(), loadF3(), scale3(), sub3(), and peclet::dem::F3::x.

Referenced by peclet::dem::HertzMindlinLaw::pairForces().

◆ hertzWallForcesKokkos()

void peclet::dem::hertzWallForcesKokkos ( Kokkos::View< const int *, CpMem candSlots,
int  numCand,
Kokkos::View< const WallSdf *, CpMem walls,
GridView  wallGrid,
Kokkos::View< const float *[3], CpMem pos,
Kokkos::View< const float *[3], CpMem vel,
Kokkos::View< const float *[3], CpMem angVel,
Kokkos::View< const float *, CpMem rad,
Kokkos::View< const float *, CpMem invMass,
MatIdView  matId,
PairTableView  pairTable,
float  eGlobal,
float  muGlobal,
Kokkos::View< const float *, CpMem hertzE,
Kokkos::View< const float *, CpMem hertzNu,
float  dt,
Kokkos::View< float *[3], CpMem xiWall,
int  maxWalls,
Kokkos::View< float *[3], CpMem force,
Kokkos::View< float *[3], CpMem torque,
Kokkos::View< const float *[4], CpMem quat = {},
Kokkos::View< const float *, CpMem scale = {},
ScalarI  shapeId = {},
Kokkos::View< const ShapeDesc *, CpMem shapes = {},
ShellView  shell = {},
float  globalScale = 1.0f,
float  contactRadiusFrac = 0.5f,
bool  hasShapes = false,
Kokkos::View< float *, CpMem snWall = {} 
)
inline

SDF-wall forces (per particle x wall).

Gradient by central differences at half a grid cell. The wall's rigid surface velocity enters vrel; per-(particle, wall) history in xiWall.

Definition at line 148 of file solver_hertz.hpp.

Referenced by peclet::dem::HertzMindlinLaw::wallForces().

◆ hertzBuildWallCandidatesKokkos()

int peclet::dem::hertzBuildWallCandidatesKokkos ( int  numReal,
int  numWalls,
Kokkos::View< const WallSdf *, CpMem walls,
GridView  wallGrid,
Kokkos::View< const float *[3], CpMem pos,
Kokkos::View< const float *, CpMem rad,
float  skin,
Kokkos::View< int *, CpMem outSlots,
Kokkos::View< int, CpMem outCount 
)
inline

Build the wall candidate list: particles within (radius + skin) of any wall's zero level.

Between pair rebuilds nothing else can reach a wall (same Verlet-skin argument as the pair list), so the per-step wall pass only visits these slots. Encodes i * maxWalls + wallIdx.

Definition at line 343 of file solver_hertz.hpp.

References sampleWallSdf().

Referenced by peclet::dem::HertzMindlinLaw::rebuild().

◆ hertzIntegrateKokkos()

void peclet::dem::hertzIntegrateKokkos ( int  numReal,
Kokkos::View< float *[3], CpMem force,
Kokkos::View< float *[3], CpMem torque,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
F3  gravity,
float  dt,
Kokkos::View< float *[3], CpMem vel,
Kokkos::View< float *[3], CpMem angVel,
Kokkos::View< float *[3], CpMem pos,
Kokkos::View< float *[4], CpMem quat = {},
bool  integrateOrientation = false 
)
inline

Symplectic-Euler kick-drift (MUSEN-style) + displacement tracking for the Verlet rebuild.

Spheres: isotropic inertia, angular update needs no orientation.

Definition at line 374 of file solver_hertz.hpp.

Referenced by demStepForce().

◆ hertzMaxDisp2Kokkos()

float peclet::dem::hertzMaxDisp2Kokkos ( int  numReal,
Kokkos::View< const float *[3], CpMem pos,
Kokkos::View< const float *[3], CpMem refPos 
)
inline

Max squared displacement since the last pair build (called only at rebuild checks – keeping this out of the integrate kernel avoids a per-step single-address atomic).

Definition at line 429 of file solver_hertz.hpp.

References dot3(), loadF3(), and sub3().

Referenced by demStepForce().

◆ hertzShapePairForcesKokkos()

void peclet::dem::hertzShapePairForcesKokkos ( Kokkos::View< const int *[2], CpMem pairs,
int  numPairs,
Kokkos::View< const float *[3], CpMem pos,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< const float *[3], CpMem vel,
Kokkos::View< const float *[3], CpMem angVel,
Kokkos::View< const float *, CpMem scale,
ScalarI  shapeId,
Kokkos::View< const ShapeDesc *, CpMem shapes,
ShellView  shell,
GridView  sdfGrid,
float  globalScale,
float  contactRadiusFrac,
Kokkos::View< const float *, CpMem invMass,
MatIdView  matId,
PairTableView  pairTable,
float  eGlobal,
float  muGlobal,
Kokkos::View< const float *, CpMem hertzE,
Kokkos::View< const float *, CpMem hertzNu,
float  dt,
Kokkos::View< float *[3], CpMem xi,
Kokkos::View< float *, CpMem snPrev,
Kokkos::View< float *[3], CpMem force,
Kokkos::View< float *[3], CpMem torque 
)
inline

Non-spherical pairs: per-point Hertz springs over A's point shell against B's SDF (the same one-sided sampling convention as the narrowphase), ONE Mindlin patch history per pair.

Per shell point k: penetration delta_k from B's SDF, its own Hertz normal spring + dashpot applied AT THE POINT (correct face/edge force distribution and torques); the tangential spring acts at the load-weighted patch centroid, bounded by mu * (sum of point spring forces). R* combines per-shape CONTACT radii (Hertz curvature is undefined at faces/edges – this is the standard point-spring approximation; spheres use their true radii via params.x).

Definition at line 454 of file solver_hertz.hpp.

References add3(), cross3v(), dot3(), force(), hertzBetaD(), hertzPairEMu(), invRotateVector(), len3(), loadF3(), loadF4(), peclet::dem::ShapeDesc::numPoints, peclet::dem::ShapeDesc::params, rotateVector(), scale3(), sdfEvalShape(), peclet::dem::ShapeDesc::shellOffset, SPHERE, sub3(), peclet::dem::ShapeDesc::type, peclet::dem::F3::x, peclet::dem::F4::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by peclet::dem::HertzMindlinLaw::pairForces().

◆ buildContactHierarchyKokkos()

ContactHierarchy peclet::dem::buildContactHierarchyKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const int *, CpMem mColor,
Kokkos::View< const float *, CpMem vn0,
Kokkos::View< const float *[3], CpMem vt0,
Kokkos::View< const unsigned char *, CpMem persistent,
Kokkos::View< const float *[3], CpMem posPred,
F3  gHat,
Kokkos::View< const float *, CpMem invMass,
float  qsThr,
int  gateMask,
int  numReal,
MlScratch S,
Kokkos::View< long long *, CpMem winner,
Kokkos::View< std::uint64_t *, CpMem colorMask,
bool  excludeImmovable = false,
Kokkos::View< const unsigned char *, CpMem asleep = {} 
)
inline

Build the aggregation hierarchy + per-level crossing-manifold colorings.

Eligibility for both matching and coarse solving: mldetail::eligible (active, non-dup, persistent, quasi-static, support-oriented). Walls (bodyB < 0) never merge but their manifolds ARE coarse contacts (the momentum sink). Returns the host hierarchy description.

Definition at line 128 of file solver_multilevel.hpp.

Referenced by demSolveContacts().

◆ buildCoarseBucketsKokkos()

void peclet::dem::buildCoarseBucketsKokkos ( const ContactHierarchy H,
MlScratch S,
int  numManifolds,
Kokkos::View< int *, CpMem colorScratch,
Kokkos::View< int *, CpMem perm,
Kokkos::View< int *, CpMem cursor,
std::vector< std::vector< int > > &  offs 
)
inline

One multilevel stabilization cycle over an already-built hierarchy: fine colored smoothing is the caller's business; this runs the coarse leg (fine -> coarse), updating velPred in place.

Eligibility is baked into the packed per-level colours (slot 63 = skip), and the composed body -> group map is rebuilt from identity each cycle (numReal-sized passes; cheap next to the sweeps). Dense per-(level, colour) buckets for the coarse cycle, built ONCE per hierarchy (the structure is static for the whole substep, so every sweep of every stabilization iteration reuses them instead of scanning ALL manifolds per colour — measured 40% of GPU time and the bulk of the launch-submission bound at 25k). perm segment for level l lives at [(l-1)*numManifolds, l*numManifolds). Colour slots >= numColors (kMlSlotSkip = uncoloured / non-crossing) are excluded — exactly the set the scan-mode colour filter never matched.

Definition at line 379 of file solver_multilevel.hpp.

References buildColorBucketsKokkos(), peclet::dem::MlScratch::colorPacked, peclet::dem::ContactHierarchy::numColors, and peclet::dem::ContactHierarchy::numLevels.

Referenced by demSolveContacts().

◆ demMakeMlFusedCtx()

MlFusedCtx peclet::dem::demMakeMlFusedCtx ( CpExec space,
const ContactHierarchy H,
const std::vector< std::vector< int > > &  bkOffs,
int  numManifolds,
int  numReal,
int  coarseSweeps,
Kokkos::View< int *, CpMem offsDev,
Kokkos::View< unsigned *, CpMem bar 
)
inline

◆ multilevelCoarseCycleKokkos()

void peclet::dem::multilevelCoarseCycleKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< float *[3], CpMem velPred,
Kokkos::View< float *, CpMem lambdaAcc,
Kokkos::View< float, CpMem maxApproach,
int  numReal,
const ContactHierarchy H,
MlScratch S,
int  coarseSweeps,
Kokkos::View< const float *, CpMem restRel = {},
const std::vector< std::vector< int > > *  bkOffs = nullptr,
Kokkos::View< const int *, CpMem bkPerm = {},
const MlFusedCtx fused = nullptr 
)
inline

Definition at line 701 of file solver_multilevel.hpp.

Referenced by demSolveContacts().

◆ solvePositionKokkos()

void peclet::dem::solvePositionKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem posPred,
Kokkos::View< const float *[4], CpMem quatPred,
Kokkos::View< const float *[4], CpMem quatStatic,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< float *[3], CpMem deltaPos,
Kokkos::View< float *[4], CpMem deltaQuat,
Kokkos::View< int *, CpMem constraintCounts,
Kokkos::View< float, CpMem maxOverlap,
Kokkos::View< const int *, CpMem onlyColor = {},
int  colorFilter = 0 
)
inline

Accumulate XPBD position corrections for numContacts contacts.

Definition at line 36 of file solver_position.hpp.

Referenced by demSolveContacts().

◆ colorContactsKokkos()

int peclet::dem::colorContactsKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
int  numBodies,
Kokkos::View< int *, CpMem cColor,
Kokkos::View< long long *, CpMem bodyWinner,
Kokkos::View< std::uint64_t *, CpMem bodyMask,
int &  leftover,
Kokkos::View< const unsigned char *, CpMem sleepMask = {} 
)
inline

Greedy graph-colour the contacts (raw bodyA/bodyB): no two contacts sharing a body get the same colour.

Round-based max-index arbitration, identical machinery to colorManifoldsKokkos but over the per-contact graph with direct (non-realIdx) body slots; every contact is active. numBodies is the body-slot count (numParticles, incl. periodic ghosts, which the position solve corrects independently). Returns the number of colours used.

Definition at line 154 of file solver_position.hpp.

Referenced by demSolveContacts().

◆ colorContactsIncrementalKokkos()

int peclet::dem::colorContactsIncrementalKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
int  numBodies,
Kokkos::View< const unsigned long long *, CpMem prevKeys,
Kokkos::View< const int *, CpMem prevColor,
int  prevCount,
Kokkos::View< int *, CpMem cColor,
Kokkos::View< unsigned long long *, CpMem keysOut,
Kokkos::View< long long *, CpMem bodyWinner,
Kokkos::View< std::uint64_t *, CpMem bodyMask,
int &  leftover,
bool  forceFull,
Kokkos::View< const unsigned char *, CpMem sleepMask = {} 
)
inline

Incremental (warm-started) contact colouring for the single-GPU PGS position solve.

Twin of colorManifoldsIncrementalKokkos, but over the per-contact graph: key every contact by its canonical pair, carry the previous substep's colour by that key (sorted ledger), seed the per-body masks, and re-arbitrate only the NEW (-1) contacts. A pair can own MORE than one contact (non-spherical multi-point patches) and periodic ghost slots churn, so the carried colours are CONFLICT-CHECKED while the mask is built (a repeated colour on a shared body forces a full recolour that substep) — the sphere / non-periodic bed hits the fast path, everything else stays correct by falling back. forceFull bypasses the carry. keysOut holds this substep's contact keys for the subsequent commit. Returns the number of colours used.

Definition at line 253 of file solver_position.hpp.

Referenced by demSolveContacts().

◆ commitContactColorKokkos()

void peclet::dem::commitContactColorKokkos ( Kokkos::View< const unsigned long long *, CpMem keys,
Kokkos::View< const int *, CpMem color,
Kokkos::View< unsigned long long *, CpMem prevKeys,
Kokkos::View< int *, CpMem prevColor,
Kokkos::View< int *, CpMem perm,
int  numContacts 
)
inline

Commit this substep's per-contact (key, colour) sorted by key, for next substep's warm gather.

Definition at line 395 of file solver_position.hpp.

Referenced by demSolveContacts().

◆ solvePositionColoredGSKokkos()

bool peclet::dem::solvePositionColoredGSKokkos ( Kokkos::View< const ContactC *, CpMem contacts,
int  numContacts,
Kokkos::View< const int *, CpMem cColor,
int  numColors,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< float *[3], CpMem posPred,
Kokkos::View< const float *[4], CpMem quatPred,
Kokkos::View< const float *[4], CpMem quatStatic,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< float, CpMem maxOverlap,
Kokkos::View< float *, CpMem posLambdaAcc = {},
Kokkos::View< const int *, CpMem colorPerm = {},
const std::vector< int > *  colorOffs = nullptr,
const FusedSweepCtx fused = nullptr,
const FusedLoopSpec loop = nullptr 
)
inline

Colored Gauss–Seidel XPBD overlap solve: sweep the numColors colour classes in order, applying each contact's non-penetration correction directly to posPred (in place, translation only).

Same per-contact math as solvePositionKokkos — only the write-back differs (in-place RMW instead of atomic-accumulate + count-average). Race-free because a colour is an independent set of contacts. One outer call = one full sweep over all colours; the caller loops it positionIterations times. Dense-bucket mode (colorPerm/colorOffs from buildColorBucketsKokkos) covers only each colour's own contacts; the fused mode collapses the whole sweep into one kernel — both bit-identical.

Definition at line 509 of file solver_position.hpp.

Referenced by demSolveContacts().

◆ solveVelocityKokkos()

void peclet::dem::solveVelocityKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< const float *[3], CpMem velPred,
Kokkos::View< const float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate,
float  restitutionNormal,
float  restVelThreshold,
Kokkos::View< float *[3], CpMem deltaVel,
Kokkos::View< float *[3], CpMem deltaAngVel,
Kokkos::View< int *, CpMem velCounts,
Kokkos::View< const int *, CpMem onlyColor = {},
int  colorFilter = 0,
Kokkos::View< const unsigned char *, CpMem persistent = {},
Kokkos::View< const float *[3], CpMem posPred = {},
F3  gHat = {},
Kokkos::View< const unsigned char *, CpMem grounded = {} 
)
inline

Accumulate normal-restitution velocity deltas for numManifolds manifolds.

Definition at line 39 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ applyVelocityDeltasAveragedKokkos()

template<class V3 , class Vi >
void peclet::dem::applyVelocityDeltasAveragedKokkos ( int  n,
V3  velPred,
V3  angVelPred,
V3  deltaVel,
V3  deltaAngVel,
Vi  velCounts 
)
inline

Apply the accumulated velocity deltas AVERAGED by the per-body manifold count — the velocity- solve twin of the position solve's constraint-count averaging (applyUpdatesKokkos).

A body in a dense pile receives one full-strength impulse per touching manifold; the raw Jacobi SUM overshoots by ~the contact count and diverges hard for e ≳ 0.5 (a settled 180k glass-bead bed switched to e=0.8 grew |v| by ~5x per substep). A lone binary collision (count 1) is unchanged.

Definition at line 233 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ colorManifoldsKokkos()

int peclet::dem::colorManifoldsKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
int  numReal,
Kokkos::View< int *, CpMem mColor,
Kokkos::View< long long *, CpMem bodyWinner,
Kokkos::View< std::uint64_t *, CpMem bodyMask,
int &  leftover,
Kokkos::View< const unsigned char *, CpMem sleepMask = {} 
)
inline

Greedy graph-colour the manifolds: no two manifolds sharing a real body get the same colour.

Round-based max-index (Jones–Plassmann) arbitration, no adjacency lists: each round every still- uncoloured manifold contends for its endpoint bodies via atomicMax(bodyWinner, idx); a manifold that wins BOTH endpoints has no uncoloured conflict this round, so it commits the lowest colour free at either endpoint (a per-body bitmask) — and, as the unique winner of those bodies, updates the masks race-free. Inactive manifolds (empty, or the periodic-dedup duplicate realA>realB) are tagged -2 and skipped by the solve. Runs once per step; the colouring is reused across the velocity sweeps. Returns the number of colours used (0 if no active manifolds).

Definition at line 277 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ colorManifoldsIncrementalKokkos()

int peclet::dem::colorManifoldsIncrementalKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
int  numReal,
Kokkos::View< const unsigned long long *, CpMem prevKeys,
Kokkos::View< const int *, CpMem prevColor,
int  prevCount,
Kokkos::View< int *, CpMem mColor,
Kokkos::View< long long *, CpMem bodyWinner,
Kokkos::View< std::uint64_t *, CpMem bodyMask,
int &  leftover,
bool  forceFull,
Kokkos::View< const unsigned char *, CpMem sleepMask = {} 
)
inline

Incremental (warm-started) manifold colouring for the single-GPU PGS path.

Carry each surviving pair's colour from the previous substep — matched by pair key against the sorted (prevPairKeys, prevColor) ledger committed alongside the warm impulses — seed the per-body colour masks from those carried colours, then run the SAME Jones-Plassmann arbitration ONLY over the NEW (colour == -1) manifolds. Result is bit-identical in FORM to colorManifoldsKokkos (a valid body-disjoint colouring + numColors); only the assignment differs.

VALIDITY (why the carried colours need no re-arbitration): within a single-GPU run realIndices are stable, so a surviving pair key maps to the same two real bodies. Last substep's colouring was valid, so any two survivors sharing a real body carried DIFFERENT colours — the survivor subset is still a valid colouring. A conflict edge can only appear via a NEW manifold, which is arbitrated against the frozen (carried) masks. Hence seeding the masks non-atomically-safe with atomic_or and running the rounds over the -1 set reproduces a valid colouring. forceFull bypasses the carry entirely (fresh substep / colour-count-creep recompaction) — identical output to colorManifoldsKokkos. Single-GPU only: under MPI migration a carried colour can cross into a neighbourhood it never arbitrated against, so the distributed path keeps the full recolour.

Definition at line 395 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ computeVn0Kokkos()

void peclet::dem::computeVn0Kokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const float *[3], CpMem velPred,
Kokkos::View< const float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate,
Kokkos::View< float *, CpMem vn0,
Kokkos::View< float *[3], CpMem vt0 
)
inline

-— Warm-started projected Gauss-Seidel (PGS) velocity solve -— Nonsmooth contact dynamics (Moreau-Jean; Stewart-Trinkle LCP): per manifold an ACCUMULATED push impulse p >= 0 along the manifold normal, updated by colored GS sweeps and projected to p >= 0 (a contact may push, never pull; over-push is retracted in later sweeps).

At convergence the p's are the contact force network (x dt): a resting pile's chains carry exactly the weight above them, all velocities -> 0 – statics with no notion of "lower body" or gravity direction, momentum-conserving at every contact (the wall provides the reaction). Deep-pile convergence is bought by WARM STARTING: p is seeded from the previous substep's converged value (matched by pair key) and applied up front, so a static network is re-established in ~1 sweep per substep. Restitution enters as the target relative velocity -e*vn0 on the PRE-SOLVE approach vn0 (with the resting threshold), so fresh binary impacts reproduce the one-shot impulse exactly. Pre-solve approach velocity per manifold (the restitution bias), measured BEFORE the warm-start application. Same kinematics as the sweep kernel.

Definition at line 543 of file solver_velocity.hpp.

References add3(), peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, cross3v(), dot3(), peclet::dem::detail::ld3(), peclet::dem::ManifoldC::normal_sum, peclet::dem::ManifoldC::num_points, peclet::dem::ManifoldC::rA_sum, peclet::dem::ManifoldC::rB_sum, scale3(), sub3(), peclet::dem::ManifoldC::torque_armA_sum, peclet::dem::ManifoldC::torque_armB_sum, peclet::dem::ManifoldC::wallVel_sum, peclet::dem::F3::x, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

Referenced by demSolveContacts().

◆ updateRestitutionBankKokkos()

void peclet::dem::updateRestitutionBankKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< const float *[3], CpMem velPred,
Kokkos::View< const float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate,
float  restitutionNormal,
float  restVelThreshold,
Kokkos::View< const float *, CpMem vn0,
Kokkos::View< const float *, CpMem lambdaAcc,
Kokkos::View< const float *, CpMem restRel,
Kokkos::View< float *, CpMem restBank,
Kokkos::View< float *, CpMem restVPeak 
)
inline

Event-level (Poisson) restitution bookkeeping, once per substep AFTER all velocity phases (restitutionModel == 1 only).

Per pair, two carried floats define the current impact EVENT:

  • restVPeak — the event's peak physical approach speed (> 0 = event active). Set/refreshed whenever the pre-solve approach is kinetic (v0til > vRest*lenN), decayed by 1/256 per substep, cleared once it ages below the resting threshold: a buried/absorbed event's bank EVAPORATES (energy went to heat) instead of popping the pile later. A resting pile never sets vPeak, so it never banks — the dense-pile energy-bomb guard.
  • restBank — the remaining OWED separation impulse: while the event is active the contact banks e x its applied normal-impulse FLUX every substep (pTot - pR, the momentum the chain actually transmitted; a per-substep kinetic gate would miss the co-moving compression plateau where vn0 ~ 0), minus the separation already delivered (pR — so a clean one-substep binary impact nets exactly 0), minus what the sweep's release channel injected (restRel).

Definition at line 612 of file solver_velocity.hpp.

References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, dot3(), peclet::dem::detail::genInvMass(), peclet::dem::detail::ld3(), peclet::dem::ManifoldC::normal_sum, peclet::dem::ManifoldC::num_points, peclet::dem::ManifoldC::rA_sum, peclet::dem::ManifoldC::rB_sum, peclet::dem::ManifoldC::restitution_sum, scale3(), sub3(), peclet::dem::ManifoldC::torque_armA_sum, peclet::dem::ManifoldC::torque_armB_sum, peclet::dem::ManifoldC::wallVel_sum, peclet::dem::F3::x, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.

Referenced by demSolveContacts().

◆ decayBodyOrphanKokkos()

void peclet::dem::decayBodyOrphanKokkos ( Kokkos::View< float *, CpMem orphan,
Kokkos::View< float *, CpMem orphanVPeak,
int  numOwned,
float  restVelThreshold 
)
inline

Orphan-account aging, once per substep over the OWNED bodies: both the balance and the carried event peak decay 1/64 per substep (e-fold ~3 ms at dt = 5e-5 — long enough for the rebound payout, which completes within ~2 ms of turnaround, short enough that a BURIED impactor's slowly re-fed credit cannot keep fluidizing its crater: with the pair-state 1/256 decay the 100k Dosta plateau crept 0.007 deeper), and once the peak ages below the resting threshold the whole account evaporates — stranded credit on a settling body never pops the pile later.

Definition at line 711 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ scatterOrphanBanksKokkos()

void peclet::dem::scatterOrphanBanksKokkos ( Kokkos::View< const unsigned long long *, CpMem prevKeys,
Kokkos::View< const float *, CpMem prevRestBank,
Kokkos::View< const float *, CpMem prevRestVPeak,
Kokkos::View< const unsigned char *, CpMem matched,
int  prevCount,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< float *, CpMem orphan,
Kokkos::View< float *, CpMem orphanVPeak,
Kokkos::View< const int *, CpMem gidSorted = {},
Kokkos::View< const int *, CpMem slotSorted = {} 
)
inline

Orphan transfer: previous-ledger entries NOT matched by any current manifold (their pair died this substep) credit their remaining owed budget to the endpoint BODIES, mass-weighted — the heavier endpoint keeps the larger share (energy of a later release scales J^2/2m, so the light grain is the dangerous store and the heavy impactor is both the safe one and the event's physical carrier); boundary pairs (wall endpoint) credit everything to the particle.

The carried event peak joins by max. Key components are keyIdx identities: REAL slots on the single-GPU path (direct index); global ids under MPI — resolved through the sorted (gidSorted, slotSorted) map (an endpoint owned by another rank simply isn't found here; that rank's redundant ledger copy credits it).

Definition at line 738 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ restBankStatsKokkos()

std::tuple< double, float, int > peclet::dem::restBankStatsKokkos ( Kokkos::View< const float *, CpMem bank,
int  n 
)
inline

Poisson-restitution diagnostics: (sum, max, count>0) over the committed owed-impulse store (namespace scope: nvcc forbids KOKKOS_LAMBDA in member functions).

Definition at line 802 of file solver_velocity.hpp.

Referenced by peclet::dem::Simulation::restBankStats(), and peclet::dem::Simulation::restOrphanStats().

◆ computeSideFlagsKokkos()

void peclet::dem::computeSideFlagsKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const unsigned char *, CpMem persistent,
Kokkos::View< const unsigned char *, CpMem grounded,
Kokkos::View< const float *[3], CpMem posPred,
Kokkos::View< const float *[3], CpMem velPred,
F3  gHat,
float  riseThr,
Kokkos::View< unsigned char *, CpMem sideFlag,
Kokkos::View< const float *, CpMem vn0,
float  approachThr 
)
inline

Decide each persistent contact's treatment ONCE per substep (before any impulse is applied): 0 = symmetric momentum-conserving PGS, 1 = one-sided with B as the held ground side, 2 = A held.

One-sided requires the ground side grounded (contact path to the floor) and not rising. Flagged contacts get their warm impulse ZEROED: their ground side is held externally (recursively down to the floor), so the correct per-substep impulse is only the ~m g dt refill, accumulated from zero – warm-applying last substep's chain impulse one-sidedly would inject the whole column weight as upward velocity (measured: instant crush + churn from the inconsistent ledger).

Definition at line 830 of file solver_velocity.hpp.

References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, dot3(), peclet::dem::detail::ld3(), ldF3(), peclet::dem::ManifoldC::num_points, sub3(), peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.

Referenced by demSolveContacts().

◆ warmStartApplyKokkos()

void peclet::dem::warmStartApplyKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< float *[3], CpMem velPred,
Kokkos::View< float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const float *, CpMem warmP,
Kokkos::View< float *[3], CpMem warmT 
)
inline

◆ makePGSManifoldSweep()

PGSManifoldSweep peclet::dem::makePGSManifoldSweep ( Kokkos::View< const ManifoldC *, CpMem manifolds,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< float *[3], CpMem velPred,
Kokkos::View< float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate,
float  restitutionNormal,
float  restVelThreshold,
Kokkos::View< float, CpMem maxApproach,
Kokkos::View< float, CpMem maxApproachQS,
Kokkos::View< float *, CpMem lambdaAcc,
Kokkos::View< const float *, CpMem vn0,
Kokkos::View< const unsigned char *, CpMem sideFlag,
Kokkos::View< float *[3], CpMem lambdaT,
float  frictionDynamic,
Kokkos::View< const float *[3], CpMem vt0,
float  restitutionTangent,
Kokkos::View< const float *, CpMem posImpulse,
Kokkos::View< float *, CpMem restBank,
Kokkos::View< float *, CpMem restRel,
Kokkos::View< const unsigned char *, CpMem restPersistent,
Kokkos::View< const float *, CpMem restVPeak,
F3  restGHat,
Kokkos::View< const unsigned char *, CpMem restGrounded,
bool  restNewtonOff,
bool  restOneSided,
Kokkos::View< float *, CpMem restOrphan,
Kokkos::View< const float *, CpMem restOrphanVPeak 
)
inline

Build the shared per-manifold sweep functor (the colored launch loop, the fused kernels and the fused multilevel iteration loop all run this one body).

maxApproachQS empty => aliased to maxApproach (the duplicate atomic_max is idempotent).

Definition at line 1412 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ solveVelocityPGSKokkos()

bool peclet::dem::solveVelocityPGSKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem mColor,
int  numColors,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< float *[3], CpMem velPred,
Kokkos::View< float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate,
float  restitutionNormal,
float  restVelThreshold,
Kokkos::View< float, CpMem maxApproach,
Kokkos::View< float *, CpMem lambdaAcc,
Kokkos::View< const float *, CpMem vn0,
Kokkos::View< const unsigned char *, CpMem sideFlag,
Kokkos::View< float *[3], CpMem lambdaT,
float  frictionDynamic,
Kokkos::View< const float *[3], CpMem vt0 = {},
float  restitutionTangent = 0.0f,
Kokkos::View< const float *, CpMem posImpulse = {},
Kokkos::View< float, CpMem maxApproachQS = {},
Kokkos::View< float *, CpMem restBank = {},
Kokkos::View< float *, CpMem restRel = {},
Kokkos::View< const unsigned char *, CpMem restPersistent = {},
Kokkos::View< const float *, CpMem restVPeak = {},
F3  restGHat = {},
Kokkos::View< const unsigned char *, CpMem restGrounded = {},
bool  restNewtonOff = false,
bool  restOneSided = false,
Kokkos::View< float *, CpMem restOrphan = {},
Kokkos::View< const float *, CpMem restOrphanVPeak = {},
Kokkos::View< const int *, CpMem colorPerm = {},
const std::vector< int > *  colorOffs = nullptr,
const FusedSweepCtx fused = nullptr,
const FusedLoopSpec loop = nullptr 
)
inline

Returns true when the sweep (or, with loop, the whole iteration loop) was submitted; false ONLY in loop mode when the fused path is unavailable — the caller then runs its own host-side iteration loop (which calls back in per-iteration mode).

Definition at line 1462 of file solver_velocity.hpp.

Referenced by demSolveContacts().

◆ buildLevelColorBucketsKokkos()

void peclet::dem::buildLevelColorBucketsKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem realIdx,
Kokkos::View< const int *, CpMem mColor,
Kokkos::View< const int *, CpMem heights,
Kokkos::View< int *, CpMem keys,
Kokkos::View< int *, CpMem perm,
std::vector< std::pair< int, int > > &  buckets 
)
inline

Bucket the active coloured manifolds by (support level, colour) for the level-ordered ("multilevel") stabilization sweeps.

A manifold's level is the smaller of its bodies' height-from-floor BFS levels (wall/plane manifolds sit at their body's level, i.e. 0), clamped to 1023; ungrounded manifolds land in the last buckets. key = level*64 + colour; key-sorting a permutation groups each (level, colour) bucket contiguously, and the host bucket list (begin, end into the permutation) drives the ordered sweeps. Inactive and uncoloured manifolds (colour < 0: periodic dups, empty, mask-saturation leftovers – the main loop's Jacobi fallback owns those) are keyed out entirely.

Definition at line 1541 of file solver_velocity.hpp.

References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, and peclet::dem::ManifoldC::num_points.

Referenced by demSolveContacts().

◆ solveVelocityPGSBucketsKokkos()

void peclet::dem::solveVelocityPGSBucketsKokkos ( const PGSManifoldSweep f,
Kokkos::View< const int *, CpMem perm,
const std::vector< std::pair< int, int > > &  buckets,
bool  topDown 
)
inline

Level-ordered symmetric sweep: launch one PGS kernel per (level, colour) bucket, ascending (bottom-up: a chain's load drains towards the floor in ~one pass) or descending (top-down: the return pass carries rebound waves back up).

Same impulse math and lambda >= 0 projection as the colored sweep (shared PGSManifoldSweep) – fully symmetric, exact momentum conservation; the ordering only accelerates transport. Launches are stream-ordered, so the Gauss-Seidel dependency between buckets needs no per-bucket fence.

Definition at line 1593 of file solver_velocity.hpp.

References peclet::dem::PGSManifoldSweep::solveOne().

Referenced by demSolveContacts().

◆ solveVelocityColoredGSKokkos()

void peclet::dem::solveVelocityColoredGSKokkos ( Kokkos::View< const ManifoldC *, CpMem manifolds,
int  numManifolds,
Kokkos::View< const int *, CpMem mColor,
int  numColors,
Kokkos::View< const float *, CpMem invMass,
Kokkos::View< const float *[3], CpMem invInertia,
Kokkos::View< const float *[4], CpMem quat,
Kokkos::View< float *[3], CpMem velPred,
Kokkos::View< float *[3], CpMem angVelPred,
Kokkos::View< const int *, CpMem realIdx,
float  growthRate,
float  restitutionNormal,
float  restVelThreshold,
Kokkos::View< float, CpMem maxApproach,
Kokkos::View< const unsigned char *, CpMem persistent = {},
Kokkos::View< const float *[3], CpMem posPred = {},
F3  gHat = {},
Kokkos::View< const unsigned char *, CpMem grounded = {} 
)
inline

Colored Gauss–Seidel normal-restitution solve: sweep the numColors colour classes in order, applying each manifold's impulse directly to velPred/angVelPred (in place).

Same per-manifold impulse math as solveVelocityKokkos (growth-velocity term, approach gate, resting-contact e=0 threshold, and the R·(invI_local·(Rᵀ J))·… world-space angular update) — only the write-back differs (in-place RMW instead of atomic-accumulate + count-average). Race-free because a colour is an independent set of manifolds. One outer call = one full sweep over all colours; the caller loops it velocityIterations times.

Definition at line 1615 of file solver_velocity.hpp.

Referenced by demSolveContacts().

Variable Documentation

◆ kLevelInf

constexpr int peclet::dem::kLevelInf = 1 << 28
inlineconstexpr

Height-from-floor BFS levels for the level-ordered ("multilevel") stabilization pass: 0 at a wall/plane contact, else 1 + min over supporting contacts, kLevelInf with no contact path to the floor.

Recomputed FRESH each time the pass triggers – no warm start and no decay: a stale-low height would mis-order the sweeps, and the pass runs rarely enough that the exact BFS (early exit once a sweep changes nothing) is affordable. The support-orientation test (up vs 0.3|dx|) matches updateGroundedLevelsKokkos; ghost-slot positions keep the pair geometry periodic-aware.

Definition at line 286 of file contact_preprocessing.hpp.

Referenced by computeHeightLevelsKokkos().

◆ kMaxMaterials

constexpr int peclet::dem::kMaxMaterials = 8
constexpr

Pair-material lookup: flat [K*K*2] table, entry ((a*K + b)*2) = restitution, +1 = friction.

Definition at line 79 of file narrowphase.hpp.

Referenced by hertzPairEMu(), and peclet::dem::Simulation::setPairMaterial().

◆ kMlMaxLevels

constexpr int peclet::dem::kMlMaxLevels = 10
inlineconstexpr

6-bit colour slots per level in the packed word; slot value 63 = not crossing / not eligible at that level (skipped by the coarse sweeps).

Definition at line 43 of file solver_multilevel.hpp.

Referenced by demMakeMlFusedCtx().

◆ kMlSlotSkip

constexpr int peclet::dem::kMlSlotSkip = 63
inlineconstexpr

Definition at line 44 of file solver_multilevel.hpp.