|
peclet-dem 1.1.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
|
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 | DebugContactCapture |
| TEST-ONLY host capture of one distributed substep's contact ownership (C++ only; filled by demStepMpi when Particles::debugCapture is set, never read by the step): the owned contacts [0, ncOwned) after the partition and the owned predicted state they were detected on. More... | |
| 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 | MlBodyViews |
| The per-body inputs of the rigid coarse space (§2.3-§2.5): the predicted positions (the member offsets d_q), the predicted angular velocities (restricted and prolonged), the orientations of the fine PGS and the coarse vertices' inverse inertia invIc = invInertia k / max(1, a). More... | |
| struct | MlCoarseSweep |
| The per-manifold coarse-PGS body (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 | PhaseCopies |
| One solve phase's body copies (docs/contact_solve_framework.md §4.4, §4.5, §WO-4 item 2): the hub copies of the colouring (extra slots [slotBase, slotBase + nCopies) appended to the SoA, per-edge slot overrides) and the fold GROUPS – one per body updated through more than one slot in the phase (a hub's base + copies; in demStep's position phase also the periodic images of a body). 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 | PosUnits |
| The position units of a contact list as a CSR (§4.3): unit u owns the contacts list(start(u)) . More... | |
| struct | RankK |
| Rank-level M (docs/contact_solve_framework.md §13.3) as the hooks expose it to the driver: whether this rank reconciles copies with neighbours at all (it sends or receives ghosts). More... | |
| struct | ShapeDesc |
| Portable mirror of ShapeDescriptor (analytic fields + a flat-array point shell). More... | |
| class | ShapeRegistry |
| Host-side shape registry (Layer 1). More... | |
| class | Simulation |
| Host-facing facade with std::vector setters/getters (binding-agnostic). More... | |
| struct | SlotOverride |
| Per-edge slot overrides of a phase's hub copies (docs/contact_solve_framework.md §4.4 item 5) plus the per-slot mass-split flag and relaxation of §4.5. 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 | SplitStats |
| diagnostics.split_stats() (docs/contact_solve_framework.md §WO-4 item 4, §13.5 WO-4b): the last substep's copies. More... | |
| struct | WallSdf |
| Static, world-space SDF container/geometry the particles collide against (a drum barrel, a hopper, a vibrating tray, ...). More... | |
| struct | XGateSpec |
| Rank-level X evaluated inline in the one-shot sweep (only for the manifolds of the colour being swept): the same test as computeXGateKokkos, without a separate pass over every manifold per iteration. 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 , SHAPE_SCENE = 4 } |
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. | |
| bool | normalOfA (const ContactC &c) |
| Which body's surface a contact's normal belongs to. | |
| constexpr int | wallContactId (int wallIndex) |
| Wall identity of a boundary contact (docs/contact_solve_framework.md §12 S6): a contact with a wall carries bodyB = -1 - wallIndex, where wallIndex runs over the analytic planes first ([0, numPlanes)) and then the SDF walls (numPlanes + w). | |
| constexpr int | wallIndexOf (int bodyB) |
| unsigned long long | pairKeyFromGids (unsigned a, unsigned b) |
The one 64-bit pair identity every gid-keyed ledger uses (the XPBD persistent-contact and warm-start ledgers, the Hertz–Mindlin history): (min(a, b) << 32) | max(a, b), symmetric in (a, b) so a pair is one key whichever body is A. | |
| template<class KeysView > | |
| int | lowerBoundKey (const KeysView &keys, int count, unsigned long long key) |
lower_bound over a ledger's sorted keys: the first index whose key is >= key (count when none). | |
| 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={}, bool dedupTwins=true) |
| 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. | |
| template<class Owns > | |
| int | partitionContactsKokkos (Kokkos::View< ContactC *, CpMem > contacts, int n, const Owns &owns) |
Stable partition of contacts [0, n) by owns(contact): the owned ones first, [0, ncOwned), then the rest, each part in its old relative order (distributed step, docs/mpi_momentum_conservation.md §2.2). | |
| 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={}, int numOwnedContacts=-1, int *numOwnedManifolds=nullptr) |
Reduce n contacts to manifolds (one per unique canonical pair). | |
| std::uint64_t | unitKey (const ContactC &c) |
| Position-unit key (docs/contact_solve_framework.md §4.3, §12 S6): the canonical pair key for a body-body contact, and (bodyA << 32) | (unsigned)bodyB for a wall contact, which separates the walls of one body (bodyB = -1 - wallIndex, so the low word is 0xFFFFFFFF - wallIndex >= 2^31, never a body slot). | |
| int | buildPositionUnitsKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int n, Kokkos::View< int *, CpMem > unitStart, Kokkos::View< int *, CpMem > unitContacts, int numManifolds=-1) |
| Build the position units of contacts [0, n) (docs/contact_solve_framework.md §4.3, §12 S6): a unit is the set of contacts of one body pair, or of one body and one wall. | |
| 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) |
| peclet::core::Vec3< float > | toCoreVec (F3 p) |
| F3 -> core's Real-templated point type. Layout-identical; this is a type change, not a copy. | |
| 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, V3 extTorque) |
| 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, bool averaged=true) |
| 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. | |
| F3 | sdfGradShape (F3 p, const ShapeDesc &d, GridView grid) |
Outward gradient of a shape's SDF at canonical point p, NOT normalised (callers normalise, matching the previous finite-difference code). | |
| 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{}, bool twoWay=false) |
| 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{}, int wallIdBase=0) |
| 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{}, float globalScale=1.0f) |
globalScale multiplies every per-particle scale, exactly as the narrow-phase does (narrowphase.hpp: effScale = scale(i) * globalScale). | |
| 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< F3 > | genCylinderShell (float radius, float height, float thickness, float spacing) |
| std::vector< F3 > | genBoxShell (float hx, float hy, float hz, float spacing) |
| 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). | |
| template<class V > | |
| void | growCopyView (V &v, std::size_t n, const char *label) |
| Grow-only (re)allocation of a copy-machinery view to at least n entries. | |
| void | velocityEdgeEndsKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int nm, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > color, Kokkos::View< int *, CpMem > eA, Kokkos::View< int *, CpMem > eB) |
| Velocity-phase colouring edges: the vertices realIdx(bodyA / bodyB) of each manifold (-1: a wall end, or both ends of an inactive (-2) manifold). | |
| void | positionEdgeEndsKokkos (Kokkos::View< const ContactC *, CpMem > contacts, const PosUnits &units, int nu, Kokkos::View< const int *, CpMem > color, Kokkos::View< int *, CpMem > eA, Kokkos::View< int *, CpMem > eB) |
| Position-phase colouring edges: one per unit, the leader contact's raw (bodyA, bodyB); active = the unit is not sleep-masked (colour != -2). | |
| void | vertexDegreeKokkos (Kokkos::View< const int *, CpMem > eA, Kokkos::View< const int *, CpMem > eB, int nE, int nV, Kokkos::View< int *, CpMem > deg) |
| Per-vertex active degree over [0, nV) (§4.4 step 1). Wall edges have one endpoint. | |
| void | buildHubCopiesKokkos (Kokkos::View< const int *, CpMem > eA, Kokkos::View< const int *, CpMem > eB, int nE, int nV, int slotBase, Kokkos::View< const int *, CpMem > deg, PhaseCopies &H) |
| Build one phase's hub copies (§4.4 steps 2, 3 and 5): every vertex with d > kHubEdgeBudget active edges gets s = ceil(d / 32) copies – its own slot plus s - 1 slots appended at [slotBase, slotBase + nCopies). | |
| void | buildCopyGroupsKokkos (Kokkos::View< const int *, CpMem > realIdx, int span, int numReal, Kokkos::View< const int *, CpMem > deg, Kokkos::View< const float *[3], CpMem > imageShift, PhaseCopies &H, bool identityBodies=false) |
| Build the fold groups of a phase (§4.4 "local fold", §WO-4 item 2): every body with more than one slot among [0, span) (the phase's vertex slots) and the hub copies. | |
| void | buildSolveViewsKokkos (Particles &P, const PhaseCopies &H, int nSlots, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia) |
| Solve views of a phase (§4.5): invMassSolve / invInertiaSolve = the phase's masses on every slot in [0, nSlots), times k on every member of a group, and splitSlot = (k > 1). | |
| void | seedCopySlotStateKokkos (Particles &P, const PhaseCopies &H) |
| Seed the copy slots' read-only state from their hub vertex (§4.4 step 6): orientation, local inverse inertia and grounded level (velocity), predicted orientation (position). | |
| void | markCopySeedsKokkos (const PhaseCopies &H, Kokkos::View< float *[3], CpMem > x, Kokkos::View< float *[3], CpMem > w, Kokkos::View< float *, CpMem > orphan, Kokkos::View< float *, CpMem > orphanPeak, bool shareFromBase=false) |
| Mark the phase seed sigma of every group and re-seed its members from the base (§4.4 step 6, and after every rank sync): x(q) = sigma + shift(q); w likewise (velocity, no shift). | |
| void | foldCopiesKokkos (CpExec space, const PhaseCopies &H, Kokkos::View< float *[3], CpMem > x, Kokkos::View< float *[3], CpMem > w, Kokkos::View< float *, CpMem > orphan, Kokkos::View< float *, CpMem > orphanPeak, Kokkos::View< float, CpMem > consensus={}) |
| The local fold (§4.4), once per iteration after the sweep: per group T = sum over the ACTIVE members of (x(q) - sigma - shift(q)) (the M-consensus of §1.3: an inactive member carries no increment of its own, only the re-seeded consensus); the base takes sigma + T / k and every member is re-seeded to it (plus its shift). | |
| void | reseedCopiesKokkos (CpExec space, const PhaseCopies &H, Kokkos::View< float *[3], CpMem > x, Kokkos::View< float *[3], CpMem > w) |
| Re-seed every member from its base, sigma unchanged (the multilevel pass, after the coarse cycle has moved the bases; §4.4 "copies re-seeded again after the coarse cycle"). | |
| void | unfoldOrphanKokkos (const PhaseCopies &H, Kokkos::View< float *, CpMem > orphan) |
| Orphan accounts back from share form (before a rank sync and at the end of the velocity phase): the base holds the body's balance, the sum of its members' shares. | |
| void | activityHitVelocityKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int nm, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > color, SlotOverride ov, Kokkos::View< unsigned char *, CpMem > hit, int nSlots) |
| Rank-level activity pass (docs/contact_solve_framework.md §13.3 C4; the distributed step only), velocity phase: hit(slot) = 1 for every slot that is an end – through the hub-copy overrides, else realIdx – of an owned manifold of colour >= 0 in the final colouring. | |
| void | activityHitPositionKokkos (Kokkos::View< const ContactC *, CpMem > contacts, const PosUnits &units, int nu, Kokkos::View< const int *, CpMem > color, SlotOverride ov, Kokkos::View< unsigned char *, CpMem > hit, int nSlots) |
| The same over the position phase's units (raw slots of the leader contact, through the overrides). | |
| void | finishActivityKokkos (Kokkos::View< const unsigned char *, CpMem > hit, int nSlots, PhaseCopies &H, Kokkos::View< int *, CpMem > a) |
| a(q) from the pass (§13.3): hit(q) for a slot outside any group; at a hub base the number of its group's members (base + copies) that were hit, which also refills groupActive and groupK (floored at 1, WO-4's local fold divisor). | |
| void | buildSolveViewsRankKKokkos (Particles &P, const PhaseCopies &H, int nSlots, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const int *, CpMem > kRank) |
| Solve views under rank-level M (§13.3, §4.5): invMassSolve / invInertiaSolve = k x the body's masses on every slot in [0, nSlots) (nSlots = slotBase + the phase's copies), with k the slot's global active copy count kRank (owner-computed, forwarded); a hub copy takes its base's k. | |
| void | buildInvMassCoarseKokkos (Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const int *, CpMem > k, Kokkos::View< const int *, CpMem > a, int n, Kokkos::View< float *, CpMem > out) |
| The multilevel coarse vertex's inverse mass (§13.2): invMass(q) (k(q) / max(1, a(q))), the ratio computed first so that k = a gives invMass bit for bit. | |
| void | buildInvInertiaCoarseKokkos (Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const int *, CpMem > k, Kokkos::View< const int *, CpMem > a, int n, Kokkos::View< float *[3], CpMem > out) |
| The multilevel coarse vertex's inverse inertia (docs/contact_physics_followups.md §2.5): the same fraction a / k of the body's inertia as its mass, invInertia(q) (k(q) / max(1, a(q))) per component, the ratio computed first exactly as buildInvMassCoarseKokkos (k = a gives invInertia bit for bit). | |
| int | countInactiveAggregatedKokkos (Kokkos::View< const int *, CpMem > parent, int off, int nV, int nGroups1, Kokkos::View< const int *, CpMem > a) |
| Debug-build check (§13.2, §13.5 WO-5 item 4): the vertices with a = 0 that sit in a level-1 multilevel group of >= 2 members (must be none: an inactive copy never joins a coarse edge). | |
| int | countSplitBodiesKokkos (const PhaseCopies &H) |
| Count the bodies whose group has k > 1 (split_stats). | |
| int | countSplitAggregatedKokkos (Kokkos::View< const int *, CpMem > parent, int off, int nV, int nGroups1, Kokkos::View< const unsigned char *, CpMem > split) |
| split_stats.mlHubAggregated (§13.2's positive control): the vertices v in [0, nV) with split(v) != 0 (k > 1) whose level-1 multilevel group – parent(off + v), the first level's parent map – has at least two members. | |
| int | countLightHubsKokkos (const PhaseCopies &H, Kokkos::View< const int *, CpMem > eA, Kokkos::View< const int *, CpMem > eB, int nE, int nV, Kokkos::View< const float *, CpMem > invMass) |
| Light hubs (split_stats, R-P3): velocity hubs whose mass is below 10x the mean mass of their partners over the hub's active edges. | |
| 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). | |
| void | fillWorldRadiiKokkos (Vf scale, Vf rad, float gs, float bR, int n) |
| World radii rad(i) = scale(i) * globalScale * baseRadius over [0, n): the owned span before a step, owned + ghosts after periodic ghost generation or a halo gather. | |
| 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). | |
| int * | demIterCountSlot (Particles &P, int slot) |
| Diagnostics (docs/contact_solve_framework.md §12 S12): the device scalar a fused main loop writes its iteration count to (slot 0 velocity, 1 position), allocated on first use. | |
| int | demReadIterCount (const Particles &P, int slot) |
| The count a fused main loop wrote (one small readback, only with P.iterCounters on); -1 with the counters off (no fence, no copy). | |
| 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. | |
| 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 | contactArmsMid (const ContactC &c, F3 &rA, F3 &rB) |
| The single application point of a body-body contact: both lever arms moved to the contact midpoint, rA - dist n / 2 and rB + dist n / 2, so x_A + rA = x_B + rB (the shift of transformContact, contact_preprocessing.hpp). | |
| 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, bool dedupTwins=true) |
| 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 *[4], CpMem > quat, 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, int mode) |
| Fused-sweep policy. | |
| 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. | |
| float | hertzSphereRadius (int i, Kokkos::View< const float *, CpMem > rad, Kokkos::View< const float *, CpMem > scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, float globalScale) |
| A body's Hertz sphere radius: a SPHERE shape's own radius, scale * globalScale * params.x (the radius the XPBD narrow phase probes with); otherwise the world reach radius rad(i). | |
| 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, Kokkos::View< const float *, CpMem > scale={}, ScalarI shapeId={}, Kokkos::View< const ShapeDesc *, CpMem > shapes={}, float globalScale=1.0f) |
| 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. | |
| int | buildMlLevelGeometryKokkos (const MlScratch &S, int off, int ng, int numReal, Kokkos::View< const float *[3], CpMem > posPred, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > invIc) |
| The per-level geometry of the rigid coarse space (docs/contact_physics_followups.md §2.3), over the composed body -> group map S.grp of the level just built (groups [off, off + ng)): | |
| 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={}, const MlBodyViews &body={}) |
| 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. | |
| MlCoarseSweep | makeMlCoarseSweep (Kokkos::View< const ManifoldC *, CpMem > manifolds, Kokkos::View< const int *, CpMem > realIdx, const MlScratch &S, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< const float *, CpMem > restRel, const MlBodyViews &body) |
| The coarse sweep over the multilevel scratch + the body views (the rigid views stay empty when the lazy pools are). | |
| 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, const MlBodyViews &body, 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 | countPositionJacobiKokkos (Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< int *, CpMem > counts) |
| Mass-split Jacobi count pass (docs/contact_solve_framework.md §3.1, D3): per body slot, the number of contacts the Jacobi position solve visits (every contact; a wall side counts nothing). | |
| 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, bool massSplit=false) |
Accumulate XPBD position corrections for numContacts contacts. | |
| bool | unitAsleep (const PosUnits &units, const Kokkos::View< const unsigned char *, CpMem > &sleepMask, int u) |
| A position unit is sleep-inactive iff all its contacts are sleep-masked (§4.3). | |
| 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={}, PosUnits units={}, SlotOverride ov={}, int vertexSpan=0) |
| 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={}, PosUnits units={}) |
| Incremental (warm-started) contact colouring for the single-GPU PGS position solve. | |
| void | expandUnitColorsKokkos (const PosUnits &units, int numUnits, Kokkos::View< const int *, CpMem > unitColor, Kokkos::View< int *, CpMem > contactColor) |
| Copy each position unit's colour onto its contacts (contactColor(i) = unitColor(unit of i)). | |
| 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, const PosUnits &units, 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, SlotOverride ov={}, Kokkos::View< float, CpMem > posResidual={}, float omega=1.0f) |
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 | countVelocityJacobiKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< int *, CpMem > counts, bool dedupTwins=true) |
| Mass-split Jacobi count pass (docs/contact_solve_framework.md §3.1, D3): per body (REAL index), the number of manifolds the Jacobi velocity solve visits – num_points > 0, one manifold per periodic pair (the solve's realA > realB dedup); a wall side counts nothing. | |
| 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={}, bool massSplit=false, bool dedupTwins=true) |
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, bool averaged=true) |
| 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={}, SlotOverride ov={}, bool dedupTwins=true, int vertexSpan=0) |
| 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={}, bool dedupTwins=true) |
| 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, bool dedupTwins=true) |
| -— 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, bool dedupTwins=true) |
| 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={}, int ownedLimit=-1) |
| 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, bool dedupTwins=true) |
| 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, bool dedupTwins=true) |
| 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 float *, CpMem > restVPeak, Kokkos::View< float *, CpMem > restOrphan, Kokkos::View< const float *, CpMem > restOrphanVPeak, SlotOverride ov={}) |
| 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 float *, CpMem > restVPeak={}, 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, SlotOverride ov={}) |
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). | |
| int | xPopcount (unsigned long long m) |
| Rank-level X (docs/contact_solve_framework.md §1.4): the holder of a body whose velocity activity mask has several bits (ranks) in sync interval t – the colour t mod C if it is in the mask, else the (t mod popcount)-th set bit (lowest = 0th). | |
| int | xHolder (unsigned long long mask, long long t, int numColors) |
| void | computeXGateKokkos (Kokkos::View< const ManifoldC *, CpMem > manifolds, int nm, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const unsigned long long *, CpMem > velMask, Kokkos::View< unsigned char *, CpMem > gate, int color, int numColors, long long t) |
The per-manifold fire gate of sync interval t: 1 iff this rank (colour color) holds every endpoint whose mask names two or more ranks. | |
| long long | countUnfiredKokkos (Kokkos::View< const unsigned char *, CpMem > gate, int nm) |
| Diagnostics (iterCounters): the number of gated-off manifolds of one sweep. | |
| 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={}, SlotOverride ov={}, XGateSpec xg={}) |
Colored Gauss–Seidel normal-restitution solve: sweep the numColors colour classes in order, applying each manifold's impulse directly to velPred/angVelPred (in place). | |
| void | growContactBuffers (Particles &P, long nBodies, long floorWant=0) |
| Grow every maxContacts-sized collision buffer to match the CURRENT particle capacity. | |
| int | narrowPhaseGrow (Particles &P, int np, float margin) |
| Narrow phase with an automatically-grown contact buffer. | |
| 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. | |
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 std::uint64_t | kNonOwnedPairBit = 1ull << 63 |
| Distributed step: bit 63 of a manifold-reduction key marks a contact this rank sees but does not own (docs/mpi_momentum_conservation.md §2.2), so the sort puts the owned manifolds first. | |
| constexpr int | kColorPalette = 64 |
| Colouring palette (docs/contact_solve_framework.md §4.2 item 1): the greedy takes the lowest colour free at both endpoints among bits 0..63 of the uint64 mask and never forces one. | |
| constexpr int | kColorUncolourable = -3 |
| constexpr int | kMaxMaterials = 8 |
| Pair-material lookup: flat [K*K*2] table, entry ((a*K + b)*2) = restitution, +1 = friction. | |
| constexpr double | kPi = 3.14159265358979323846 |
| constexpr int | kHubEdgeBudget = 32 |
| Hub edge budget (§4.4): a colouring vertex with more active edges is split into ceil(d / kHubEdgeBudget) copies, so no copy carries more than 32 and the 64-colour greedy provably succeeds (§1.6). | |
| constexpr float | kSplitOmegaVelocity = 1.0f |
| Split relaxation (§4.5, §13.1): the PGS normal step on an edge touching a mass-split slot is scaled by kSplitOmegaVelocity before the clamp (1: no relaxation; the pre-designed lever of R-F2, legitimate there because the PGS normal multiplier is accumulated and its clamp can retract an overshoot). | |
| 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 |
| constexpr long long | kMlPendingSkipBit = 1ll << 62 |
| Transient mark of the coarse colouring (docs/contact_solve_framework.md §4.4, "the multilevel
coarse colouring"): an edge that won its groups but found no free colour keeps slot 63 and is skipped at this level. | |
| using peclet::dem::BpExec = typedef Kokkos::DefaultExecutionSpace |
Definition at line 21 of file broadphase_arborx.hpp.
| using peclet::dem::BpMem = typedef BpExec::memory_space |
Definition at line 22 of file broadphase_arborx.hpp.
| using peclet::dem::CpExec = typedef Kokkos::DefaultExecutionSpace |
Definition at line 29 of file contact_preprocessing.hpp.
| using peclet::dem::CpMem = typedef CpExec::memory_space |
Definition at line 30 of file contact_preprocessing.hpp.
| using peclet::dem::V3 = typedef Kokkos::View<float* [3], CpMem> |
Definition at line 24 of file integration.hpp.
| using peclet::dem::V4 = typedef Kokkos::View<float* [4], CpMem> |
Definition at line 25 of file integration.hpp.
| using peclet::dem::Vf = typedef Kokkos::View<float*, CpMem> |
Definition at line 26 of file integration.hpp.
| using peclet::dem::Vi = typedef Kokkos::View<int*, CpMem> |
Definition at line 27 of file integration.hpp.
| using peclet::dem::PairTableView = typedef Kokkos::View<const float*, CpMem> |
Definition at line 100 of file narrowphase.hpp.
| using peclet::dem::MatIdView = typedef Kokkos::View<const unsigned char*, CpMem> |
Definition at line 101 of file narrowphase.hpp.
| using peclet::dem::PosView = typedef Kokkos::View<const float* [3], CpMem> |
Definition at line 104 of file narrowphase.hpp.
| using peclet::dem::QuatView = typedef Kokkos::View<const float* [4], CpMem> |
Definition at line 105 of file narrowphase.hpp.
| using peclet::dem::ScalarF = typedef Kokkos::View<const float*, CpMem> |
Definition at line 106 of file narrowphase.hpp.
| using peclet::dem::ScalarI = typedef Kokkos::View<const int*, CpMem> |
Definition at line 107 of file narrowphase.hpp.
| using peclet::dem::ShellView = typedef Kokkos::View<const float* [3], CpMem> |
Definition at line 108 of file narrowphase.hpp.
| using peclet::dem::GridView = typedef Kokkos::View<const float*, CpMem> |
Definition at line 109 of file narrowphase.hpp.
| using peclet::dem::FrManifoldCounts = typedef Kokkos::View<float* [2], CpMem> |
Definition at line 26 of file solver_friction.hpp.
| Enumerator | |
|---|---|
| SHAPE_GRID_SDF | |
| SPHERE | |
| HOLLOW_CYLINDER | |
| BOX | |
| SHAPE_SCENE | |
Definition at line 90 of file dem_portable.hpp.
|
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().
| bool peclet::dem::normalOfA | ( | const ContactC & | c | ) |
Which body's surface a contact's normal belongs to.
A forward contact (A's shell point against B's SDF) carries B's outward normal; a two-way reverse contact (B's shell point against A's SDF, set_shell_detection('two_way')) carries the negated outward normal of A and marks normal.w = 1. The position phase delta-rotates a stored normal with its own body's predicted rotation.
Definition at line 54 of file contact_preprocessing.hpp.
References peclet::dem::ContactC::normal, and peclet::dem::F4::w.
Referenced by peclet::dem::PositionContactSweep::solveContact().
|
constexpr |
Wall identity of a boundary contact (docs/contact_solve_framework.md §12 S6): a contact with a wall carries bodyB = -1 - wallIndex, where wallIndex runs over the analytic planes first ([0, numPlanes)) and then the SDF walls (numPlanes + w).
Every "is a wall" test is bodyB < 0; the index only separates the position units of one body against different walls. The manifold reduction key (pairKey) ignores it: all walls of a body still form ONE velocity manifold.
Definition at line 63 of file contact_preprocessing.hpp.
Referenced by detectBoundaryKokkos().
|
constexpr |
Definition at line 66 of file contact_preprocessing.hpp.
| unsigned long long peclet::dem::pairKeyFromGids | ( | unsigned | a, |
| unsigned | b | ||
| ) |
The one 64-bit pair identity every gid-keyed ledger uses (the XPBD persistent-contact and warm-start ledgers, the Hertz–Mindlin history): (min(a, b) << 32) | max(a, b), symmetric in (a, b) so a pair is one key whichever body is A.
a/b are whatever identity is stable for the run — the real index single-rank, the global id under MPI.
Definition at line 92 of file contact_preprocessing.hpp.
Referenced by hertzRebuildPairs(), and pairKeyOf().
| int peclet::dem::lowerBoundKey | ( | const KeysView & | keys, |
| int | count, | ||
| unsigned long long | key | ||
| ) |
lower_bound over a ledger's sorted keys: the first index whose key is >= key (count when none).
A hit is i < count && keys(i) == key; the index doubles as the ledger slot of the carried payload.
Definition at line 101 of file contact_preprocessing.hpp.
Referenced by hertzRebuildPairs(), and markPersistentManifoldsKokkos().
| 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 = pairKeyFromGids over (real body A, real body B); boundary manifolds (bodyB = -1: planes + SDF walls, merged per particle) use 0xFFFFFFFF for B. 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 118 of file contact_preprocessing.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, and pairKeyFromGids().
Referenced by markPersistentManifoldsKokkos().
|
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 128 of file contact_preprocessing.hpp.
References lowerBoundKey(), peclet::dem::ManifoldC::num_points, and pairKeyOf().
Referenced by demSolveContacts().
|
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 158 of file contact_preprocessing.hpp.
Referenced by demSolveContacts().
|
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 205 of file contact_preprocessing.hpp.
Referenced by demSolveContacts().
|
inline |
Copy this substep's keys into prevKeys and sort them for next substep's binary search.
Definition at line 253 of file contact_preprocessing.hpp.
|
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 271 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().
|
inline |
Definition at line 320 of file contact_preprocessing.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, dot3(), kLevelInf, ldF3(), peclet::dem::ManifoldC::num_points, sub3(), peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by demSolveContacts().
|
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 371 of file contact_preprocessing.hpp.
Referenced by buildCoarseBucketsKokkos(), and demSolveContacts().
| 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 407 of file contact_preprocessing.hpp.
| 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 417 of file contact_preprocessing.hpp.
References peclet::dem::ContactC::bodyA, and peclet::dem::ContactC::bodyB.
Referenced by unitKey().
| 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).
Bit 63 (kNonOwnedPairBit) is masked: the identity on every key below 2^63.
Definition at line 472 of file contact_preprocessing.hpp.
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 481 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.
|
inline |
Stable partition of contacts [0, n) by owns(contact): the owned ones first, [0, ncOwned), then the rest, each part in its old relative order (distributed step, docs/mpi_momentum_conservation.md §2.2).
One exclusive scan + one scatter into a scratch copy; with every contact owned (np = 1 on a closed domain) the contacts are unchanged bit for bit. Returns ncOwned.
Definition at line 524 of file contact_preprocessing.hpp.
|
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).
Distributed step (docs/mpi_momentum_conservation.md §2.2): with numOwnedContacts >= 0 the contacts at index >= numOwnedContacts (not owned by this rank, after partitionContactsKokkos) get kNonOwnedPairBit in their key, so the sort puts the owned manifolds first, [0, nmOwned) in their old relative order, and the non-owned ones after them; *numOwnedManifolds receives nmOwned. The defaults reproduce the single-rank reduction exactly.
Definition at line 567 of file contact_preprocessing.hpp.
Referenced by demStep().
| std::uint64_t peclet::dem::unitKey | ( | const ContactC & | c | ) |
Position-unit key (docs/contact_solve_framework.md §4.3, §12 S6): the canonical pair key for a body-body contact, and (bodyA << 32) | (unsigned)bodyB for a wall contact, which separates the walls of one body (bodyB = -1 - wallIndex, so the low word is 0xFFFFFFFF - wallIndex >= 2^31, never a body slot).
Wall 0 keeps pairKey's value; pairKey itself is unchanged.
Definition at line 685 of file contact_preprocessing.hpp.
References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, and pairKey().
Referenced by buildPositionUnitsKokkos().
|
inline |
Build the position units of contacts [0, n) (docs/contact_solve_framework.md §4.3, §12 S6): a unit is the set of contacts of one body pair, or of one body and one wall.
Two key sorts: by unitKey to group (leader = the segment's smallest contact index), then by (leader, contact index) for the canonical CSR. Returns the unit count; unitStart gets numUnits + 1 entries. numManifolds, when given, is the manifold count of the same contacts: the manifold key (pairKey, all walls of a body merged; the solved range [0, n) is all owned, so the ownership bit is constant on it) is never finer than the unit key, so numManifolds == n already proves every unit is one contact and the identity CSR is written without the key sort (a serial host sort on the host backends) – the same result the sort would find.
Definition at line 716 of file contact_preprocessing.hpp.
References unitKey().
Referenced by demSolveContacts().
|
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 810 of file contact_preprocessing.hpp.
References peclet::dem::ManifoldC::num_points.
|
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 832 of file contact_preprocessing.hpp.
Referenced by demSolveContacts().
Definition at line 29 of file dem_portable.hpp.
References peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by accumulateNormalImpulseKokkos(), applyUpdatesKokkos(), applyVelocityAndPredictPositionKokkos(), applyVelocityDeltasKokkos(), computePlaneLoadKokkos(), computeVn0Kokkos(), detectBoundaryKokkos(), hertzForce(), hertzShapePairForcesKokkos(), predictVelocityKokkos(), peclet::dem::MlCoarseSweep::restrictAngular(), rotateVector(), peclet::dem::MlCoarseSweep::row(), peclet::dem::PositionContactSweep::solveContact(), solveContactFrictionKokkos(), and peclet::dem::PGSManifoldSweep::solveOne().
Definition at line 32 of file dem_portable.hpp.
References peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by accumulateNormalImpulseKokkos(), computeHeightLevelsKokkos(), computePlaneLoadKokkos(), computeSideFlagsKokkos(), computeVn0Kokkos(), detectBoundaryKokkos(), peclet::dem::mldetail::eligible(), hertzForce(), hertzMaxDisp2Kokkos(), hertzShapePairForcesKokkos(), peclet::dem::MlCoarseSweep::row(), peclet::dem::PositionContactSweep::solveContact(), solveContactFrictionKokkos(), peclet::dem::PGSManifoldSweep::solveOne(), updateGroundedLevelsKokkos(), updateRestitutionBankKokkos(), and warmStartApplyKokkos().
Definition at line 35 of file dem_portable.hpp.
References peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by accumulateNormalImpulseKokkos(), applyThermostatKokkos(), applyUpdatesKokkos(), applyVelocityAndPredictPositionKokkos(), computeVn0Kokkos(), detectBoundaryKokkos(), hertzForce(), hertzShapePairForcesKokkos(), predictVelocityKokkos(), peclet::dem::MlCoarseSweep::restrictAngular(), rotateVector(), peclet::dem::MlCoarseSweep::row(), solveContactFrictionKokkos(), peclet::dem::PGSManifoldSweep::solveOne(), peclet::dem::MlCoarseSweep::solveOne(), peclet::dem::mldetail::spinInertiaTimes(), updateRestitutionBankKokkos(), and warmStartApplyKokkos().
Definition at line 38 of file dem_portable.hpp.
References peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by accumulateNormalImpulseKokkos(), computeHeightLevelsKokkos(), computePlaneLoadKokkos(), computeSideFlagsKokkos(), computeVn0Kokkos(), detectBoundaryKokkos(), peclet::dem::mldetail::eligible(), peclet::dem::detail::genInvMass(), hertzForce(), hertzMaxDisp2Kokkos(), hertzShapePairForcesKokkos(), len3(), peclet::dem::MlCoarseSweep::row(), peclet::dem::PositionContactSweep::solveContact(), solveContactFrictionKokkos(), peclet::dem::PGSManifoldSweep::solveOne(), updateGroundedLevelsKokkos(), updateRestitutionBankKokkos(), and warmStartApplyKokkos().
| float peclet::dem::len3 | ( | F3 | v | ) |
Definition at line 41 of file dem_portable.hpp.
References dot3().
Referenced by hertzShapePairForcesKokkos().
Definition at line 44 of file dem_portable.hpp.
References peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by accumulateNormalImpulseKokkos(), computePlaneLoadKokkos(), computeVn0Kokkos(), peclet::dem::detail::computeW(), hertzShapePairForcesKokkos(), predictVelocityKokkos(), peclet::dem::MlCoarseSweep::prolongRigid(), peclet::dem::MlCoarseSweep::restrictAngular(), rotateVector(), peclet::dem::MlCoarseSweep::row(), solveContactFrictionKokkos(), peclet::dem::PGSManifoldSweep::solveOne(), and warmStartApplyKokkos().
Definition at line 47 of file dem_portable.hpp.
References peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by transformContact().
| F3 peclet::dem::ldF3 | ( | const V & | v, |
| int | i | ||
| ) |
Definition at line 53 of file dem_portable.hpp.
Referenced by accumulateNormalImpulseKokkos(), applyThermostatKokkos(), applyUpdatesKokkos(), applyVelocityAndPredictPositionKokkos(), applyVelocityDeltasKokkos(), computeHeightLevelsKokkos(), computePlaneLoadKokkos(), computeSideFlagsKokkos(), peclet::dem::mldetail::eligible(), finalCommitKokkos(), predictVelocityKokkos(), peclet::dem::PositionContactSweep::solveContact(), solveContactFrictionKokkos(), and updateGroundedLevelsKokkos().
| F4 peclet::dem::ldF4 | ( | const V & | v, |
| int | i | ||
| ) |
Definition at line 57 of file dem_portable.hpp.
Referenced by applyThermostatKokkos(), applyVelocityAndPredictPositionKokkos(), finalCommitKokkos(), predictVelocityKokkos(), and peclet::dem::PositionContactSweep::solveContact().
Definition at line 63 of file dem_portable.hpp.
References add3(), cross3v(), scale3(), peclet::dem::F4::w, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by detectBoundaryKokkos(), hertzShapePairForcesKokkos(), invRotateVector(), predictVelocityKokkos(), peclet::dem::PositionContactSweep::solveContact(), solveContactFrictionKokkos(), peclet::dem::PGSManifoldSweep::solveOne(), peclet::dem::mldetail::spinInertiaTimes(), and warmStartApplyKokkos().
Definition at line 68 of file dem_portable.hpp.
References rotateVector(), peclet::dem::F4::w, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by applyThermostatKokkos(), peclet::dem::detail::genInvMass(), hertzShapePairForcesKokkos(), predictVelocityKokkos(), solveContactFrictionKokkos(), peclet::dem::PGSManifoldSweep::solveOne(), peclet::dem::mldetail::spinInertiaTimes(), and warmStartApplyKokkos().
Definition at line 71 of file dem_portable.hpp.
References peclet::dem::F4::w, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by peclet::dem::PositionContactSweep::solveContact().
Definition at line 74 of file dem_portable.hpp.
References peclet::dem::F4::w, peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by peclet::dem::PositionContactSweep::solveContact().
| peclet::core::Vec3< float > peclet::dem::toCoreVec | ( | F3 | p | ) |
F3 -> core's Real-templated point type. Layout-identical; this is a type change, not a copy.
Definition at line 103 of file dem_portable.hpp.
References peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by peclet::dem::ShapeRegistry::addSdfShape(), peclet::dem::Simulation::addSdfWall(), sampleGridSdf(), sampleWallSdf(), sdfBox(), sdfEvalShape(), sdfGradShape(), sdfHollowCylinder(), sdfSphere(), and peclet::dem::ShapeRegistry::setSdfShape().
Definition at line 107 of file dem_portable.hpp.
References toCoreVec(), and peclet::dem::F4::x.
Referenced by sdfEval().
Definition at line 114 of file dem_portable.hpp.
References toCoreVec(), peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by sdfEval().
Definition at line 119 of file dem_portable.hpp.
References toCoreVec(), peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by sdfEval().
Definition at line 123 of file dem_portable.hpp.
References BOX, HOLLOW_CYLINDER, sdfBox(), sdfHollowCylinder(), sdfSphere(), and SPHERE.
Referenced by sdfEvalShape().
|
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().
|
inline |
Add accumulated velocity/angular deltas onto the predicted velocity, then clear the delta buffers.
Definition at line 104 of file integration.hpp.
References add3(), ldF3(), and peclet::dem::detail::st3().
Referenced by demSolveContacts().
|
inline |
Re-integration: persist solved velocity, trapezoidal position predict, quaternion integrate.
Definition at line 119 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().
|
inline |
Per-contact constraint-count pre-pass (active contacts, dist <= 0).
Definition at line 158 of file integration.hpp.
References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, and peclet::dem::ContactC::dist.
|
inline |
Jacobi count-averaged apply of position/velocity deltas, then clear deltas + counts.
averaged = false (the mass-split 'jacobi' diagnostic, docs/contact_solve_framework.md §3.1): the deltas are already true-mass corrections against copies of mass m / count, so the apply is a plain add (factor 1).
Definition at line 178 of file integration.hpp.
References add3(), ldF3(), scale3(), and peclet::dem::detail::st3().
Referenced by demSolveContacts().
|
inline |
Final commit: periodic wrap of the predicted position into the domain, commit position + quat.
Definition at line 197 of file integration.hpp.
References ldF3(), ldF4(), peclet::dem::Domain::max, peclet::dem::Domain::min, peclet::dem::Domain::periodic_x, peclet::dem::Domain::periodic_y, peclet::dem::Domain::periodic_z, peclet::dem::Domain::size, peclet::dem::detail::st3(), peclet::dem::detail::st4(), peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by demStep().
|
inline |
Definition at line 239 of file integration.hpp.
References invRotateVector(), ldF3(), ldF4(), peclet::dem::KE2::r, scale3(), peclet::dem::detail::st3(), peclet::dem::KE2::t, peclet::dem::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by demStep().
Growth mode: scale = target * factor (when active).
Definition at line 285 of file integration.hpp.
Referenced by demStep(), and peclet::dem::Simulation::setGrowthParams().
|
inline |
Definition at line 23 of file io.hpp.
Referenced by peclet::dem::Simulation::exportLammps(), and NB_MODULE().
|
inline |
Definition at line 86 of file io.hpp.
Referenced by peclet::dem::Simulation::exportSdf().
Definition at line 111 of file narrowphase.hpp.
Referenced by detectBoundaryKokkos(), hertzMaxDisp2Kokkos(), and hertzShapePairForcesKokkos().
Definition at line 114 of file narrowphase.hpp.
Referenced by detectBoundaryKokkos(), and hertzShapePairForcesKokkos().
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 (the kObject policy), 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 it).
RELOCATED (Layer 0 rung 3): the body is now peclet::core::geom::sampleGrid, which carries this and the wall variant below as ONE routine parameterised by GridExtension — the two used to be near-duplicate functions differing only in the residual's sign, which is exactly the kind of silent divergence that cost 71k grains once (see sampleWallSdf).
Definition at line 129 of file narrowphase.hpp.
References peclet::dem::ShapeDesc::grid, and toCoreVec().
Referenced by sdfEvalShape().
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 kContainer policy) — 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. That is why the sign is now a NAMED POLICY on one shared routine (Layer 0 rung 3) instead of a one-character difference between two copied functions.
Definition at line 143 of file narrowphase.hpp.
References peclet::dem::WallSdf::grid, peclet::dem::WallSdf::nodeCount, peclet::dem::WallSdf::nodes, peclet::dem::WallSdf::shapeRoot, peclet::dem::WallSdf::sign, and toCoreVec().
Referenced by hertzBuildWallCandidatesKokkos(), and peclet::dem::Simulation::wallSdfAt().
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 155 of file narrowphase.hpp.
References peclet::dem::ShapeDesc::nodeCount, peclet::dem::ShapeDesc::nodes, peclet::dem::ShapeDesc::params, sampleGridSdf(), sdfEval(), SHAPE_GRID_SDF, SHAPE_SCENE, peclet::dem::ShapeDesc::shapeRoot, toCoreVec(), and peclet::dem::ShapeDesc::type.
Referenced by hertzShapePairForcesKokkos(), and sdfGradShape().
Outward gradient of a shape's SDF at canonical point p, NOT normalised (callers normalise, matching the previous finite-difference code).
EXACT closed form for the analytic kinds (Layer 1). The old path spent SIX extra sdfEvalShape calls per shell point on a central difference with a fixed eps = 1e-4 in canonical units, which is both slower and less accurate: 1e-4 is a real length in canonical space, so a shape feature or a per-particle scale far from 1 degrades the normal. A grid SDF has no closed form and keeps the central difference.
Definition at line 175 of file narrowphase.hpp.
References BOX, HOLLOW_CYLINDER, peclet::dem::ShapeDesc::nodeCount, peclet::dem::ShapeDesc::nodes, peclet::dem::ShapeDesc::params, sdfEvalShape(), SHAPE_SCENE, peclet::dem::ShapeDesc::shapeRoot, SPHERE, toCoreVec(), peclet::dem::ShapeDesc::type, 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 hertzShapePairForcesKokkos().
|
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)).
One-way (the default, twoWay == false): A's probes – its shell points, or its centre and radius for a sphere – are tested against B's SDF, and nothing else. A thin rim, wall or edge of B pressed into a face of A can then sit between A's shell points unseen (docs/contact_physics_followups.md F2: 0.0235 penetration on tubes while 0.001 was reported).
Two-way (twoWay == true, Simulation::setShellDetection("two_way"); the XPBD narrow phase only – the Hertz engine has its own pair law and would double-count the stiffness):
Definition at line 235 of file narrowphase.hpp.
Referenced by narrowPhaseGrow().
|
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 = wallContactId(wallIdBase + wallIndex), wallIdBase = numPlanes (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 397 of file narrowphase.hpp.
Referenced by narrowPhaseGrow().
|
inline |
Per-real-particle contacts against explicit planes (point-shell shapes test each surface point; analytic spheres use centre-minus-radius).
bodyB = wallContactId(planeIndex); plane anchor in rB.
Definition at line 505 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(), wallContactId(), peclet::dem::F3::x, peclet::dem::F4::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by narrowPhaseGrow().
|
inline |
globalScale multiplies every per-particle scale, exactly as the narrow-phase does (narrowphase.hpp: effScale = scale(i) * globalScale).
It defaults to 1 so existing callers are unchanged; passing the simulation's real value is what makes the exported field agree with the simulated geometry.
Definition at line 29 of file output_sdf.hpp.
Referenced by peclet::dem::Simulation::getSdfGrid().
|
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 26 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().
|
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 44 of file periodicity.hpp.
Referenced by computeOverlapsKokkos(), and demStep().
|
inline |
Definition at line 27 of file shapes_portable.hpp.
References kPi.
Referenced by peclet::dem::ShapeRegistry::initializeShape().
|
inline |
Definition at line 86 of file shapes_portable.hpp.
Referenced by peclet::dem::ShapeRegistry::initializeShape().
|
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().
|
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().
|
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().
|
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().
|
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().
|
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().
|
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().
|
inline |
Grow-only (re)allocation of a copy-machinery view to at least n entries.
Definition at line 47 of file solve_copies.hpp.
Referenced by buildCopyGroupsKokkos(), buildHubCopiesKokkos(), buildSolveViewsKokkos(), buildSolveViewsRankKKokkos(), demSolveContacts(), and demStep().
|
inline |
Velocity-phase colouring edges: the vertices realIdx(bodyA / bodyB) of each manifold (-1: a wall end, or both ends of an inactive (-2) manifold).
§4.4 step 1: active = colour != -2.
Definition at line 54 of file solve_copies.hpp.
References peclet::dem::ManifoldC::bodyA, and peclet::dem::ManifoldC::bodyB.
Referenced by demSolveContacts().
|
inline |
Position-phase colouring edges: one per unit, the leader contact's raw (bodyA, bodyB); active = the unit is not sleep-masked (colour != -2).
Definition at line 69 of file solve_copies.hpp.
References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, and peclet::dem::PosUnits::leader().
Referenced by demSolveContacts().
|
inline |
Per-vertex active degree over [0, nV) (§4.4 step 1). Wall edges have one endpoint.
Definition at line 83 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
inline |
Build one phase's hub copies (§4.4 steps 2, 3 and 5): every vertex with d > kHubEdgeBudget active edges gets s = ceil(d / 32) copies – its own slot plus s - 1 slots appended at [slotBase, slotBase + nCopies).
Its incident edges, listed as (hub, edge index[, end]) and sorted, go round-robin: the j-th to copy j mod s (copy 0 = the base slot); an edge between two hubs is assigned independently at each end. Writes the per-edge overrides slotA / slotB (-1 = none) and copyBase. Deterministic: the order is the sorted key, never thread order.
Definition at line 103 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::copyBase, growCopyView(), peclet::dem::PhaseCopies::hubS, peclet::dem::PhaseCopies::hubVertex, kHubEdgeBudget, peclet::dem::PhaseCopies::maxHubDegree, peclet::dem::PhaseCopies::nCopies, peclet::dem::PhaseCopies::nHubs, peclet::dem::PhaseCopies::slotA, peclet::dem::PhaseCopies::slotB, and peclet::dem::PhaseCopies::slotBase.
Referenced by demSolveContacts().
|
inline |
Build the fold groups of a phase (§4.4 "local fold", §WO-4 item 2): every body with more than one slot among [0, span) (the phase's vertex slots) and the hub copies.
A slot's body is realIdx(slot) (a copy's is its hub vertex's), so in demStep's position phase a body's periodic images join its group; under MPI and in the velocity phase realIdx is the identity on the vertices and only hubs form groups. Members are sorted (body, slot), so the body's own slot – the smallest – comes first. k = the members with at least one active edge (a copy always has one). imageShift (empty = none) gives an image slot's periodic shift; a copy takes its hub vertex's.
identityBodies: every vertex slot is its own body (a copy's body is its hub vertex), so only hubs form groups. The velocity phase (vertices are realIdx slots; under MPI the §6.2 slot map makes the other slots of a body aliases, which must not join its group) and the distributed position phase (raw slots: every image slot is its own copy, reconciled at rank level, §13.3). On the single-rank velocity phase realIdx is the identity on [0, span), so it is the same grouping.
Definition at line 243 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::copyBase, peclet::dem::PhaseCopies::groupActive, peclet::dem::PhaseCopies::groupK, peclet::dem::PhaseCopies::groupShift, peclet::dem::PhaseCopies::groupSlot, peclet::dem::PhaseCopies::groupStart, growCopyView(), peclet::dem::PhaseCopies::nCopies, peclet::dem::PhaseCopies::nGroups, peclet::dem::PhaseCopies::seedW, peclet::dem::PhaseCopies::seedX, peclet::dem::PhaseCopies::slotBase, and peclet::dem::F3::x.
Referenced by demSolveContacts().
|
inline |
Solve views of a phase (§4.5): invMassSolve / invInertiaSolve = the phase's masses on every slot in [0, nSlots), times k on every member of a group, and splitSlot = (k > 1).
Built only while the phase has groups.
Definition at line 336 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::groupK, peclet::dem::PhaseCopies::groupSlot, peclet::dem::PhaseCopies::groupStart, growCopyView(), peclet::dem::Particles::invInertiaSolve, peclet::dem::Particles::invMassSolve, peclet::dem::PhaseCopies::nGroups, and peclet::dem::Particles::splitSlot.
Referenced by demSolveContacts().
|
inline |
Seed the copy slots' read-only state from their hub vertex (§4.4 step 6): orientation, local inverse inertia and grounded level (velocity), predicted orientation (position).
Definition at line 381 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::copyBase, peclet::dem::Particles::groundedLevel, peclet::dem::Particles::invInertia, peclet::dem::PhaseCopies::nCopies, peclet::dem::Particles::quat, peclet::dem::Particles::quatPred, and peclet::dem::PhaseCopies::slotBase.
Referenced by demSolveContacts().
|
inline |
Mark the phase seed sigma of every group and re-seed its members from the base (§4.4 step 6, and after every rank sync): x(q) = sigma + shift(q); w likewise (velocity, no shift).
With orphan (Poisson, velocity) every member's account becomes the share B / k of the base's balance B, and the peak the base's. shareFromBase (rank-level M, §13.3): the base already holds the share B / k_global (set by the opening / rank sync), and every member copies it.
Definition at line 410 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::groupK, peclet::dem::PhaseCopies::groupShift, peclet::dem::PhaseCopies::groupSlot, peclet::dem::PhaseCopies::groupStart, peclet::dem::PhaseCopies::nGroups, peclet::dem::PhaseCopies::seedW, and peclet::dem::PhaseCopies::seedX.
Referenced by demSolveContacts().
|
inline |
The local fold (§4.4), once per iteration after the sweep: per group T = sum over the ACTIVE members of (x(q) - sigma - shift(q)) (the M-consensus of §1.3: an inactive member carries no increment of its own, only the re-seeded consensus); the base takes sigma + T / k and every member is re-seeded to it (plus its shift).
w likewise. Orphan accounts (Poisson): every member takes (sum of the active members' accounts) / k, the peak their max. With consensus (§12 S14) the largest correction the fold applies to an active member's x, |T / k - (x(q) - sigma - shift(q))| (increment form: exactly 0 once the sweep stops moving the copies), is atomic-maxed into it; w, orphan and the result are unaffected.
Definition at line 463 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
inline |
Re-seed every member from its base, sigma unchanged (the multilevel pass, after the coarse cycle has moved the bases; §4.4 "copies re-seeded again after the coarse cycle").
Definition at line 543 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::groupShift, peclet::dem::PhaseCopies::groupSlot, peclet::dem::PhaseCopies::groupStart, and peclet::dem::PhaseCopies::nGroups.
Referenced by demSolveContacts().
|
inline |
Orphan accounts back from share form (before a rank sync and at the end of the velocity phase): the base holds the body's balance, the sum of its members' shares.
Definition at line 567 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::groupActive, peclet::dem::PhaseCopies::groupSlot, peclet::dem::PhaseCopies::groupStart, and peclet::dem::PhaseCopies::nGroups.
Referenced by demSolveContacts().
|
inline |
Rank-level activity pass (docs/contact_solve_framework.md §13.3 C4; the distributed step only), velocity phase: hit(slot) = 1 for every slot that is an end – through the hub-copy overrides, else realIdx – of an owned manifold of colour >= 0 in the final colouring.
A same-value store, so the order of the writers does not matter.
Definition at line 589 of file solve_copies.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, peclet::dem::SlotOverride::slotA(), and peclet::dem::SlotOverride::slotB().
Referenced by demSolveContacts().
|
inline |
The same over the position phase's units (raw slots of the leader contact, through the overrides).
Definition at line 609 of file solve_copies.hpp.
References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, peclet::dem::PosUnits::leader(), peclet::dem::SlotOverride::slotA(), and peclet::dem::SlotOverride::slotB().
Referenced by demSolveContacts().
|
inline |
a(q) from the pass (§13.3): hit(q) for a slot outside any group; at a hub base the number of its group's members (base + copies) that were hit, which also refills groupActive and groupK (floored at 1, WO-4's local fold divisor).
Copy slots get 0 (they are never packed; their solve mass takes the base's k). a is written on [0, nSlots + H.nCopies).
Definition at line 631 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::groupActive, peclet::dem::PhaseCopies::groupK, peclet::dem::PhaseCopies::groupSlot, peclet::dem::PhaseCopies::groupStart, peclet::dem::PhaseCopies::nCopies, and peclet::dem::PhaseCopies::nGroups.
Referenced by demSolveContacts().
|
inline |
Solve views under rank-level M (§13.3, §4.5): invMassSolve / invInertiaSolve = k x the body's masses on every slot in [0, nSlots) (nSlots = slotBase + the phase's copies), with k the slot's global active copy count kRank (owner-computed, forwarded); a hub copy takes its base's k.
splitSlot = (k > 1). k <= 1 keeps the true masses bit for bit.
Definition at line 663 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::copyBase, growCopyView(), peclet::dem::Particles::invInertiaSolve, peclet::dem::Particles::invMassSolve, peclet::dem::PhaseCopies::nCopies, peclet::dem::PhaseCopies::slotBase, and peclet::dem::Particles::splitSlot.
Referenced by demSolveContacts().
|
inline |
The multilevel coarse vertex's inverse mass (§13.2): invMass(q) (k(q) / max(1, a(q))), the ratio computed first so that k = a gives invMass bit for bit.
Definition at line 700 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
inline |
The multilevel coarse vertex's inverse inertia (docs/contact_physics_followups.md §2.5): the same fraction a / k of the body's inertia as its mass, invInertia(q) (k(q) / max(1, a(q))) per component, the ratio computed first exactly as buildInvMassCoarseKokkos (k = a gives invInertia bit for bit).
Definition at line 717 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
inline |
Debug-build check (§13.2, §13.5 WO-5 item 4): the vertices with a = 0 that sit in a level-1 multilevel group of >= 2 members (must be none: an inactive copy never joins a coarse edge).
Definition at line 733 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
inline |
Count the bodies whose group has k > 1 (split_stats).
Definition at line 753 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::groupK, and peclet::dem::PhaseCopies::nGroups.
Referenced by demSolveContacts().
|
inline |
split_stats.mlHubAggregated (§13.2's positive control): the vertices v in [0, nV) with split(v) != 0 (k > 1) whose level-1 multilevel group – parent(off + v), the first level's parent map – has at least two members.
Diagnostic only (reads the hierarchy, writes nothing the solve reads).
Definition at line 768 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
inline |
Light hubs (split_stats, R-P3): velocity hubs whose mass is below 10x the mean mass of their partners over the hub's active edges.
Definition at line 790 of file solve_copies.hpp.
References peclet::dem::PhaseCopies::hubVertex, and peclet::dem::PhaseCopies::nHubs.
Referenced by demSolveContacts().
|
inline |
Definition at line 53 of file solve_driver.hpp.
Referenced by computeOverlapsKokkos(), peclet::dem::Simulation::debugColoringConflicts(), peclet::dem::Simulation::debugColoringLeftovers(), demStep(), narrowPhaseGrow(), peclet::dem::Simulation::numContacts(), and peclet::dem::Simulation::numManifolds().
|
inline |
Definition at line 58 of file solve_driver.hpp.
Referenced by demSolveContacts().
|
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 66 of file solve_driver.hpp.
|
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 78 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().
World radii rad(i) = scale(i) * globalScale * baseRadius over [0, n): the owned span before a step, owned + ghosts after periodic ghost generation or a halo gather.
Every step driver (XPBD, overlap probe, force-based, their distributed forms) fills the radii through this one kernel. Fences the default instance: the callers' next launch on that instance is stream-ordered anyway, so the fence changes nothing about the result.
Definition at line 94 of file solve_driver.hpp.
Referenced by computeOverlapsKokkos(), demStep(), and demStepForce().
|
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 112 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().
|
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 134 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().
|
inline |
Diagnostics (docs/contact_solve_framework.md §12 S12): the device scalar a fused main loop writes its iteration count to (slot 0 velocity, 1 position), allocated on first use.
Definition at line 274 of file solve_driver.hpp.
References peclet::dem::Particles::iterCountDev.
Referenced by demSolveContacts().
|
inline |
The count a fused main loop wrote (one small readback, only with P.iterCounters on); -1 with the counters off (no fence, no copy).
Definition at line 281 of file solve_driver.hpp.
References peclet::dem::Particles::iterCountDev, and peclet::dem::Particles::iterCounters.
Referenced by demSolveContacts().
|
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 293 of file solve_driver.hpp.
References accumulateNormalImpulseKokkos(), peclet::dem::Particles::activityHit, activityHitPositionKokkos(), activityHitVelocityKokkos(), peclet::dem::Particles::angVel, peclet::dem::Particles::angVelPred, peclet::dem::Particles::aPos, applyUpdatesKokkos(), applyVelocityAndPredictPositionKokkos(), applyVelocityDeltasAveragedKokkos(), applyVelocityDeltasKokkos(), peclet::dem::Particles::asleep, peclet::dem::Particles::aVel, 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(), buildCopyGroupsKokkos(), buildHubCopiesKokkos(), buildInvInertiaCoarseKokkos(), buildInvMassCoarseKokkos(), buildLevelColorBucketsKokkos(), buildPositionUnitsKokkos(), buildSolveViewsKokkos(), buildSolveViewsRankKKokkos(), peclet::dem::Particles::capacity, peclet::dem::RankK::color, colorContactsIncrementalKokkos(), colorContactsKokkos(), colorManifoldsIncrementalKokkos(), colorManifoldsKokkos(), commitContactColorKokkos(), commitPairKeysLambdaKokkos(), peclet::dem::Particles::commitPerm, commitPosImpulseKokkos(), computeHeightLevelsKokkos(), computePlaneLoadKokkos(), computeSideFlagsKokkos(), computeVn0Kokkos(), computeXGateKokkos(), 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(), countInactiveAggregatedKokkos(), countLightHubsKokkos(), countPositionJacobiKokkos(), countSplitAggregatedKokkos(), countSplitBodiesKokkos(), countUnfiredKokkos(), countVelocityJacobiKokkos(), peclet::dem::Particles::cudaGraphs, decayBodyOrphanKokkos(), peclet::dem::Particles::deltaAngVel, peclet::dem::Particles::deltaPos, peclet::dem::Particles::deltaQuat, peclet::dem::Particles::deltaVel, demFusedWanted(), demIterCountSlot(), demMakeFusedCtx(), demMakeMlFusedCtx(), demReadIterCount(), peclet::dem::SplitStats::driftMigrations, peclet::dem::Particles::dt, peclet::dem::Particles::ensureCapacity(), expandUnitColorsKokkos(), peclet::dem::Particles::extForceActive, peclet::dem::Particles::extTorqueActive, finishActivityKokkos(), foldCopiesKokkos(), peclet::dem::Particles::frictionDynamic, peclet::dem::Particles::fusedBar, peclet::dem::Particles::fusedSweeps, gatherWarmLambdaKokkos(), peclet::dem::Particles::gid, peclet::dem::Particles::globalScale, peclet::dem::Particles::graphCache, peclet::dem::Particles::gravity, peclet::dem::Particles::groundedLevel, growCopyView(), peclet::dem::Particles::growthRate, peclet::dem::Particles::heightLevel, peclet::dem::Particles::imageShift, peclet::dem::Particles::incrementalColoring, peclet::dem::Particles::invInertia, peclet::dem::Particles::invInertiaCoarse, peclet::dem::Particles::invInertiaSolve, peclet::dem::Particles::invMass, peclet::dem::Particles::invMassCoarse, peclet::dem::Particles::invMassSolve, peclet::dem::Particles::iterCounters, kColorUncolourable, peclet::dem::mldetail::kGateSlip, peclet::dem::Particles::kPos, kSplitOmegaVelocity, peclet::dem::Particles::kVel, peclet::dem::Particles::lambdaAcc, peclet::dem::Particles::lambdaT, peclet::dem::Particles::levelKey, peclet::dem::Particles::levelPerm, peclet::dem::SplitStats::lightHubs, makePGSManifoldSweep(), peclet::dem::Particles::manifoldColor, peclet::dem::Particles::manifoldPersistent, peclet::dem::Particles::manifolds, peclet::dem::Particles::manifoldSleep, markCopySeedsKokkos(), markPersistentManifoldsKokkos(), peclet::dem::Particles::maxApproach, peclet::dem::Particles::maxApproachQS, peclet::dem::FusedSweepCtx::maxBucket, peclet::dem::Particles::maxConsensus, peclet::dem::Particles::maxOverlap, peclet::dem::MlFusedCtx::maxWork, peclet::dem::Particles::mlAccD, peclet::dem::Particles::mlAngG, peclet::dem::Particles::mlAngG0, peclet::dem::Particles::mlBucketPerm, peclet::dem::Particles::mlColorPacked, peclet::dem::Particles::mlComOffG, peclet::dem::Particles::mlGrp, peclet::dem::SplitStats::mlHubAggregated, peclet::dem::Particles::mlInvIG, peclet::dem::Particles::mlInvMassG, peclet::dem::Particles::mlLast, peclet::dem::Particles::mlMassG, peclet::dem::Particles::mlMate, peclet::dem::Particles::mlOffsDev, peclet::dem::Particles::mlOriginG, peclet::dem::Particles::mlParent, peclet::dem::Particles::mlVelG, peclet::dem::Particles::mlVelG0, multilevelCoarseCycleKokkos(), peclet::dem::PhaseCopies::nCopies, peclet::dem::PhaseCopies::nGroups, peclet::dem::PhaseCopies::nHubs, peclet::dem::Particles::noAdaptiveStop, peclet::dem::Particles::MlLast::numBodies, peclet::dem::RankK::numColors, peclet::dem::Particles::MlLast::numGroups, peclet::dem::ContactHierarchy::numGroups, peclet::dem::Particles::MlLast::numLevels, peclet::dem::ContactHierarchy::numLevels, peclet::dem::Particles::MlLast::numManifolds, peclet::dem::Particles::numParticles, peclet::dem::Particles::numPosUnits, peclet::dem::Particles::numReal, peclet::dem::Particles::pairKeys, peclet::dem::Particles::MlLast::parentOff, peclet::dem::ContactHierarchy::parentOff, PECLET_DEM_GRAPH_LOOP, peclet::dem::Particles::planeFriction, peclet::dem::Particles::pos, peclet::dem::Particles::posCommitPerm, peclet::dem::Particles::posCopies, peclet::dem::SplitStats::posHubCopies, peclet::dem::Particles::posImpulse, peclet::dem::SplitStats::posItersUsed, positionEdgeEndsKokkos(), peclet::dem::Particles::positionIterations, peclet::dem::Particles::positionOmega, 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::posResidual, 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, reseedCopiesKokkos(), 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(), seedCopySlotStateKokkos(), peclet::dem::Particles::sideFlags, peclet::dem::Particles::sleepingEnabled, peclet::dem::PhaseCopies::slotA, peclet::dem::PhaseCopies::slotB, peclet::dem::PhaseCopies::slotBase, solveContactFrictionKokkos(), peclet::dem::Particles::solveEpoch, solvePositionColoredGSKokkos(), solvePositionKokkos(), solveVelocityColoredGSKokkos(), solveVelocityKokkos(), solveVelocityPGSBucketsKokkos(), solveVelocityPGSKokkos(), peclet::dem::SplitStats::splitBodiesPos, peclet::dem::SplitStats::splitBodiesVel, peclet::dem::Particles::splitSlot, peclet::dem::Particles::splitStats, peclet::dem::Particles::stabilizationMode, peclet::dem::RankK::syncInterval, peclet::dem::SplitStats::unfiredSplitContacts, unfoldOrphanKokkos(), peclet::dem::Particles::unitColor, peclet::dem::Particles::unitContacts, peclet::dem::Particles::unitStart, updateGroundedLevelsKokkos(), updateRestitutionBankKokkos(), peclet::dem::Particles::vel, peclet::dem::Particles::velCopies, peclet::dem::Particles::velCopiesLastSubstep, peclet::dem::SplitStats::velHubCopies, peclet::dem::SplitStats::velItersUsed, peclet::dem::Particles::velLastFullColors, peclet::dem::Particles::velMask, velocityEdgeEndsKokkos(), peclet::dem::Particles::velocityIterations, peclet::dem::Particles::velocityUseGS, peclet::dem::Particles::velOffsDev, peclet::dem::Particles::velPerm, peclet::dem::Particles::velPred, peclet::dem::Particles::vertexDegree, vertexDegreeKokkos(), peclet::dem::Particles::vn0, peclet::dem::Particles::vt0, peclet::dem::Particles::wallFrictionMax, warmStartApplyKokkos(), peclet::dem::F3::x, peclet::dem::Particles::xGate, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by demStep().
|
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 53 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, lowerBoundKey(), pairKeyFromGids(), peclet::dem::Particles::pairs, peclet::dem::Particles::pos, and peclet::dem::Particles::posPred.
Referenced by peclet::dem::HertzMindlinLaw::rebuild().
|
inline |
Save the current list (sorted by key) so the NEXT rebuild can carry the history.
Definition at line 111 of file solve_driver_force.hpp.
References peclet::dem::Particles::hertzKeys, peclet::dem::Particles::hertzNumPairs, peclet::dem::Particles::hertzPrevCount, peclet::dem::Particles::hertzPrevKeys, peclet::dem::Particles::hertzPrevXi, and peclet::dem::Particles::hertzXi.
Referenced by peclet::dem::HertzMindlinLaw::commitHistory().
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 196 of file solve_driver_force.hpp.
|
inline |
nsteps explicit force-based DEM steps of size dt with force law Law (see file comment).
The force/torque accumulators reuse the impulse engine's deltaVel/deltaAngVel scratch.
Definition at line 224 of file solve_driver_force.hpp.
References peclet::dem::Particles::angVel, peclet::dem::Particles::baseRadius, peclet::dem::Particles::deltaAngVel, peclet::dem::Particles::deltaVel, fillWorldRadiiKokkos(), peclet::dem::Particles::globalScale, peclet::dem::Particles::gravity, hertzIntegrateKokkos(), hertzMaxDisp2Kokkos(), peclet::dem::Particles::hertzNumPairs, peclet::dem::Particles::hertzNumWallCand, peclet::dem::Particles::hertzRefPos, peclet::dem::Particles::invInertia, peclet::dem::Particles::invMass, peclet::dem::Particles::numReal, peclet::dem::Particles::pos, peclet::dem::Particles::posPred, peclet::dem::Particles::quat, peclet::dem::Particles::rad, peclet::dem::Particles::scale, peclet::dem::Particles::shapes, peclet::dem::Particles::vel, and peclet::dem::Particles::velPred.
Referenced by demStepHertz().
|
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 327 of file solve_driver_force.hpp.
References demStepForce().
Referenced by peclet::dem::Simulation::stepHertz().
The single application point of a body-body contact: both lever arms moved to the contact midpoint, rA - dist n / 2 and rB + dist n / 2, so x_A + rA = x_B + rB (the shift of transformContact, contact_preprocessing.hpp).
The narrow phase's two surface arms differ by dist n, which made every legacy friction impulse also apply the couple dist n x J_t (docs/contact_solve_framework.md §1.7, D2). Wall contacts keep their own arm.
Definition at line 33 of file solver_friction.hpp.
References 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.
Referenced by accumulateNormalImpulseKokkos(), and solveContactFrictionKokkos().
|
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 45 of file solver_friction.hpp.
References add3(), peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, peclet::dem::ContactC::boundaryVel, peclet::dem::detail::computeW(), contactArmsMid(), cross3v(), dot3(), ldF3(), peclet::dem::ContactC::normal, peclet::dem::ContactC::rA, scale3(), sub3(), peclet::dem::F4::x, peclet::dem::F4::y, and peclet::dem::F4::z.
Referenced by demSolveContacts().
|
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 101 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().
|
inline |
Per-body active-contact count into planeFriction(:,1).
Definition at line 137 of file solver_friction.hpp.
References peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, and peclet::dem::ContactC::friction_lambda_n.
Referenced by demSolveContacts().
|
inline |
One count-averaged Coulomb friction sweep.
Zeros the delta arrays first, then accumulates the tangential impulse (clamped by mu*normal-load, divided by the larger contact count) into them.
The torque r x t is a WORLD-frame vector and invInertia is the body-frame principal inverse inertia, so both the effective mass and the angular velocity change go through the world inverse inertia R diag(invI) R^T of the phase's frozen orientation quat (R from the unit quaternion), exactly as every other velocity kernel does (detail::genInvMass, invRotateVector / rotateVector; docs/contact_solve_framework.md §12 S15). Applying the body-frame diagonal to the world torque directly broke angular momentum by up to 32 % of the applied torque on one ring-ring impulse. Isotropic inverse inertia (spheres) has no principal frame: its branch keeps the component-wise arithmetic verbatim, so sphere runs are byte-identical.
Definition at line 165 of file solver_friction.hpp.
References add3(), peclet::dem::ContactC::bodyA, peclet::dem::ContactC::bodyB, peclet::dem::ContactC::boundaryFriction, peclet::dem::ContactC::boundaryVel, contactArmsMid(), cross3v(), dot3(), peclet::dem::ContactC::friction_lambda_n, peclet::dem::detail::genInvMass(), invRotateVector(), ldF3(), peclet::dem::ContactC::normal, peclet::dem::ContactC::rA, peclet::dem::ContactC::rB, rotateVector(), scale3(), sub3(), 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().
|
inline |
Fused-sweep policy.
mode is Particles::fusedSweeps (set_fused_sweeps): -1 auto, 0 off (launch path everywhere), 1 on (fused everywhere it applies). Auto = fused only where CUDA-graph replay is unavailable — the distributed step (ghost syncs inside the loops forbid capture) and set_cuda_graphs(False) 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). Either way the arithmetic is identical.
Definition at line 63 of file solver_fused.hpp.
Referenced by demSolveContacts().
|
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 233 of file solver_fused.hpp.
References peclet::dem::FusedSweepCtx::bar, peclet::dem::FusedSweepCtx::maxBucket, and peclet::dem::FusedSweepCtx::offsDev.
Referenced by demSolveContacts().
| 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 hertzShapePairForcesKokkos().
| 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().
| 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().
| float peclet::dem::hertzSphereRadius | ( | int | i, |
| Kokkos::View< const float *, CpMem > | rad, | ||
| Kokkos::View< const float *, CpMem > | scale, | ||
| ScalarI | shapeId, | ||
| Kokkos::View< const ShapeDesc *, CpMem > | shapes, | ||
| float | globalScale | ||
| ) |
A body's Hertz sphere radius: a SPHERE shape's own radius, scale * globalScale * params.x (the radius the XPBD narrow phase probes with); otherwise the world reach radius rad(i).
rad(i) is scale * globalScale * the registry's LARGEST bounding radius (fillWorldRadiiKokkos), so in a mixture with tubes or boxes (circumscribed radius) it overstates a sphere; alone it is equal, computed in the same order, bit for bit.
Definition at line 91 of file solver_hertz.hpp.
References peclet::dem::ShapeDesc::params, SPHERE, peclet::dem::ShapeDesc::type, and peclet::dem::F4::x.
|
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 106 of file solver_hertz.hpp.
Referenced by peclet::dem::HertzMindlinLaw::pairForces().
|
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 165 of file solver_hertz.hpp.
Referenced by peclet::dem::HertzMindlinLaw::wallForces().
|
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 352 of file solver_hertz.hpp.
References sampleWallSdf().
Referenced by peclet::dem::HertzMindlinLaw::rebuild().
|
inline |
Symplectic-Euler kick-drift (MUSEN-style) + displacement tracking for the Verlet rebuild.
Spheres: isotropic inertia, angular update needs no orientation.
Definition at line 380 of file solver_hertz.hpp.
Referenced by demStepForce().
|
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 432 of file solver_hertz.hpp.
References dot3(), loadF3(), and sub3().
Referenced by demStepForce().
|
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 456 of file solver_hertz.hpp.
References add3(), cross3v(), dot3(), hertzBetaD(), hertzPairEMu(), invRotateVector(), len3(), loadF3(), loadF4(), peclet::dem::ShapeDesc::numPoints, peclet::dem::ShapeDesc::params, rotateVector(), scale3(), sdfEvalShape(), sdfGradShape(), peclet::dem::ShapeDesc::shellOffset, SPHERE, sub3(), peclet::dem::ShapeDesc::type, and peclet::dem::F4::x.
Referenced by peclet::dem::HertzMindlinLaw::pairForces().
|
inline |
The per-level geometry of the rigid coarse space (docs/contact_physics_followups.md §2.3), over the composed body -> group map S.grp of the level just built (groups [off, off + ng)):
Definition at line 223 of file solver_multilevel.hpp.
References peclet::dem::MlScratch::accD, peclet::dem::MlScratch::comOffG, peclet::dem::mldetail::effMass(), peclet::dem::MlScratch::grp, peclet::dem::MlScratch::invIG, peclet::dem::mldetail::memberOffset(), peclet::dem::MlScratch::originG, peclet::dem::mldetail::rotateD(), peclet::dem::F3::x, peclet::dem::mldetail::D3::x, peclet::dem::F3::y, peclet::dem::mldetail::D3::y, peclet::dem::F3::z, and peclet::dem::mldetail::D3::z.
|
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 347 of file solver_multilevel.hpp.
Referenced by demSolveContacts().
|
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 623 of file solver_multilevel.hpp.
References buildColorBucketsKokkos(), peclet::dem::MlScratch::colorPacked, peclet::dem::ContactHierarchy::numColors, and peclet::dem::ContactHierarchy::numLevels.
Referenced by demSolveContacts().
|
inline |
The coarse sweep over the multilevel scratch + the body views (the rigid views stay empty when the lazy pools are).
Definition at line 825 of file solver_multilevel.hpp.
References peclet::dem::MlScratch::angG, peclet::dem::MlScratch::angG0, peclet::dem::MlScratch::comOffG, peclet::dem::MlScratch::grp, peclet::dem::MlScratch::invIG, peclet::dem::MlScratch::invMassG, peclet::dem::MlScratch::originG, and peclet::dem::MlScratch::velG.
|
inline |
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.
Inactive (maxWork = 0) when fused sweeps are off / no CUDA / the pooled view is too small.
Definition at line 1017 of file solver_multilevel.hpp.
References peclet::dem::MlFusedCtx::bar, peclet::dem::MlFusedMeta::coarseSweeps, peclet::dem::ContactHierarchy::groupOff, peclet::dem::MlFusedMeta::groupOff, kMlMaxLevels, peclet::dem::MlFusedCtx::maxWork, peclet::dem::MlFusedCtx::meta, peclet::dem::ContactHierarchy::numColors, peclet::dem::MlFusedMeta::numColors, peclet::dem::ContactHierarchy::numGroups, peclet::dem::MlFusedMeta::numGroups, peclet::dem::ContactHierarchy::numLevels, peclet::dem::MlFusedMeta::numLevels, peclet::dem::MlFusedMeta::numReal, peclet::dem::MlFusedMeta::offsBase, peclet::dem::MlFusedCtx::offsDev, peclet::dem::ContactHierarchy::parentOff, peclet::dem::MlFusedMeta::parentOff, and peclet::dem::MlFusedMeta::permBase.
Referenced by demSolveContacts().
|
inline |
Definition at line 1067 of file solver_multilevel.hpp.
Referenced by demSolveContacts().
|
inline |
Mass-split Jacobi count pass (docs/contact_solve_framework.md §3.1, D3): per body slot, the number of contacts the Jacobi position solve visits (every contact; a wall side counts nothing).
Accumulates into counts, handed over zeroed (the apply clears it). Under MPI the caller then makes the counts global (syncContactCounts).
Definition at line 33 of file solver_position.hpp.
References peclet::dem::ContactC::bodyA, and peclet::dem::ContactC::bodyB.
Referenced by demSolveContacts().
|
inline |
Accumulate XPBD position corrections for numContacts contacts.
massSplit (the 'jacobi' diagnostic, §3.1): constraintCounts holds the global per-body counts n of countPositionJacobiKokkos and is only read; each contact's correction is solved against copies of mass m / n (w~ = n_A w_A + n_B w_B, a wall side 0) and the TRUE-mass deltas are accumulated, to be applied with factor 1. Off: the solve bumps the counts and the caller averages the sum by 1/count – the pre-framework count-averaged Jacobi, kept ONLY for the kernel unit test against its serial reference; no production path calls it (the colour-saturation fallbacks were deleted with complete colouring, docs/contact_solve_framework.md §4.2 / §12 S3).
Definition at line 55 of file solver_position.hpp.
Referenced by demSolveContacts().
| bool peclet::dem::unitAsleep | ( | const PosUnits & | units, |
| const Kokkos::View< const unsigned char *, CpMem > & | sleepMask, | ||
| int | u | ||
| ) |
A position unit is sleep-inactive iff all its contacts are sleep-masked (§4.3).
Definition at line 162 of file solver_position.hpp.
References peclet::dem::PosUnits::begin(), peclet::dem::PosUnits::contact(), and peclet::dem::PosUnits::end().
|
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.
With units (docs/contact_solve_framework.md §4.3) the edges are position UNITS, not contacts: numContacts is then the unit count and cColor is per unit; a unit's edge is its leader contact's (bodyA, bodyB) with key colorKey(leader). A one-point unit is exactly today's edge.
Definition at line 180 of file solver_position.hpp.
Referenced by demSolveContacts().
|
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 298 of file solver_position.hpp.
Referenced by demSolveContacts().
|
inline |
Copy each position unit's colour onto its contacts (contactColor(i) = unitColor(unit of i)).
Definition at line 458 of file solver_position.hpp.
References peclet::dem::PosUnits::begin(), peclet::dem::PosUnits::contact(), and peclet::dem::PosUnits::end().
Referenced by demSolveContacts().
|
inline |
Commit this substep's per-contact (key, colour) sorted by key, for next substep's warm gather.
Definition at line 474 of file solver_position.hpp.
Referenced by demSolveContacts().
|
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 636 of file solver_position.hpp.
Referenced by demSolveContacts().
|
inline |
Mass-split Jacobi count pass (docs/contact_solve_framework.md §3.1, D3): per body (REAL index), the number of manifolds the Jacobi velocity solve visits – num_points > 0, one manifold per periodic pair (the solve's realA > realB dedup); a wall side counts nothing.
Accumulates into counts, which the caller hands over zeroed (the apply clears it), exactly as the solve's own count did. Under MPI the caller then makes the counts global (syncContactCounts). dedupTwins (docs/contact_solve_framework.md §4.2 item 2, §6.2): the single-rank periodic twin rule (skip realIdx(A) > realIdx(B)); off under MPI, where ownership already excludes the non-owned twin and the velocity slot map would make the two rules disagree.
Definition at line 46 of file solver_velocity.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, and peclet::dem::ManifoldC::num_points.
Referenced by demSolveContacts().
|
inline |
Accumulate normal-restitution velocity deltas for numManifolds manifolds.
massSplit (the 'jacobi' diagnostic, §3.1): velCounts holds the global per-body counts n of countVelocityJacobiKokkos and is only read; each manifold is solved against copies of mass m / n (w~ = n_A w_A + n_B w_B, a wall side 0) and the TRUE-mass deltas are accumulated, to be applied with factor 1. Off: the solve bumps velCounts and the caller count-averages the sum – the pre-framework count-averaged Jacobi, kept ONLY for the kernel unit test against its serial reference; no production path calls it (the colour-saturation fallbacks were deleted with complete colouring, docs/contact_solve_framework.md §4.2 / §12 S3).
Definition at line 76 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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. averaged = false (the mass-split 'jacobi' diagnostic, §3.1): the deltas are already true-mass impulses against copies of mass m / count, so the apply is a plain add (factor 1).
Definition at line 279 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 323 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 458 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 615 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().
|
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:
Definition at line 685 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().
|
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 784 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 over owned + ghost slots. Under MPI the pair's bank lives only in its owning rank's ledger (docs/mpi_momentum_conservation.md §4.6): a credit to a ghost endpoint is delivered to that body's owner by the velocity reverse at the next sync, and an endpoint that has left this rank's halo is not found (it gets the conservative half, and that half is dropped).
Definition at line 814 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 882 of file solver_velocity.hpp.
Referenced by peclet::dem::Simulation::restBankStats(), and peclet::dem::Simulation::restOrphanStats().
|
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 910 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().
|
inline |
Apply the warm-start impulses up front (order-independent: fixed impulses, atomic adds).
Definition at line 952 of file solver_velocity.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, cross3v(), dot3(), invRotateVector(), peclet::dem::detail::ld3(), peclet::dem::ManifoldC::normal_sum, peclet::dem::ManifoldC::num_points, peclet::dem::ManifoldC::rA_sum, peclet::dem::ManifoldC::rB_sum, rotateVector(), scale3(), sub3(), peclet::dem::ManifoldC::torque_armA_sum, peclet::dem::ManifoldC::torque_armB_sum, 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().
|
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 1489 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 1534 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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) are keyed out entirely. (Complete colouring leaves no active manifold uncoloured: docs/contact_solve_framework.md §4.2.)
Definition at line 1610 of file solver_velocity.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, and peclet::dem::ManifoldC::num_points.
Referenced by demSolveContacts().
|
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 1662 of file solver_velocity.hpp.
References peclet::dem::PGSManifoldSweep::solveOne().
Referenced by demSolveContacts().
| int peclet::dem::xPopcount | ( | unsigned long long | m | ) |
Rank-level X (docs/contact_solve_framework.md §1.4): the holder of a body whose velocity activity mask has several bits (ranks) in sync interval t – the colour t mod C if it is in the mask, else the (t mod popcount)-th set bit (lowest = 0th).
Every rank evaluates the same mask and t, so all ranks agree on the holder without communication.
Definition at line 1681 of file solver_velocity.hpp.
Referenced by computeXGateKokkos(), peclet::dem::XGateSpec::fires(), and xHolder().
| int peclet::dem::xHolder | ( | unsigned long long | mask, |
| long long | t, | ||
| int | numColors | ||
| ) |
Definition at line 1689 of file solver_velocity.hpp.
References xPopcount().
Referenced by computeXGateKokkos(), and peclet::dem::XGateSpec::fires().
|
inline |
The per-manifold fire gate of sync interval t: 1 iff this rank (colour color) holds every endpoint whose mask names two or more ranks.
Masks live at the canonical velocity slot realIdx(body), so every image and hub copy of one body on this rank shares the decision.
Definition at line 1726 of file solver_velocity.hpp.
References peclet::dem::ManifoldC::bodyA, peclet::dem::ManifoldC::bodyB, xHolder(), and xPopcount().
Referenced by demSolveContacts().
|
inline |
Diagnostics (iterCounters): the number of gated-off manifolds of one sweep.
Definition at line 1747 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
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 1762 of file solver_velocity.hpp.
Referenced by demSolveContacts().
|
inline |
Grow every maxContacts-sized collision buffer to match the CURRENT particle capacity.
Sized from capacity, not numReal: periodic ghost slots take part in the narrow phase, so a buffer sized when capacity was smaller is an out-of-bounds write the moment the ghost band grows it. That is exactly what happened – demStep calls ensureCapacity every step (the ghost headroom is numReal + estGhosts + 4096), so a Simulation constructed with a small capacity had its contact buffers frozen at the construction size while the particle SoA grew by an order of magnitude around them. Found via peclet-examples/pall-ring-packing, where it showed up twice: boundary contacts silently dropped (scene-shape grains falling through an add_plane floor) and heap corruption inside step() at ~2000 steps.
nBodies is the count the setup-time bound is taken over (capacity, exactly as the original sizing did, so every existing run is byte-identical). floorWant is the per-step path: the narrow phase knows the contact count it actually needs and asks for it directly. A per-PARTICLE bound is not safe for a many-probe composed shape – a pair can contribute up to shellPoints contacts and a grain has several neighbours – and sizing from the ghost capacity is worse still, since calculateGhostCapacity's +4096 slots of slack alone ask for 13 million contacts (several GB across the ~40 buffers) with a 1625-probe particle. See narrowPhaseGrow.
Definition at line 42 of file step_solve.hpp.
References peclet::dem::Particles::commitPerm, peclet::dem::Particles::contactColor, peclet::dem::Particles::contactKeys, peclet::dem::Particles::contacts, peclet::dem::Particles::contactSleep, peclet::dem::Particles::contactSlot, peclet::dem::Particles::lambdaAcc, peclet::dem::Particles::lambdaT, peclet::dem::Particles::levelKey, peclet::dem::Particles::levelPerm, peclet::dem::Particles::manifoldColor, peclet::dem::Particles::manifoldPersistent, peclet::dem::Particles::manifolds, peclet::dem::Particles::manifoldSleep, peclet::dem::Particles::maxContacts, peclet::dem::Particles::mlColorPacked, peclet::dem::Particles::numWalls, peclet::dem::Particles::pairKeys, peclet::dem::Particles::posCommitPerm, peclet::dem::Particles::posImpulse, peclet::dem::Particles::posLambdaContact, peclet::dem::Particles::posPerm, 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::restBank, peclet::dem::Particles::restRel, peclet::dem::Particles::restVPeak, peclet::dem::Particles::shellDetection, peclet::dem::Particles::shellPoints, peclet::dem::Particles::sideFlags, peclet::dem::Particles::unitColor, peclet::dem::Particles::unitContacts, peclet::dem::Particles::unitStart, peclet::dem::Particles::velPerm, peclet::dem::Particles::vn0, and peclet::dem::Particles::vt0.
Referenced by peclet::dem::ShapeRegistry::ensureContactCapacity(), and narrowPhaseGrow().
|
inline |
Narrow phase with an automatically-grown contact buffer.
The three detect kernels guard their contact WRITES at the buffer extent, but P.contactCount is the RAW number of contacts found – and every consumer downstream (manifold reduction, the sleeping masks, the whole solve) uses that count as a loop bound over maxContacts-sized views. When the raw count exceeds the buffer, those loops walk off the end: "corrupted double-linked
list" on a host backend, cudaErrorIllegalAddress on a device one. Exactly the failure mode findCollisionsGrow already handles for the broad-phase pair buffer, and handled the same way – detect the overflow, grow with headroom, re-run once so no contact is silently dropped, then clamp defensively so the returned count is ALWAYS <= the extent.
This is what actually bounds the contact buffer. Sizing it from the particle count (capacity or numParticles) was only ever a proxy: a pair can contribute up to shellPoints contacts and a grain has several neighbours, so no per-particle bound is safe for a many-probe composed shape. Found via peclet-examples/pall-ring-packing (48 rings x 1625 probes).
Definition at line 118 of file step_solve.hpp.
References peclet::dem::Particles::contactCount, peclet::dem::Particles::contacts, detectBoundaryKokkos(), detectContactsKokkos(), detectWallSdfKokkos(), peclet::dem::Particles::globalScale, growContactBuffers(), peclet::dem::Particles::materialId, peclet::dem::Particles::maxContacts, peclet::dem::Particles::maxOverlap, 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::posPred, peclet::dem::Particles::quatPred, readInt(), peclet::dem::Particles::scale, peclet::dem::Particles::sdfGrid, peclet::dem::Particles::shapeId, peclet::dem::Particles::shapes, peclet::dem::Particles::shell, peclet::dem::Particles::shellDetection, peclet::dem::Particles::wallGrid, and peclet::dem::Particles::walls.
Referenced by computeOverlapsKokkos(), and demStep().
|
inline |
One full XPBD DEM substep over the particle SoA (mirrors simulation.cpp Simulation::step()).
Definition at line 144 of file step_solve.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(), peclet::dem::Particles::domain, peclet::dem::Particles::dt, peclet::dem::Particles::ensureCapacity(), peclet::dem::Particles::extForce, peclet::dem::Particles::extForceActive, peclet::dem::Particles::extTorque, peclet::dem::Particles::extTorqueActive, fillWorldRadiiKokkos(), finalCommitKokkos(), findCollisionsGrow(), findCollisionsVerlet(), freezeAsleepKokkos(), generateGhostsKokkos(), peclet::dem::Particles::gid, peclet::dem::Particles::globalScale, peclet::dem::Particles::gravity, peclet::dem::Particles::groundedLevel, growCopyView(), peclet::dem::Particles::growthFactor, peclet::dem::Particles::growthRate, peclet::dem::Particles::imageShift, 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(), narrowPhaseGrow(), peclet::dem::Particles::numParticles, peclet::dem::Particles::numReal, peclet::dem::Domain::periodic_x, peclet::dem::Domain::periodic_y, peclet::dem::Domain::periodic_z, 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::shapeId, 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::F3::x, peclet::dem::F3::y, and peclet::dem::F3::z.
Referenced by peclet::dem::Simulation::relax(), and peclet::dem::Simulation::step().
|
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 290 of file step_solve.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::domain, peclet::dem::Particles::ensureCapacity(), fillWorldRadiiKokkos(), findCollisionsGrow(), generateGhostsKokkos(), peclet::dem::Particles::gid, peclet::dem::Particles::globalScale, peclet::dem::Particles::invMass, peclet::dem::Particles::materialId, peclet::dem::Particles::maxOverlap, maxOwnedRadius(), narrowPhaseGrow(), peclet::dem::Particles::numParticles, peclet::dem::Particles::numReal, 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::shapeId, peclet::dem::Particles::topGhost, peclet::dem::Particles::vel, and peclet::dem::Particles::velPred.
Referenced by peclet::dem::Simulation::computeOverlaps().
|
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 319 of file contact_preprocessing.hpp.
Referenced by computeHeightLevelsKokkos().
|
inlineconstexpr |
Distributed step: bit 63 of a manifold-reduction key marks a contact this rank sees but does not own (docs/mpi_momentum_conservation.md §2.2), so the sort puts the owned manifolds first.
Slots are < 2^31, so no single-rank key ever has it set.
Definition at line 429 of file contact_preprocessing.hpp.
|
inlineconstexpr |
Colouring palette (docs/contact_solve_framework.md §4.2 item 1): the greedy takes the lowest colour free at both endpoints among bits 0..63 of the uint64 mask and never forces one.
An edge with no free colour is marked kColorUncolourable; it is neither coloured nor remaining, so the arbitration terminates, and it counts as leftover (after hub copies: an invariant violation).
Definition at line 435 of file contact_preprocessing.hpp.
|
inlineconstexpr |
Definition at line 436 of file contact_preprocessing.hpp.
Referenced by peclet::dem::Simulation::debugColoringLeftovers(), and demSolveContacts().
|
constexpr |
Pair-material lookup: flat [K*K*2] table, entry ((a*K + b)*2) = restitution, +1 = friction.
Definition at line 99 of file narrowphase.hpp.
Referenced by hertzPairEMu(), and peclet::dem::Simulation::setPairMaterial().
|
inlineconstexpr |
Definition at line 23 of file shapes_portable.hpp.
Referenced by genCylinderShell().
|
inlineconstexpr |
Hub edge budget (§4.4): a colouring vertex with more active edges is split into ceil(d / kHubEdgeBudget) copies, so no copy carries more than 32 and the 64-colour greedy provably succeeds (§1.6).
Definition at line 32 of file solve_copies.hpp.
Referenced by buildHubCopiesKokkos().
|
inlineconstexpr |
Split relaxation (§4.5, §13.1): the PGS normal step on an edge touching a mass-split slot is scaled by kSplitOmegaVelocity before the clamp (1: no relaxation; the pre-designed lever of R-F2, legitimate there because the PGS normal multiplier is accumulated and its clamp can retract an overshoot).
The overlap projection is the accumulated, retractable form since WO-12 (projected SOR on each contact's net push at P.positionOmega = 1.5, solver_position.hpp); the non-accumulated POCS of §13.1 could not retract and was held at omega 1. At omega 1 each update of that old form was an exact projection in the split metric, the local fold and the rank reconciliation are exact projections onto the consensus subspaces, and cyclic projection onto these half-spaces and subspaces converges to a feasible point (Fejer-monotone; which point depends on the order, as for serial POCS).
Definition at line 43 of file solve_copies.hpp.
Referenced by demSolveContacts().
|
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 49 of file solver_multilevel.hpp.
Referenced by demMakeMlFusedCtx().
|
inlineconstexpr |
Definition at line 50 of file solver_multilevel.hpp.
Referenced by peclet::dem::Simulation::debugMultilevelColoringConflicts().
|
inlineconstexpr |
Transient mark of the coarse colouring (docs/contact_solve_framework.md §4.4, "the multilevel coarse colouring"): an edge that won its groups but found no free colour keeps slot 63 and is skipped at this level.
Bit 62 lies above the 10 x 6 packed slot bits and is SET in every word (the build initialises colorPacked to ~0), so the mark is the bit CLEARED, and it is set again when the level's colouring ends – the packed word is bit for bit what it was without the mark.
Definition at line 56 of file solver_multilevel.hpp.