23#ifndef DEM_SOLVE_DRIVER_HPP
24#define DEM_SOLVE_DRIVER_HPP
28#include <Kokkos_Core.hpp>
42inline int readInt(Kokkos::View<int, CpMem> v) {
44 Kokkos::deep_copy(h, v);
47inline float readFloat(Kokkos::View<float, CpMem> v) {
49 Kokkos::deep_copy(h, v);
57 "peclet::dem::gid_base", Kokkos::RangePolicy<CpExec>(0, n),
58 KOKKOS_LAMBDA(
int i) { gid(i) = base + i; });
72 Kokkos::parallel_reduce(
73 "peclet::dem::max_scale", Kokkos::RangePolicy<CpExec>(0, P.
numReal),
74 KOKKOS_LAMBDA(
int i,
float& m) { m = sc(i) > m ? sc(i) : m; }, Kokkos::Max<float>(mx));
92 if (np >
static_cast<int>(P.
pairs.extent(0))) {
93 const int grown = np + np / 2 + 64;
94 Kokkos::realloc(Kokkos::WithoutInitializing, P.
pairs, grown);
99 return std::min(np,
static_cast<int>(P.
pairs.extent(0)));
117 Kokkos::parallel_reduce(
118 "peclet::dem::verlet_disp", Kokkos::RangePolicy<CpExec>(0, P.
numReal),
119 KOKKOS_LAMBDA(
int i,
float& acc) {
120 const float dx = pp(i, 0) - rp(i, 0), dy = pp(i, 1) - rp(i, 1), dz = pp(i, 2) - rp(i, 2);
121 const float d = dx * dx + dy * dy + dz * dz;
125 Kokkos::Max<float>(md2));
129 const float grow = std::max(0.0f, maxRad - P.
impRefMaxRad);
130 if (std::sqrt(md2) + 2.0f * grow > 0.5f * skin)
135 const auto rng = Kokkos::pair<int, int>(0, P.
numReal);
136 Kokkos::deep_copy(Kokkos::subview(P.
impRefPos, rng, Kokkos::ALL),
137 Kokkos::subview(P.
posPred, rng, Kokkos::ALL));
145#ifdef KOKKOS_ENABLE_CUDA
153struct CudaIterGraph {
154 cudaGraphExec_t exec =
nullptr;
157 cudaStream_t str = space.cuda_stream();
158 if (cudaStreamBeginCapture(str, cudaStreamCaptureModeThreadLocal) != cudaSuccess) {
159 (void)cudaGetLastError();
163 cudaGraph_t g =
nullptr;
164 if (cudaStreamEndCapture(str, &g) != cudaSuccess || g ==
nullptr) {
165 (void)cudaGetLastError();
171 if (cacheSlot !=
nullptr) {
172 exec =
static_cast<cudaGraphExec_t
>(cacheSlot);
173 cudaGraphExecUpdateResultInfo ri;
174 if (cudaGraphExecUpdate(exec, g, &ri) != cudaSuccess) {
175 (void)cudaGetLastError();
176 cudaGraphExecDestroy(exec);
181 if (exec ==
nullptr) {
182 if (cudaGraphInstantiate(&exec, g,
nullptr,
nullptr, 0) != cudaSuccess) {
183 (void)cudaGetLastError();
189 return exec !=
nullptr;
191 void launch(
CpExec& space) { cudaGraphLaunch(exec, space.cuda_stream()); }
194#define PECLET_DEM_GRAPH_LOOP(useVar, graphVar, emitVar, slotVar) \
195 if constexpr (!Hooks::distributed) { \
196 static const bool gOff = std::getenv("PECLET_DEM_NO_GRAPH") != nullptr; \
198 useVar = graphVar.capture(space, emitVar, slotVar); \
208#define PECLET_DEM_GRAPH_LOOP(useVar, graphVar, emitVar, slotVar) (void)graphVar;
214 float allMax(
float v)
const {
return v; }
223template <
class Hooks>
225 Kokkos::View<const int*, CpMem> keyIdx,
const Hooks& hooks) {
234 static const bool incrColorOff = [] {
235 const char* e = std::getenv(
"PECLET_DEM_NO_INCR_COLOR");
236 return e && std::atoi(e) != 0;
244 const Kokkos::View<const unsigned char*, CpMem> mSleep =
245 sleepOn ? Kokkos::View<const unsigned char*, CpMem>(P.
manifoldSleep)
246 : Kokkos::View<const unsigned char*, CpMem>();
247 const Kokkos::View<const unsigned char*, CpMem> cSleep =
248 sleepOn ? Kokkos::View<const unsigned char*, CpMem>(P.
contactSleep)
249 : Kokkos::View<const unsigned char*, CpMem>();
250 const bool legacyFriction = friction && !(usePersistPre && P.
velocityUseGS);
266 const bool incrColor = usePersistPre && P.
velocityUseGS && !Hooks::distributed && !incrColorOff;
271 Kokkos::View<const unsigned long long*, CpMem>(P.
prevPairKeys),
277 Kokkos::View<const unsigned long long*, CpMem>(P.
prevPairKeys),
290 std::vector<int> velOffs;
291 const bool velBuckets = P.
velocityUseGS && nm > 0 && numColors > 0;
295 const Kokkos::View<const int*, CpMem> velPermC(P.
velPerm);
296 const std::vector<int>* velOffsP = velBuckets ? &velOffs :
nullptr;
301 static const bool graphEnvOff = std::getenv(
"PECLET_DEM_NO_GRAPH") !=
nullptr;
302 const bool wantFused =
demFusedWanted(!Hooks::distributed && !graphEnvOff);
326 const Kokkos::View<float*, CpMem> bankV = poisson ? P.
restBank : Kokkos::View<float*, CpMem>();
327 const Kokkos::View<float*, CpMem> relV = poisson ? P.
restRel : Kokkos::View<float*, CpMem>();
328 const Kokkos::View<const unsigned char*, CpMem> persC =
330 : Kokkos::View<const unsigned char*, CpMem>();
331 const Kokkos::View<const float*, CpMem> vpkC =
332 poisson ? Kokkos::View<const float*, CpMem>(P.
restVPeak)
333 : Kokkos::View<const float*, CpMem>();
334 const Kokkos::View<const unsigned char*, CpMem> grdC =
335 poisson ? Kokkos::View<const unsigned char*, CpMem>(P.
groundedLevel)
336 : Kokkos::View<const unsigned char*, CpMem>();
337 const Kokkos::View<float*, CpMem> orphV = poisson ? P.
bodyOrphan : Kokkos::View<float*, CpMem>();
338 const Kokkos::View<const float*, CpMem> orphPk =
340 : Kokkos::View<const float*, CpMem>();
343 static const bool restNewtonOff = [] {
344 const char* e2 = std::getenv(
"PECLET_DEM_REST_NEWTON_OFF");
345 return e2 && std::atoi(e2) != 0;
347 static const bool restOneSided = [] {
348 const char* e2 = std::getenv(
"PECLET_DEM_REST_ONESIDED");
349 return e2 && std::atoi(e2) != 0;
354 Kokkos::deep_copy(mt,
static_cast<unsigned char>(0));
360 poisson ? P.
prevMatched : Kokkos::View<unsigned char*, CpMem>());
363 auto rr = Kokkos::subview(P.
restRel, Kokkos::pair<int, int>(0, nm));
364 Kokkos::deep_copy(rr, 0.0f);
373 Kokkos::View<const int*, CpMem> gidSorted, slotSorted;
374 if constexpr (Hooks::distributed) {
375 Kokkos::View<int*, CpMem> gs(
376 Kokkos::view_alloc(space,
"peclet::dem::orphan_gids", Kokkos::WithoutInitializing),
378 Kokkos::View<int*, CpMem> ss(
379 Kokkos::view_alloc(space,
"peclet::dem::orphan_slots", Kokkos::WithoutInitializing),
382 Kokkos::parallel_for(
383 "peclet::dem::orphan_gid_map", Kokkos::RangePolicy<CpExec>(space, 0, nBodies),
384 KOKKOS_LAMBDA(
int i) {
388 Kokkos::Experimental::sort_by_key(space, gs, ss);
395 Kokkos::View<const unsigned char*, CpMem>(P.
prevMatched),
410 auto flags = Kokkos::subview(P.
sideFlags, Kokkos::pair<int, int>(0, nm));
411 Kokkos::deep_copy(flags,
static_cast<unsigned char>(0));
419 if constexpr (Hooks::distributed)
420 hooks.syncVelocities(P);
424 const float vRest = 2.0f * P.
dt * gMagP;
430 auto emitVelIter = [&] {
437 Kokkos::View<const float*, CpMem>(P.
posImpulse), {}, bankV, relV, persC, vpkC, gHat, grdC,
438 restNewtonOff, restOneSided, orphV, orphPk, velPermC, velOffsP, velFusedP);
443 bool velLoopDone =
false;
444 if constexpr (!Hooks::distributed) {
445 if (usePGS && P.
velocityUseGS && velLeftover == 0 && velFusedP) {
452 Kokkos::View<const float*, CpMem>(P.
posImpulse), {}, bankV, relV, persC, vpkC, gHat, grdC,
453 restNewtonOff, restOneSided, orphV, orphPk, velPermC, velOffsP, velFusedP, &spec);
456 bool graphVel =
false;
458 if (!velLoopDone && usePGS && P.
velocityUseGS && velLeftover == 0) {
481 if (velLeftover > 0) {
505 if constexpr (Hooks::distributed) {
506 if (hooks.syncPoint(it))
507 hooks.syncVelocities(P);
510 if constexpr (Hooks::distributed)
511 hooks.syncVelocities(P);
519 const float vRestS = 2.0f * P.
dt * gMagP;
527 8.0f * P.
dt * gMagP);
530 auto emitOsIter = [&] {
538 bankV, relV, persC, vpkC, gHat, grdC, restNewtonOff, restOneSided, orphV, orphPk,
539 velPermC, velOffsP, velFusedP);
541 bool osLoopDone =
false;
542 if constexpr (!Hooks::distributed) {
543 if (velLeftover == 0 && velFusedP) {
551 Kokkos::View<const float*, CpMem>(P.
posImpulse), {}, bankV, relV, persC, vpkC, gHat,
552 grdC, restNewtonOff, restOneSided, orphV, orphPk, velPermC, velOffsP, velFusedP,
556 bool graphOs =
false;
558 if (!osLoopDone && velLeftover == 0) {
568 if constexpr (Hooks::distributed) {
569 if (hooks.syncPoint(it))
570 hooks.syncVelocities(P);
573 }
else if (smode == 2) {
586 const float qsThr = 8.0f * P.
dt * gMagP;
590 static const int mlGates = [] {
591 const char* e = std::getenv(
"PECLET_DEM_ML_GATES");
598 Kokkos::View<const float*, CpMem>(P.
vn0), Kokkos::View<
const float* [3],
CpMem>(P.
vt0),
600 Kokkos::View<const float*, CpMem>(P.
invMass), qsThr, mlGates, nBodies, S, P.
bodyWinner,
602 sleepOn ? Kokkos::View<const unsigned char*, CpMem>(P.
asleep)
603 : Kokkos::View<const unsigned char*, CpMem>());
605 std::vector<std::vector<int>> mlOffs;
627 auto emitMlIter = [&] {
635 P.
maxApproachQS, bankV, relV, persC, vpkC, gHat, grdC, restNewtonOff, restOneSided,
636 orphV, orphPk, velPermC, velOffsP, velFusedP);
641 2, Kokkos::View<const float*, CpMem>(relV), &mlOffs,
642 Kokkos::View<const int*, CpMem>(P.
mlBucketPerm), mlFusedP);
646 bool mlLoopDone =
false;
647#ifdef KOKKOS_ENABLE_CUDA
648 if constexpr (!Hooks::distributed) {
649 if (velLeftover == 0 && velFusedP) {
657 Kokkos::View<const float*, CpMem>(P.
posImpulse), bankV, relV, persC, vpkC, gHat,
658 grdC, restNewtonOff, restOneSided, orphV, orphPk);
659 mlLoopDone = demLaunchFusedMlLoop(
663 Kokkos::View<const int*, CpMem>(P.
mlBucketPerm), *mlFusedP,
675 persC, vpkC, gHat, grdC, restNewtonOff, restOneSided, orphV, orphPk, velPermC,
676 velOffsP, velFusedP, &spec);
681 bool graphMl =
false;
683 if (!mlLoopDone && velLeftover == 0) {
693 if constexpr (Hooks::distributed) {
694 if (hooks.syncPoint(it))
695 hooks.syncVelocities(P);
698 }
else if (smode == 4) {
706 std::vector<std::pair<int, int>> buckets;
724 Kokkos::View<const unsigned char*, CpMem>(P.
sideFlags),
729 Kokkos::View<const float*, CpMem>(P.
posImpulse),
748 if constexpr (Hooks::distributed) {
749 if (hooks.syncPoint(it))
750 hooks.syncVelocities(P);
753 }
else if (smode == 3) {
757 for (
int it = 0; it < 256; ++it) {
765 bankV, relV, persC, vpkC, gHat, grdC, restNewtonOff, restOneSided, orphV, orphPk,
766 velPermC, velOffsP, velFusedP);
769 if constexpr (Hooks::distributed) {
770 if (hooks.syncPoint(it))
771 hooks.syncVelocities(P);
775 if constexpr (Hooks::distributed)
776 hooks.syncVelocities(P);
793 Hooks::distributed ? Kokkos::View<const int*, CpMem>()
798 if (legacyFriction) {
804 if constexpr (Hooks::distributed)
805 hooks.syncVelocities(P);
810 if constexpr (Hooks::distributed)
811 hooks.syncPositions(P);
816 int numPosColors = 0;
818 const bool incrPosColor =
819 usePersistPre && P.
velocityUseGS && !Hooks::distributed && !incrColorOff;
820 bool posDidFull =
false;
855 auto pc = Kokkos::subview(P.
posLambdaContact, Kokkos::pair<int, int>(0, nc));
856 Kokkos::deep_copy(pc, 0.0f);
861 std::vector<int> posOffs;
862 const bool posBuckets = P.
velocityUseGS && nc > 0 && numPosColors > 0;
866 const Kokkos::View<const int*, CpMem> posPermC(P.
posPerm);
867 const std::vector<int>* posOffsP = posBuckets ? &posOffs :
nullptr;
874 auto emitPosIter = [&] {
878 posPermC, posOffsP, posFusedP);
883 bool posLoopDone =
false;
884 if constexpr (!Hooks::distributed) {
892 bool graphPos =
false;
905 if (posLeftover > 0) {
922 if constexpr (Hooks::distributed) {
923 if (hooks.syncPoint(it))
924 hooks.syncPositions(P);
927 if constexpr (Hooks::distributed)
928 hooks.syncPositions(P);
933 if (usePGS && nm > 0)
dem — portable (ArborX) broad-phase, the Kokkos-native replacement for the CUDA-only cuBQL broad-phas...
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 ...
void multilevelCoarseCycleKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< float, CpMem > maxApproach, int numReal, const ContactHierarchy &H, MlScratch &S, int coarseSweeps, Kokkos::View< const float *, CpMem > restRel={}, const std::vector< std::vector< int > > *bkOffs=nullptr, Kokkos::View< const int *, CpMem > bkPerm={}, const MlFusedCtx *fused=nullptr)
void warmStartApplyKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const float *, CpMem > warmP, Kokkos::View< float *[3], CpMem > warmT)
Apply the warm-start impulses up front (order-independent: fixed impulses, atomic adds).
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.
void updateRestitutionBankKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const float *, CpMem > lambdaAcc, Kokkos::View< const float *, CpMem > restRel, Kokkos::View< float *, CpMem > restBank, Kokkos::View< float *, CpMem > restVPeak)
Event-level (Poisson) restitution bookkeeping, once per substep AFTER all velocity phases (restitutio...
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 applyVelocityDeltasAveragedKokkos(int n, V3 velPred, V3 angVelPred, V3 deltaVel, V3 deltaAngVel, Vi velCounts)
Apply the accumulated velocity deltas AVERAGED by the per-body manifold count — the velocity- solve t...
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.
int colorManifoldsIncrementalKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, int numReal, Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const int *, CpMem > prevColor, int prevCount, Kokkos::View< int *, CpMem > mColor, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, bool forceFull, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
Incremental (warm-started) manifold colouring for the single-GPU PGS path.
void 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 sco...
float maxOwnedRadius(const Particles &P)
Largest effective particle radius over the owned set (= max scale × globalScale, growth included).
void accumulateNormalImpulseKokkos(Kokkos::View< ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate)
Force-chain normal load, accumulated over the velocity iterations: contacts(idx).friction_lambda_n +=...
bool solvePositionColoredGSKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const int *, CpMem > cColor, int numColors, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *[3], CpMem > posPred, Kokkos::View< const float *[4], CpMem > quatPred, Kokkos::View< const float *[4], CpMem > quatStatic, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< float, CpMem > maxOverlap, Kokkos::View< float *, CpMem > posLambdaAcc={}, Kokkos::View< const int *, CpMem > colorPerm={}, const std::vector< int > *colorOffs=nullptr, const FusedSweepCtx *fused=nullptr, const FusedLoopSpec *loop=nullptr)
Colored Gauss–Seidel XPBD overlap solve: sweep the numColors colour classes in order,...
void scatterOrphanBanksKokkos(Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const float *, CpMem > prevRestBank, Kokkos::View< const float *, CpMem > prevRestVPeak, Kokkos::View< const unsigned char *, CpMem > matched, int prevCount, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< float *, CpMem > orphan, Kokkos::View< float *, CpMem > orphanVPeak, Kokkos::View< const int *, CpMem > gidSorted={}, Kokkos::View< const int *, CpMem > slotSorted={})
Orphan transfer: previous-ledger entries NOT matched by any current manifold (their pair died this su...
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 commen...
void computeVn0Kokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, Kokkos::View< float *, CpMem > vn0, Kokkos::View< float *[3], CpMem > vt0)
-— Warm-started projected Gauss-Seidel (PGS) velocity solve -— Nonsmooth contact dynamics (Moreau-Jea...
Kokkos::View< int *, CpMem > Vi
int colorContactsKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, int numBodies, Kokkos::View< int *, CpMem > cColor, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
Greedy graph-colour the contacts (raw bodyA/bodyB): no two contacts sharing a body get the same colou...
void solveContactFrictionKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, FrManifoldCounts planeFriction, float frictionDynamic, Kokkos::View< float *[3], CpMem > deltaVel, Kokkos::View< float *[3], CpMem > deltaAngVel)
One count-averaged Coulomb friction sweep.
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] .
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 solveVelocityKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > velPred, Kokkos::View< const float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float *[3], CpMem > deltaVel, Kokkos::View< float *[3], CpMem > deltaAngVel, Kokkos::View< int *, CpMem > velCounts, Kokkos::View< const int *, CpMem > onlyColor={}, int colorFilter=0, Kokkos::View< const unsigned char *, CpMem > persistent={}, Kokkos::View< const float *[3], CpMem > posPred={}, F3 gHat={}, Kokkos::View< const unsigned char *, CpMem > grounded={})
Accumulate normal-restitution velocity deltas for numManifolds manifolds.
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-...
void gatherWarmLambdaKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > keyIdx, Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const float *, CpMem > prevLambda, Kokkos::View< const float *[3], CpMem > prevLambdaT, Kokkos::View< const float *, CpMem > prevPosImpulse, Kokkos::View< const float *, CpMem > prevRestBank, Kokkos::View< const float *, CpMem > prevRestVPeak, int prevCount, Kokkos::View< unsigned long long *, CpMem > outKeys, Kokkos::View< float *, CpMem > outWarm, Kokkos::View< float *[3], CpMem > outWarmT, Kokkos::View< float *, CpMem > outPosImpulse, Kokkos::View< float *, CpMem > outRestBank, Kokkos::View< float *, CpMem > outRestVPeak, Kokkos::View< unsigned char *, CpMem > outMatched={})
Warm-start gather for the PGS velocity solve: per manifold, write its pair key and look up the previo...
void solvePositionKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > posPred, Kokkos::View< const float *[4], CpMem > quatPred, Kokkos::View< const float *[4], CpMem > quatStatic, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< float *[3], CpMem > deltaPos, Kokkos::View< float *[4], CpMem > deltaQuat, Kokkos::View< int *, CpMem > constraintCounts, Kokkos::View< float, CpMem > maxOverlap, Kokkos::View< const int *, CpMem > onlyColor={}, int colorFilter=0)
Accumulate XPBD position corrections for numContacts contacts.
ContactHierarchy buildContactHierarchyKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const int *, CpMem > mColor, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const float *[3], CpMem > vt0, Kokkos::View< const unsigned char *, CpMem > persistent, Kokkos::View< const float *[3], CpMem > posPred, F3 gHat, Kokkos::View< const float *, CpMem > invMass, float qsThr, int gateMask, int numReal, MlScratch &S, Kokkos::View< long long *, CpMem > winner, Kokkos::View< std::uint64_t *, CpMem > colorMask, bool excludeImmovable=false, Kokkos::View< const unsigned char *, CpMem > asleep={})
Build the aggregation hierarchy + per-level crossing-manifold colorings.
PGSManifoldSweep makePGSManifoldSweep(Kokkos::View< const ManifoldC *, CpMem > manifolds, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< float, CpMem > maxApproachQS, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const unsigned char *, CpMem > sideFlag, Kokkos::View< float *[3], CpMem > lambdaT, float frictionDynamic, Kokkos::View< const float *[3], CpMem > vt0, float restitutionTangent, Kokkos::View< const float *, CpMem > posImpulse, Kokkos::View< float *, CpMem > restBank, Kokkos::View< float *, CpMem > restRel, Kokkos::View< const unsigned char *, CpMem > restPersistent, Kokkos::View< const float *, CpMem > restVPeak, F3 restGHat, Kokkos::View< const unsigned char *, CpMem > restGrounded, bool restNewtonOff, bool restOneSided, Kokkos::View< float *, CpMem > restOrphan, Kokkos::View< const float *, CpMem > restOrphanVPeak)
Build the shared per-manifold sweep functor (the colored launch loop, the fused kernels and the fused...
void solveVelocityColoredGSKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > mColor, int numColors, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< const unsigned char *, CpMem > persistent={}, Kokkos::View< const float *[3], CpMem > posPred={}, F3 gHat={}, Kokkos::View< const unsigned char *, CpMem > grounded={})
Colored Gauss–Seidel normal-restitution solve: sweep the numColors colour classes in order,...
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 ...
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...
int readInt(Kokkos::View< int, CpMem > v)
float readFloat(Kokkos::View< float, CpMem > v)
bool solveVelocityPGSKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > mColor, int numColors, Kokkos::View< const float *, CpMem > invMass, Kokkos::View< const float *[3], CpMem > invInertia, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< float *[3], CpMem > velPred, Kokkos::View< float *[3], CpMem > angVelPred, Kokkos::View< const int *, CpMem > realIdx, float growthRate, float restitutionNormal, float restVelThreshold, Kokkos::View< float, CpMem > maxApproach, Kokkos::View< float *, CpMem > lambdaAcc, Kokkos::View< const float *, CpMem > vn0, Kokkos::View< const unsigned char *, CpMem > sideFlag, Kokkos::View< float *[3], CpMem > lambdaT, float frictionDynamic, Kokkos::View< const float *[3], CpMem > vt0={}, float restitutionTangent=0.0f, Kokkos::View< const float *, CpMem > posImpulse={}, Kokkos::View< float, CpMem > maxApproachQS={}, Kokkos::View< float *, CpMem > restBank={}, Kokkos::View< float *, CpMem > restRel={}, Kokkos::View< const unsigned char *, CpMem > restPersistent={}, Kokkos::View< const float *, CpMem > restVPeak={}, F3 restGHat={}, Kokkos::View< const unsigned char *, CpMem > restGrounded={}, bool restNewtonOff=false, bool restOneSided=false, Kokkos::View< float *, CpMem > restOrphan={}, Kokkos::View< const float *, CpMem > restOrphanVPeak={}, Kokkos::View< const int *, CpMem > colorPerm={}, const std::vector< int > *colorOffs=nullptr, const FusedSweepCtx *fused=nullptr, const FusedLoopSpec *loop=nullptr)
Returns true when the sweep (or, with loop, the whole iteration loop) was submitted; false ONLY in lo...
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.
CpExec::memory_space CpMem
bool demFusedWanted(bool graphReplayAvailable)
Fused-sweep policy (read once).
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") ...
int colorContactsIncrementalKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, int numBodies, Kokkos::View< const unsigned long long *, CpMem > prevKeys, Kokkos::View< const int *, CpMem > prevColor, int prevCount, Kokkos::View< int *, CpMem > cColor, Kokkos::View< unsigned long long *, CpMem > keysOut, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, bool forceFull, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
Incremental (warm-started) contact colouring for the single-GPU PGS position solve.
int colorManifoldsKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, int numReal, Kokkos::View< int *, CpMem > mColor, Kokkos::View< long long *, CpMem > bodyWinner, Kokkos::View< std::uint64_t *, CpMem > bodyMask, int &leftover, Kokkos::View< const unsigned char *, CpMem > sleepMask={})
Greedy graph-colour the manifolds: no two manifolds sharing a real body get the same colour.
int findCollisionsGrow(Particles &P, float margin)
Broad phase with an automatically-grown pair buffer.
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 subs...
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 cal...
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...
void applyUpdatesKokkos(int n, V3 posPred, V3 velPred, V3 deltaPos, V3 deltaVel, Vi constraintCounts)
Jacobi count-averaged apply of position/velocity deltas, then clear deltas + counts.
int findCollisionsVerlet(Particles &P, float margin, float maxRad)
Verlet-cached impulse broadphase (single-GPU, non-periodic).
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...
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.
void computeSideFlagsKokkos(Kokkos::View< const ManifoldC *, CpMem > manifolds, int numManifolds, Kokkos::View< const int *, CpMem > realIdx, Kokkos::View< const unsigned char *, CpMem > persistent, Kokkos::View< const unsigned char *, CpMem > grounded, Kokkos::View< const float *[3], CpMem > posPred, Kokkos::View< const float *[3], CpMem > velPred, F3 gHat, float riseThr, Kokkos::View< unsigned char *, CpMem > sideFlag, Kokkos::View< const float *, CpMem > vn0, float approachThr)
Decide each persistent contact's treatment ONCE per substep (before any impulse is applied): 0 = symm...
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 d...
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).
Kokkos::DefaultExecutionSpace CpExec
dem — portable (Kokkos) particle SoA container: the storage the dem flip pivots on.
#define PECLET_DEM_GRAPH_LOOP(useVar, graphVar, emitVar, slotVar)
dem — portable (Kokkos) Coulomb friction cluster (the single dissipative friction path).
dem — multilevel (GraphMG-style) momentum-conserving contact stabilization.
dem — portable (Kokkos) XPBD position solve (pure overlap removal).
dem — portable (Kokkos) manifold velocity solve (normal restitution impulse).
bool capture(CpExec &, F &&, void *&)
Device-side iteration loop: run up to maxIters sweeps of the colour classes inside ONE kernel,...
Device-side context for a fused colour sweep: the colour offsets (numColors+1, uploaded from buildCol...
Fused-coarse-cycle context: flat per-level colour offsets on device + barrier + meta.
Device scratch for the multilevel pass, sized once (see Particles::allocate).
One full colored PGS sweep.
Kokkos::View< int *, CpMem > commitPerm
Kokkos::View< unsigned *, CpMem > fusedBar
Kokkos::View< unsigned char *, CpMem > asleep
Kokkos::View< int *, CpMem > bucketCursor
Kokkos::View< unsigned char *, CpMem > sideFlags
Kokkos::View< unsigned long long *, CpMem > prevContactKeys
Kokkos::View< int *, CpMem > mlGrp
Kokkos::View< unsigned char *, CpMem > manifoldPersistent
Kokkos::View< float *[3], CpMem > impRefPos
Kokkos::View< int *, CpMem > posOffsDev
Kokkos::View< float *, CpMem > bodyOrphanVPeak
Kokkos::View< int *, CpMem > velPerm
Kokkos::View< unsigned char *, CpMem > contactSleep
Kokkos::View< float *, CpMem > prevLambda
Kokkos::View< ManifoldC *, CpMem > manifolds
Kokkos::View< float *, CpMem > vn0
Kokkos::View< float *, CpMem > mlMassG
Kokkos::View< int *, CpMem > levelKey
Kokkos::View< int *[2], CpMem > pairs
Kokkos::View< float *[3], CpMem > vt0
Kokkos::View< float *, CpMem > restRel
Kokkos::View< int *, CpMem > levelPerm
Kokkos::View< int *, CpMem > prevManifoldColor
Kokkos::View< unsigned long long *, CpMem > contactKeys
Kokkos::View< int *, CpMem > prevContactColor
Kokkos::View< unsigned char *, CpMem > prevMatched
Kokkos::View< float, CpMem > maxApproach
Kokkos::View< float *, CpMem > prevRestBank
Kokkos::View< float *, CpMem > restVPeak
Kokkos::View< float *, CpMem > restBank
Kokkos::View< std::uint64_t *, CpMem > bodyColorMask
Kokkos::View< int *, CpMem > posCommitPerm
Kokkos::View< int *, CpMem > velOffsDev
Kokkos::View< int *, CpMem > mlOffsDev
Kokkos::View< unsigned long long *, CpMem > pairKeys
Kokkos::View< float *, CpMem > bodyOrphan
Kokkos::View< unsigned long long *, CpMem > prevPairKeys
Kokkos::View< int *, CpMem > posPerm
Kokkos::View< float *, CpMem > prevPosImpulse
Kokkos::View< int *, CpMem > contactColor
Kokkos::View< float *[3], CpMem > mlVelG
Kokkos::View< float *[3], CpMem > mlVelG0
Kokkos::View< int *, CpMem > mlBucketPerm
Kokkos::View< int *, CpMem > mlParent
Kokkos::View< float *[3], CpMem > lambdaT
Kokkos::View< float *[3], CpMem > prevLambdaT
Kokkos::View< float, CpMem > maxOverlap
Kokkos::View< float *, CpMem > posLambdaContact
Kokkos::View< float *, CpMem > posImpulse
Kokkos::View< int *, CpMem > contactSlot
Kokkos::View< float *, CpMem > mlInvMassG
Kokkos::View< int *, CpMem > heightLevel
Kokkos::View< long long *, CpMem > bodyWinner
Kokkos::View< float *, CpMem > lambdaAcc
Kokkos::View< long long *, CpMem > mlColorPacked
Kokkos::View< float, CpMem > maxApproachQS
Kokkos::View< unsigned char *, CpMem > manifoldSleep
Kokkos::View< const float *, CpMem > crad() const
Kokkos::View< float *[2], CpMem > planeFriction
Kokkos::View< float *, CpMem > prevRestVPeak
Kokkos::View< int *, CpMem > mlMate
Kokkos::View< ContactC *, CpMem > contacts
Kokkos::View< int, CpMem > pairCount
Kokkos::View< unsigned char *, CpMem > groundedLevel
Kokkos::View< int *, CpMem > manifoldColor
Single-GPU hooks: no ghost refresh, residuals are already global. Everything inlines away.
static constexpr bool distributed
float allMax(float v) const
void syncVelocities(Particles &) const
bool syncPoint(int) const
void syncPositions(Particles &) const