16#include <Kokkos_Core.hpp>
30#include "peclet/core/common/view.hpp"
66 const float margin = 0.1f * maxRad;
79 const float sleepVRest = 2.0f * P.
dt * gMag;
87 "self", Kokkos::RangePolicy<CpExec>(space, 0, P.
numReal),
88 KOKKOS_LAMBDA(
int i) { ri(i) = i; });
94 const float ghostBand = maxRad;
108 Kokkos::parallel_for(
109 "rad", Kokkos::RangePolicy<CpExec>(space, 0, P.
numParticles),
110 KOKKOS_LAMBDA(
int i) { rad(i) = sc(i) * gs * bR; });
188 const float margin = 0.1f * maxRad;
194 Kokkos::parallel_for(
195 "self", Kokkos::RangePolicy<CpExec>(space, 0, P.
numReal),
196 KOKKOS_LAMBDA(
int i) { ri(i) = i; });
199 const float ghostBand = maxRad;
211 Kokkos::parallel_for(
212 "rad", Kokkos::RangePolicy<CpExec>(space, 0, P.
numParticles),
213 KOKKOS_LAMBDA(
int i) { rad(i) = sc(i) * gs * bR; });
243struct MpiSolveHooks {
244 static constexpr bool distributed =
true;
247 bool forwardRotation;
248 float allMax(
float v)
const {
250 MPI_Allreduce(&v, &g, 1, MPI_FLOAT, MPI_MAX, halo.comm());
253 bool syncPoint(
int it)
const {
return (it + 1) % syncEvery == 0; }
254 void syncVelocities(Particles& P)
const {
255 halo.forward(P.velPred);
257 halo.forward(P.angVelPred);
259 void syncPositions(Particles& P)
const {
260 halo.forwardPositions(P.posPred);
262 halo.forward4(P.quatPred);
282inline void demStepMpi(Particles& P, ParticleHalo& halo,
double rcut,
int syncEvery,
283 bool forwardRotation) {
287 if (P.growthFactor != -1.0f && P.growthRate != 0.0f) {
288 P.growthFactor *= std::exp(P.growthRate * P.dt);
289 if (P.growthFactor > 1.0f)
290 P.growthFactor = 1.0f;
292 if (P.growthFactor > 0.0f)
296 P.numParticles = P.numReal;
298 P.posPred, P.quatPred, P.velPred, P.angVelPred, P.deltaPos, P.deltaQuat,
299 P.deltaVel, P.deltaAngVel, P.constraintCounts, P.gravity, P.dt, P.extForce);
304 halo.gather(P, rcut);
309 float gs = P.globalScale, bR = P.baseRadius;
310 Kokkos::parallel_for(
311 "rad", Kokkos::RangePolicy<CpExec>(space, 0, P.numParticles),
312 KOKKOS_LAMBDA(
int i) { rad(i) = sc(i) * gs * bR; });
321 Kokkos::deep_copy(space, P.contactCount, 0);
322 Kokkos::deep_copy(space, P.maxOverlap, 0.0f);
324 P.globalScale, margin, P.contacts, P.contactCount, P.maxOverlap, P.sdfGrid,
325 P.materialId, P.pairMaterials);
326 detectBoundaryKokkos(P.numReal, P.numPlanes, P.posPred, P.quatPred, P.scale, P.shapeId, P.shapes,
327 P.shell, P.planes, P.globalScale, margin, P.contacts, P.contactCount,
330 detectWallSdfKokkos(P.numReal, P.numWalls, P.posPred, P.quatPred, P.scale, P.shapeId, P.shapes,
331 P.shell, P.walls, P.wallGrid, P.globalScale, margin, P.contacts,
332 P.contactCount, P.maxOverlap, P.materialId, P.pairMaterials);
333 const int nc =
readInt(P.contactCount);
336 const int nm =
readInt(P.manifoldCount);
342 MpiSolveHooks{halo, syncEvery < 1 ? 1 : syncEvery, forwardRotation});
345 finalCommitKokkos(P.numReal, P.pos, P.invMass, P.posPred, P.quat, P.quatPred, P.domain);
347 if (P.thermostatTau > 0.0f && P.dt > 0.0f)
349 P.thermostatKB, P.thermostatTau, P.thermostatTemp, P.dt);
351 P.numParticles = P.numReal;
360struct MpiForceHooks {
361 static constexpr bool distributed =
true;
364 float allMax(
float v)
const {
366 MPI_Allreduce(&v, &g, 1, MPI_FLOAT, MPI_MAX, halo.comm());
369 float allMin(
float v)
const {
371 MPI_Allreduce(&v, &g, 1, MPI_FLOAT, MPI_MIN, halo.comm());
374 void gatherGhosts(Particles& P)
const {
375 halo.invalidateTopology();
376 halo.gather(P, band);
379 void refreshGhostState(Particles& P,
bool needQuat)
const {
380 halo.forwardPositions(P.pos);
382 halo.forward(P.angVel);
384 halo.forward4(P.quat);
386 void clearGhostScratch(Particles& P)
const {
394inline void demStepHertzMpi(Particles& P, ParticleHalo& halo,
float dt,
int nsteps,
399 MPI_Allreduce(&maxR, &maxRg, 1, MPI_FLOAT, MPI_MAX, halo.comm());
400 const double band = (2.0 + skinFrac) *
static_cast<double>(maxRg);
401 demStepForce(P, dt, nsteps, skinFrac, HertzMindlinLaw{}, MpiForceHooks{halo, band});
402 P.numParticles = P.numReal;
411 P_.
allocate(capacity, capacity * 64, capacity * 16, 1, 1, 8);
416 if (
const char* e = std::getenv(
"PECLET_DEM_REST_MODEL"); e && *e)
420 if (
const char* e = std::getenv(
"PECLET_DEM_SLEEP"); e && *e)
422 if (
const char* e = std::getenv(
"PECLET_DEM_SLEEP_SCALE"); e && *e)
424 if (
const char* e = std::getenv(
"PECLET_DEM_SLEEP_K"); e && *e)
426 if (
const char* e = std::getenv(
"PECLET_DEM_WAKE_SCALE"); e && *e)
428 if (
const char* e = std::getenv(
"PECLET_DEM_SLEEP_WAKELOST"); e && *e)
430 if (
const char* e = std::getenv(
"PECLET_DEM_SLEEP_INVMASS_FRAC"); e && *e)
434 if (
const char* e = std::getenv(
"PECLET_DEM_VERLET_SKIN"); e && *e)
439 r.erase(std::remove(r.begin(), r.end(),
this), r.end());
459 static std::vector<Simulation*> r;
470 baseRadius_ = radius;
473 F4 params{radius, 0, 0, 0};
474 std::vector<F3> shell;
477 params =
F4{radius, height, thickness, 0};
479 float min_dim = std::min(radius, thickness);
482 float spacing = std::min(radius * 0.3f, min_dim * 0.5f);
486 }
else if (shape_type ==
BOX) {
488 params =
F4{radius, radius, radius, 0};
489 float spacing = std::max(radius * 0.5f, 1e-3f);
490 shell =
genBoxShell(radius, radius, radius, spacing);
493 params =
F4{radius, 0, 0, 0};
497 const int nPts =
static_cast<int>(shell.size());
500 P_.
shell = Kokkos::View<float* [3], CpMem>(
"shell", nPts);
501 auto hs = Kokkos::create_mirror_view(P_.
shell);
502 for (
int i = 0; i < nPts; ++i) {
503 hs(i, 0) = shell[i].x;
504 hs(i, 1) = shell[i].y;
505 hs(i, 2) = shell[i].z;
507 Kokkos::deep_copy(P_.
shell, hs);
510 auto h = Kokkos::create_mirror_view(P_.
shapes);
511 h(0) =
ShapeDesc{shape_type, params, 0, nPts};
512 Kokkos::deep_copy(P_.
shapes, h);
515 float ix = 1.0f, iy = 1.0f, iz = 1.0f;
516 if (shape_type ==
SPHERE) {
517 if (baseRadius_ > 0.0f) {
518 float v = 2.5f / (baseRadius_ * baseRadius_);
522 float r_out = baseRadius_, r_in = baseRadius_ - thickness;
525 float term_r = r_out * r_out + r_in * r_in;
526 float I_zz = 0.5f * term_r;
527 float I_xx = (1.0f / 12.0f) * (3.0f * term_r + height * height);
534 }
else if (shape_type ==
BOX) {
535 float L = 2.0f * baseRadius_;
536 float I = (1.0f / 6.0f) *
L *
L;
538 ix = iy = iz = 1.0f / I;
541 defaultInvI_ =
F3{ix, iy, iz};
555 void setSdfShape(
const std::vector<float>& grid,
int nx,
int ny,
int nz,
F3 origin,
F3 spacing,
556 const std::vector<float>& shellFlat,
F3 invInertia,
float boundingRadius) {
557 if (nx < 2 || ny < 2 || nz < 2)
558 throw std::runtime_error(
"setSdfShape: grid dims must be >= 2 on each axis");
559 if (
static_cast<long>(nx) * ny * nz !=
static_cast<long>(grid.size()))
560 throw std::runtime_error(
"setSdfShape: grid.size() must equal nx*ny*nz");
561 const int nPts =
static_cast<int>(shellFlat.size() / 3);
563 throw std::runtime_error(
"setSdfShape: empty surface point shell");
566 P_.
sdfGrid = Kokkos::View<float*, CpMem>(
"sdfGrid", grid.size());
567 auto hg = Kokkos::create_mirror_view(P_.
sdfGrid);
568 for (
size_t i = 0; i < grid.size(); ++i)
570 Kokkos::deep_copy(P_.
sdfGrid, hg);
573 P_.
shell = Kokkos::View<float* [3], CpMem>(
"shell", nPts);
574 auto hs = Kokkos::create_mirror_view(P_.
shell);
575 for (
int i = 0; i < nPts; ++i) {
576 hs(i, 0) = shellFlat[3 * i];
577 hs(i, 1) = shellFlat[3 * i + 1];
578 hs(i, 2) = shellFlat[3 * i + 2];
580 Kokkos::deep_copy(P_.
shell, hs);
585 sd.params =
F4{boundingRadius, 0, 0, 0};
592 sd.gridOrigin = origin;
594 F3{spacing.
x > 0 ? 1.0f / spacing.
x : 0.0f, spacing.
y > 0 ? 1.0f / spacing.
y : 0.0f,
595 spacing.
z > 0 ? 1.0f / spacing.
z : 0.0f};
596 auto h = Kokkos::create_mirror_view(P_.
shapes);
598 Kokkos::deep_copy(P_.
shapes, h);
600 baseRadius_ = boundingRadius;
602 defaultInvI_ = invInertia;
604 ensureContactCapacity();
607 void setDomain(
float lx,
float ly,
float lz,
bool px,
bool py,
bool pz) {
608 P_.
domain =
Domain{
F3{0, 0, 0},
F3{lx, ly, lz},
F3{lx, ly, lz}, px, py, pz};
615 F3{mx.
x - mn.
x, mx.y - mn.
y, mx.z - mn.
z},
659 else if (mode ==
"onesided")
661 else if (mode ==
"multilevel")
663 else if (mode ==
"escalate")
665 else if (mode ==
"ordered")
668 throw std::invalid_argument(
669 "set_stabilization_mode: expected 'off', 'onesided', 'multilevel', 'escalate' or "
678 if (model ==
"newton")
680 else if (model ==
"poisson")
683 throw std::invalid_argument(
"set_restitution_model: expected 'newton' or 'poisson'");
698 void setSleeping(
bool enabled,
float threshold_scale = 2.0f,
int consecutive = 64,
699 float wake_scale = 40.0f) {
701 if (threshold_scale > 0.0f)
705 if (wake_scale > 0.0f)
721 Kokkos::parallel_reduce(
722 "peclet::dem::count_asleep", Kokkos::RangePolicy<CpExec>(0, P_.
numReal),
723 KOKKOS_LAMBDA(
int i,
int& acc) { acc += a(i) ? 1 : 0; }, n);
729 if (mat < 0 || mat >= 8)
730 throw std::invalid_argument(
"material id out of range");
731 auto he = Kokkos::create_mirror_view(P_.
hertzE);
732 auto hn = Kokkos::create_mirror_view(P_.
hertzNu);
733 Kokkos::deep_copy(he, P_.
hertzE);
734 Kokkos::deep_copy(hn, P_.
hertzNu);
737 Kokkos::deep_copy(P_.
hertzE, he);
738 Kokkos::deep_copy(P_.
hertzNu, hn);
742 void stepHertz(
float dt,
int substeps,
float skin_frac) {
763 auto h = Kokkos::create_mirror_view(P_.
materialId);
765 for (
int i = 0; i < P_.
numReal && i < (int)ids.size(); ++i)
766 h(i) =
static_cast<unsigned char>(ids[i]);
773 throw std::invalid_argument(
"material id out of range");
786 for (
auto xy : {std::pair<int, int>{a, b}, std::pair<int, int>{b, a}}) {
788 h((xy.first *
kMaxMaterials + xy.second) * 2 + 1) = friction;
795 throw std::invalid_argument(
"wall index out of range");
796 auto h = Kokkos::create_mirror_view(P_.
walls);
797 Kokkos::deep_copy(h, P_.
walls);
798 h(wid).materialId = mat;
799 Kokkos::deep_copy(P_.
walls, h);
801 void addPlane(
float px,
float py,
float pz,
float nx,
float ny,
float nz) {
802 auto h = Kokkos::create_mirror_view(P_.
planes);
803 Kokkos::deep_copy(h, P_.
planes);
806 Kokkos::deep_copy(P_.
planes, h);
818 int addSdfWall(
const std::vector<float>& grid,
int nx,
int ny,
int nz,
F3 origin,
F3 spacing,
819 float restitution,
float friction) {
820 if (nx < 2 || ny < 2 || nz < 2)
821 throw std::runtime_error(
"addSdfWall: grid dims must be >= 2 on each axis");
822 if (
static_cast<long>(nx) * ny * nz !=
static_cast<long>(grid.size()))
823 throw std::runtime_error(
"addSdfWall: grid.size() must equal nx*ny*nz");
829 w.gridOffset =
static_cast<int>(wallGridHost_.size());
832 F3{spacing.
x > 0 ? 1.0f / spacing.
x : 0.0f, spacing.
y > 0 ? 1.0f / spacing.
y : 0.0f,
833 spacing.
z > 0 ? 1.0f / spacing.
z : 0.0f};
834 w.restitution = restitution;
835 w.friction = friction;
836 const int idx =
static_cast<int>(wallsHost_.size());
837 wallsHost_.push_back(w);
838 wallGridHost_.insert(wallGridHost_.end(), grid.begin(), grid.end());
840 P_.
wallGrid = Kokkos::View<float*, CpMem>(
"wallGrid", wallGridHost_.size());
841 auto hg = Kokkos::create_mirror_view(P_.
wallGrid);
842 for (
size_t i = 0; i < wallGridHost_.size(); ++i)
843 hg(i) = wallGridHost_[i];
846 P_.
numWalls =
static_cast<int>(wallsHost_.size());
849 ensureContactCapacity();
858 if (wallIndex < 0 || wallIndex >=
static_cast<int>(wallsHost_.size()))
859 throw std::runtime_error(
"setWallVelocity: wall index out of range");
860 wallsHost_[wallIndex].linVel = linVel;
861 wallsHost_[wallIndex].angVel = angVel;
862 wallsHost_[wallIndex].center = center;
868 const int n =
static_cast<int>(xyz.size() / 3);
875 mpiGidsGlobal_ =
false;
877 auto pos = Kokkos::create_mirror_view(P_.
pos);
878 auto q = Kokkos::create_mirror_view(P_.
quat);
879 auto im = Kokkos::create_mirror_view(P_.
invMass);
880 auto sc = Kokkos::create_mirror_view(P_.
scale);
881 auto ii = Kokkos::create_mirror_view(P_.
invInertia);
882 auto sid = Kokkos::create_mirror_view(P_.
shapeId);
883 auto vel = Kokkos::create_mirror_view(P_.
vel);
884 auto av = Kokkos::create_mirror_view(P_.
angVel);
885 auto gi = Kokkos::create_mirror_view(P_.
gid);
886 for (
int i = 0; i < n; ++i) {
888 pos(i, 0) = xyz[3 * i];
889 pos(i, 1) = xyz[3 * i + 1];
890 pos(i, 2) = xyz[3 * i + 2];
898 ii(i, 0) = defaultInvI_.
x;
899 ii(i, 1) = defaultInvI_.
y;
900 ii(i, 2) = defaultInvI_.
z;
901 vel(i, 0) = vel(i, 1) = vel(i, 2) = 0;
902 av(i, 0) = av(i, 1) = av(i, 2) = 0;
904 Kokkos::deep_copy(P_.
pos, pos);
905 Kokkos::deep_copy(P_.
quat, q);
906 Kokkos::deep_copy(P_.
invMass, im);
907 Kokkos::deep_copy(P_.
scale, sc);
909 Kokkos::deep_copy(P_.
shapeId, sid);
910 Kokkos::deep_copy(P_.
vel, vel);
911 Kokkos::deep_copy(P_.
angVel, av);
912 Kokkos::deep_copy(P_.
gid, gi);
916 auto sc = Kokkos::create_mirror_view(P_.
scale);
917 for (
int i = 0; i < P_.
numReal; ++i)
919 Kokkos::deep_copy(P_.
scale, sc);
925 auto tsc = Kokkos::create_mirror_view(P_.
targetScale);
926 for (
int i = 0; i < P_.
numReal && i < (int)s.size(); ++i)
932 auto vel = Kokkos::create_mirror_view(P_.
vel);
933 for (
int i = 0; i < P_.
numReal && 3 * i + 2 < (int)v.size(); ++i) {
934 vel(i, 0) = v[3 * i];
935 vel(i, 1) = v[3 * i + 1];
936 vel(i, 2) = v[3 * i + 2];
938 Kokkos::deep_copy(P_.
vel, vel);
943 auto ef = Kokkos::create_mirror_view(P_.
extForce);
944 for (
int i = 0; i < P_.
numReal && 3 * i + 2 < (int)f.size(); ++i) {
946 ef(i, 1) = f[3 * i + 1];
947 ef(i, 2) = f[3 * i + 2];
957 auto h = Kokkos::create_mirror_view(P_.
quat);
958 for (
int i = 0; i < P_.
numReal && 4 * i + 3 < (int)q.size(); ++i) {
960 h(i, 1) = q[4 * i + 1];
961 h(i, 2) = q[4 * i + 2];
962 h(i, 3) = q[4 * i + 3];
964 Kokkos::deep_copy(P_.
quat, h);
967 auto h = Kokkos::create_mirror_view(P_.
angVel);
968 for (
int i = 0; i < P_.
numReal && 3 * i + 2 < (int)w.size(); ++i) {
970 h(i, 1) = w[3 * i + 1];
971 h(i, 2) = w[3 * i + 2];
973 Kokkos::deep_copy(P_.
angVel, h);
976 auto h = Kokkos::create_mirror_view(P_.
invInertia);
977 for (
int i = 0; i < P_.
numReal && 3 * i + 2 < (int)ii.size(); ++i) {
979 h(i, 1) = ii[3 * i + 1];
980 h(i, 2) = ii[3 * i + 2];
985 auto h = Kokkos::create_mirror_view(P_.
invMass);
986 for (
int i = 0; i < P_.
numReal && i < (int)im.size(); ++i)
988 Kokkos::deep_copy(P_.
invMass, h);
991 return peclet::core::toVector(
992 Kokkos::subview(P_.
angVel, Kokkos::make_pair(0, P_.
numReal), Kokkos::ALL));
995 return peclet::core::toVector(
1002 P_.
growthFactor = (new_factor > 0.0f) ? new_factor : 0.01f;
1003 else if (new_factor > 0.0f)
1014 auto im = Kokkos::create_mirror_view(P_.
invMass);
1015 Kokkos::deep_copy(im, P_.
invMass);
1016 std::vector<float> out(P_.
numReal);
1017 for (
int i = 0; i < P_.
numReal; ++i)
1018 out[i] = (im(i) > 0.0f) ? (1.0f / im(i)) : 0.0f;
1023 return peclet::core::toVector(
1024 Kokkos::subview(P_.
pos, Kokkos::make_pair(0, P_.
numReal), Kokkos::ALL));
1027 return peclet::core::toVector(
1028 Kokkos::subview(P_.
vel, Kokkos::make_pair(0, P_.
numReal), Kokkos::ALL));
1031 return peclet::core::toVector(
1032 Kokkos::subview(P_.
quat, Kokkos::make_pair(0, P_.
numReal), Kokkos::ALL));
1035 return peclet::core::toVector(Kokkos::subview(P_.
scale, Kokkos::make_pair(0, P_.
numReal)));
1052 auto sc = Kokkos::create_mirror_view(P_.
scale);
1053 Kokkos::deep_copy(sc, P_.
scale);
1054 std::vector<float> radii(P_.
numReal);
1055 for (
int i = 0; i < P_.
numReal; ++i)
1062 void exportSdf(
const std::string& filename,
int rx,
int ry,
int rz) {
1063 const std::vector<float> grid =
getSdfGrid(rx, ry, rz);
1069#ifdef PECLET_DEM_MPI
1072 void initMpi(std::tuple<double, double, double> origin, std::tuple<double, double, double> size,
1073 std::tuple<long, long, long> gsize, std::tuple<bool, bool, bool> periodic,
1075 halo_->initMpi({std::get<0>(origin), std::get<1>(origin), std::get<2>(origin)},
1076 {std::get<0>(size), std::get<1>(size), std::get<2>(size)},
1077 {std::get<0>(gsize), std::get<1>(gsize), std::get<2>(gsize)},
1078 {std::get<0>(periodic), std::get<1>(periodic), std::get<2>(periodic)}, comm);
1086 void enableMpiStep(
double rcut,
int sync_every = 1,
bool forward_rotation =
true,
1087 int rebalance_every = 0,
double verlet_skin = 0.0) {
1089 mpiSyncEvery_ = sync_every < 1 ? 1 : sync_every;
1090 mpiForwardRotation_ = forward_rotation;
1091 mpiRebalanceEvery_ = rebalance_every < 0 ? 0 : rebalance_every;
1094 halo_->setVerletSkin(
static_cast<float>(verlet_skin));
1097 long mpiRebuilds()
const {
return halo_->numRebuilds(); }
1098 long mpiGathers()
const {
return halo_->numGathers(); }
1101 int rebalance() {
return halo_->rebalance(P_); }
1105 int migrateToWeights(
const std::vector<peclet::core::Real>& w) {
1106 return halo_->migrateToWeights(P_, w);
1113 void ensureGlobalGids() {
1116 long base = 0, mine = P_.
numReal;
1117 MPI_Exscan(&mine, &base, 1, MPI_LONG, MPI_SUM, halo_->comm());
1118 if (halo_->rank() == 0)
1124 mpiGidsGlobal_ =
true;
1126 void stepMpi(
int nsteps) {
1127 const double rcut = (mpiRcut_ > 0.0) ? mpiRcut_ :
maxOwnedRadius(P_);
1129 for (
int s = 0; s < nsteps; ++s) {
1130 if (mpiRebalanceEvery_ > 0 && mpiStepCount_ % mpiRebalanceEvery_ == 0)
1131 halo_->rebalance(P_);
1132 demStepMpi(P_, *halo_, rcut, mpiSyncEvery_, mpiForwardRotation_);
1140 void stepHertzMpi(
float dt,
int substeps,
float skin_frac) {
1143 if (mpiRebalanceEvery_ > 0 && mpiHertzCalls_ % mpiRebalanceEvery_ == 0)
1144 halo_->rebalance(P_);
1146 demStepHertzMpi(P_, *halo_, dt, substeps, skin_frac);
1148 int rank()
const {
return halo_->rank(); }
1149 int numGhost()
const {
return halo_->numGhost(); }
1156 rx, ry, rz, P_.
domain.
min, P_.
domain.
max, P_.
numReal, P_.
pos, P_.
quat, P_.
scale, P_.
shapeId,
1179 Kokkos::View<std::uint64_t*, CpMem> seen(
"dbg_color_seen", nb);
1180 int velConf = 0, posConf = 0;
1182 Kokkos::deep_copy(space, seen, std::uint64_t(0));
1186 Kokkos::parallel_reduce(
1187 "peclet::dem::dbg_vel_color", Kokkos::RangePolicy<CpExec>(space, 0, nm),
1188 KOKKOS_LAMBDA(
int idx,
int& acc) {
1189 const int c = mColor(idx);
1192 const auto m = manifolds(idx);
1193 const std::uint64_t bit = std::uint64_t(1) << c;
1194 if ((Kokkos::atomic_fetch_or(&seen(realIdx(m.bodyA)), bit) >> c) & 1)
1196 if (m.bodyB >= 0 && ((Kokkos::atomic_fetch_or(&seen(realIdx(m.bodyB)), bit) >> c) & 1))
1202 Kokkos::deep_copy(space, seen, std::uint64_t(0));
1205 Kokkos::parallel_reduce(
1206 "peclet::dem::dbg_pos_color", Kokkos::RangePolicy<CpExec>(space, 0, nc),
1207 KOKKOS_LAMBDA(
int idx,
int& acc) {
1208 const int c = cColor(idx);
1211 const auto ct = contacts(idx);
1212 const std::uint64_t bit = std::uint64_t(1) << c;
1213 if ((Kokkos::atomic_fetch_or(&seen(ct.bodyA), bit) >> c) & 1)
1215 if (ct.bodyB >= 0 && ((Kokkos::atomic_fetch_or(&seen(ct.bodyB), bit) >> c) & 1))
1221 return {velConf, posConf};
1241 auto pos = Kokkos::create_mirror_view(P_.
pos);
1242 Kokkos::deep_copy(pos, P_.
pos);
1243 auto sc = Kokkos::create_mirror_view(P_.
scale);
1244 Kokkos::deep_copy(sc, P_.
scale);
1245 auto vel = Kokkos::create_mirror_view(P_.
vel);
1246 Kokkos::deep_copy(vel, P_.
vel);
1249 std::ofstream out(filename);
1251 throw std::runtime_error(
"Could not open file for writing: " + filename);
1252 out <<
"<?xml version=\"1.0\"?>\n";
1253 out <<
"<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
1254 out <<
" <PolyData>\n";
1255 out <<
" <Piece NumberOfPoints=\"" << n <<
"\" NumberOfVerts=\"0\" "
1256 <<
"NumberOfLines=\"0\" NumberOfStrips=\"0\" NumberOfPolys=\"0\">\n";
1257 out <<
" <Points>\n";
1258 out <<
" <DataArray type=\"Float32\" Name=\"Position\" NumberOfComponents=\"3\" "
1259 "format=\"ascii\">\n";
1260 for (
int i = 0; i < n; ++i)
1261 out << pos(i, 0) <<
" " << pos(i, 1) <<
" " << pos(i, 2) <<
" ";
1262 out <<
"\n </DataArray>\n";
1263 out <<
" </Points>\n";
1264 out <<
" <PointData Scalars=\"Radius\">\n";
1265 out <<
" <DataArray type=\"Float32\" Name=\"Radius\" NumberOfComponents=\"1\" "
1266 "format=\"ascii\">\n";
1267 for (
int i = 0; i < n; ++i)
1268 out << sc(i) * P_.
globalScale * baseRadius_ <<
" ";
1269 out <<
"\n </DataArray>\n";
1270 out <<
" <DataArray type=\"Float32\" Name=\"Velocity\" NumberOfComponents=\"3\" "
1271 "format=\"ascii\">\n";
1272 for (
int i = 0; i < n; ++i)
1273 out << vel(i, 0) <<
" " << vel(i, 1) <<
" " << vel(i, 2) <<
" ";
1274 out <<
"\n </DataArray>\n";
1275 out <<
" </PointData>\n";
1276 out <<
" </Piece>\n";
1277 out <<
" </PolyData>\n";
1278 out <<
"</VTKFile>\n";
1280 std::printf(
"Exported VTP: %s\n", filename.c_str());
1286 void uploadWalls() {
1287 const int n = std::max<int>(1,
static_cast<int>(wallsHost_.size()));
1288 if (
static_cast<int>(P_.
walls.extent(0)) < n)
1289 P_.
walls = Kokkos::View<WallSdf*, CpMem>(
"walls", n);
1290 auto h = Kokkos::create_mirror_view(P_.
walls);
1291 for (
size_t i = 0; i < wallsHost_.size(); ++i)
1292 h(i) = wallsHost_[i];
1293 Kokkos::deep_copy(P_.
walls, h);
1301 void ensureContactCapacity() {
1302 const int perParticle = std::max(16, shellPoints_);
1303 const long want =
static_cast<long>(P_.
capacity) * perParticle +
1312 P_.
contacts = Kokkos::View<ContactC*, CpMem>(
"contacts", want);
1313 P_.
manifolds = Kokkos::View<ManifoldC*, CpMem>(
"manifolds", want);
1314 P_.
manifoldColor = Kokkos::View<int*, CpMem>(
"manifoldColor", want);
1315 P_.
pairKeys = Kokkos::View<unsigned long long*, CpMem>(
"pairKeys", want);
1316 P_.
prevPairKeys = Kokkos::View<unsigned long long*, CpMem>(
"prevPairKeys", want);
1317 P_.
manifoldPersistent = Kokkos::View<unsigned char*, CpMem>(
"manifoldPersistent", want);
1318 P_.
contactColor = Kokkos::View<int*, CpMem>(
"contactColor", want);
1319 P_.
lambdaAcc = Kokkos::View<float*, CpMem>(
"lambdaAcc", want);
1320 P_.
lambdaT = Kokkos::View<float* [3], CpMem>(
"lambdaT", want);
1321 P_.
posLambdaContact = Kokkos::View<float*, CpMem>(
"posLambdaContact", want);
1322 P_.
posImpulse = Kokkos::View<float*, CpMem>(
"posImpulse", want);
1323 P_.
prevPosImpulse = Kokkos::View<float*, CpMem>(
"prevPosImpulse", want);
1324 P_.
restBank = Kokkos::View<float*, CpMem>(
"restBank", want);
1325 P_.
prevRestBank = Kokkos::View<float*, CpMem>(
"prevRestBank", want);
1326 P_.
restRel = Kokkos::View<float*, CpMem>(
"restRel", want);
1327 P_.
restVPeak = Kokkos::View<float*, CpMem>(
"restVPeak", want);
1328 P_.
prevRestVPeak = Kokkos::View<float*, CpMem>(
"prevRestVPeak", want);
1329 P_.
prevMatched = Kokkos::View<unsigned char*, CpMem>(
"prevMatched", want);
1330 P_.
velPerm = Kokkos::View<int*, CpMem>(
"velPerm", want);
1331 P_.
commitPerm = Kokkos::View<int*, CpMem>(
"commitPerm", want);
1332 P_.
sideFlags = Kokkos::View<unsigned char*, CpMem>(
"sideFlags", want);
1333 P_.
prevLambdaT = Kokkos::View<float* [3], CpMem>(
"prevLambdaT", want);
1334 P_.
contactSlot = Kokkos::View<int*, CpMem>(
"contactSlot", want);
1335 P_.
prevLambda = Kokkos::View<float*, CpMem>(
"prevLambda", want);
1336 P_.
vn0 = Kokkos::View<float*, CpMem>(
"vn0", want);
1337 P_.
vt0 = Kokkos::View<float* [3], CpMem>(
"vt0", want);
1338 P_.
levelKey = Kokkos::View<int*, CpMem>(
"levelKey", want);
1339 P_.
levelPerm = Kokkos::View<int*, CpMem>(
"levelPerm", want);
1340 P_.
mlColorPacked = Kokkos::View<long long*, CpMem>(
"mlColorPacked", want);
1346 P_.
contactKeys = Kokkos::View<unsigned long long*, CpMem>(
"contactKeys", want);
1347 P_.
prevContactKeys = Kokkos::View<unsigned long long*, CpMem>(
"prevContactKeys", want);
1349 P_.
posCommitPerm = Kokkos::View<int*, CpMem>(
"posCommitPerm", want);
1350 P_.
posPerm = Kokkos::View<int*, CpMem>(
"posPerm", want);
1351 P_.
manifoldSleep = Kokkos::View<unsigned char*, CpMem>(
"manifoldSleep", want);
1352 P_.
contactSleep = Kokkos::View<unsigned char*, CpMem>(
"contactSleep", want);
1359 float baseRadius_ = 1.0f;
1360 int shellPoints_ = 0;
1361 std::vector<WallSdf> wallsHost_;
1362 std::vector<float> wallGridHost_;
1363 F3 defaultInvI_{2.5f, 2.5f, 2.5f};
1364#ifdef PECLET_DEM_MPI
1365 std::unique_ptr<ParticleHalo> halo_ = std::make_unique<ParticleHalo>();
1366 double mpiRcut_ = 0.0;
1367 int mpiSyncEvery_ = 1;
1368 bool mpiForwardRotation_ =
true;
1369 int mpiRebalanceEvery_ = 0;
1370 long mpiStepCount_ = 0;
1371 long mpiHertzCalls_ =
1373 bool mpiGidsGlobal_ =
false;
dem — portable (ArborX) broad-phase, the Kokkos-native replacement for the CUDA-only cuBQL broad-phas...
Host-facing facade with std::vector setters/getters (binding-agnostic).
void setQuaternions(const std::vector< float > &q)
std::vector< float > getMasses() const
void setSleeping(bool enabled, float threshold_scale=2.0f, int consecutive=64, float wake_scale=40.0f)
Island sleeping / freezing (single-GPU statics, default ON; PECLET_DEM_SLEEP=0 disables).
void setThermostat(float temperature, float tau, float kB)
std::tuple< float, float, float > getDomainMax() const
std::vector< float > getInvInertia() const
std::pair< int, int > debugColoringConflicts()
int numAsleep()
Number of currently-sleeping real bodies (diagnostics / tests).
std::vector< float > getVelocities() const
void setPairMaterial(int a, int b, float restitution, float friction)
Set the symmetric pair material (restitution, friction) for material ids (a, b).
std::vector< float > getScales() const
void enablePeriodicity(bool x, bool y, bool z)
std::tuple< double, float, int > restOrphanStats()
Orphan-account diagnostics: (sum, max, count>0) of the per-body orphaned budget.
static std::vector< Simulation * > & registry()
void setVelocityUseGS(bool useGS)
void setSphereShape(float radius)
void setStabilization(bool enabled)
Enable/disable the stabilization pass (default on).
std::vector< float > getQuaternions() const
void setWallVelocity(int wallIndex, F3 linVel, F3 angVel, F3 center)
void exportSdf(const std::string &filename, int rx, int ry, int rz)
void writeVtp(const std::string &filename) const
void setVerletSkin(float skin_frac)
Verlet-cached impulse broadphase (single-GPU, non-periodic; default OFF).
void setGlobalScale(float s)
void addPlane(float px, float py, float pz, float nx, float ny, float nz)
void setVelocities(const std::vector< float > &v)
float growthFactor() const
std::tuple< float, float, float > getDomainMin() const
int addSdfWall(const std::vector< float > &grid, int nx, int ny, int nz, F3 origin, F3 spacing, float restitution, float friction)
void setPositions(const std::vector< float > &xyz)
void setInvInertia(const std::vector< float > &ii)
const Vf & invMassView() const
void setAngularVelocities(const std::vector< float > &w)
const V3 & externalForcesView() const
void setHertzMaterial(int mat, float youngs, float poisson)
Per-material Young's modulus + Poisson ratio for the Hertz-Mindlin engine (material ids as in setMate...
void clearExternalForces()
std::vector< float > getAngularVelocities() const
void setScalesUniform(float s)
std::vector< float > getSdfGrid(int rx, int ry, int rz)
void setDomain(float lx, float ly, float lz, bool px, bool py, bool pz)
void setSolverIterations(int pos, int vel)
void initializeShape(int shape_type, float radius, float height, float thickness)
const V3 & velocitiesView() const
void setExternalForces(const std::vector< float > &f)
std::vector< float > getPositions() const
std::tuple< double, float, int > restBankStats()
Poisson-restitution diagnostics: (sum, max, count>0) of the committed per-pair owed separation impuls...
void setMaterialParams(float restitution_normal, float restitution_tangent, float friction)
void exportLammps(const std::string &filename, int step) const
float getGrowthRate() const
void setDomainMinMax(F3 mn, F3 mx)
void setMaterialIds(const std::vector< int > &ids)
Per-particle material ids (0..kMaxMaterials-1); pair (e, mu) values come from setPairMaterial.
const V3 & positionsView() const
void setInvMass(const std::vector< float > &im)
void setSdfShape(const std::vector< float > &grid, int nx, int ny, int nz, F3 origin, F3 spacing, const std::vector< float > &shellFlat, F3 invInertia, float boundingRadius)
void setScales(const std::vector< float > &s)
void setGrowthParams(float rate, float new_factor)
void stepHertz(float dt, int substeps, float skin_frac)
Advance substeps explicit soft-sphere Hertz-Mindlin steps of size dt (device-side loop; the (e,...
void setGravity(float gx, float gy, float gz)
void setWallMaterialId(int wid, int mat)
Give an SDF wall a material id so particle-wall (e, mu) also resolves via the pair table.
void setStabilizationMode(const std::string &mode)
Select the stabilization pass of the staged velocity solve: "off" (pure symmetric PGS),...
void setRestitutionModel(const std::string &model)
Restitution model of the PGS velocity solve: "newton" (default; per-substep restitution on the pre-so...
dem — portable (Kokkos) time integration kernels (integration.cu).
dem — portable (CUDA-free) I/O helpers for the Kokkos dem module: a LAMMPS dump writer and a scalar-S...
dem — portable (Kokkos) owner<->ghost particle halo for the distributed XPBD step.
std::vector< F3 > genCylinderShell(float radius, float height, float thickness, float spacing)
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 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...
int reduceContactsToManifoldsKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int n, Kokkos::View< ManifoldC *, CpMem > outManifolds, Kokkos::View< int, CpMem > outCount, Kokkos::View< int *, CpMem > contactSlot={})
Reduce n contacts to manifolds (one per unique canonical pair).
float maxOwnedRadius(const Particles &P)
Largest effective particle radius over the owned set (= max scale × globalScale, growth included).
void detectContactsKokkos(Kokkos::View< const int *[2], CpMem > pairs, int numPairs, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, float globalScale, float margin, Kokkos::View< ContactC *, CpMem > outContacts, Kokkos::View< int, CpMem > outCount, Kokkos::View< float, CpMem > maxOverlap, GridView sdfGrid=GridView{}, MatIdView matId=MatIdView{}, PairTableView pairTable=PairTableView{})
Pair point-shell vs SDF contacts.
void 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).
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 on...
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...
Kokkos::View< float *, CpMem > Vf
Kokkos::View< float *[3], CpMem > V3
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; analy...
void predictVelocityKokkos(int n, V3 pos, Vf invMass, V3 vel, V4 quat, V3 angVel, V3 invInertia, V3 posPred, V4 quatPred, V3 velPred, V3 angVelPred, V3 deltaPos, V4 deltaQuat, V3 deltaVel, V3 deltaAngVel, Vi constraintCounts, F3 gravity, float dt, V3 extForce)
Predict velocity (gravity + gyroscopic precession), speculative position, and clear all deltas.
void 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 detectWallSdfKokkos(int numReal, int numWalls, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, Kokkos::View< const WallSdf *, CpMem > walls, GridView wallGrid, float globalScale, float margin, Kokkos::View< ContactC *, CpMem > outContacts, Kokkos::View< int, CpMem > outCount, Kokkos::View< float, CpMem > maxOverlap, MatIdView matId=MatIdView{}, PairTableView pairTable=PairTableView{})
Per-real-particle contacts against a static world-space wall SDF set (a drum barrel,...
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 staye...
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 —...
int readInt(Kokkos::View< int, CpMem > v)
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).
CpExec::memory_space CpMem
int findCollisionsGrow(Particles &P, float margin)
Broad phase with an automatically-grown pair buffer.
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 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 driv...
void fillWorldRadiiKokkos(Vf scale, Vf rad, float gs, float bR, int n)
World radii rad(i) = scale(i) * globalScale * baseRadius over [0, n) (n = owned + ghosts after a halo...
void updateGrowthScalesKokkos(int n, Vf scale, Vf targetScale, float factor)
Growth mode: scale = target * factor (when active).
float computeOverlapsKokkos(Particles &P)
Max pair interpenetration on the committed state (faithful to CUDA Simulation::compute_overlaps): cop...
void demStep(Particles &P)
One full XPBD DEM substep over the particle SoA (mirrors simulation.cpp Simulation::step()).
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...
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.
std::vector< float > generateSdfKokkos(int rx, int ry, int rz, F3 dmin, F3 dmax, int numReal, PosView pos, QuatView quat, ScalarF scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, bool px, bool py, bool pz, GridView sdfGrid=GridView{})
int findCollisionsVerlet(Particles &P, float margin, float maxRad)
Verlet-cached impulse broadphase (single-GPU, non-periodic).
std::vector< F3 > genBoxShell(float hx, float hy, float hz, float spacing)
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).
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...
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 th...
constexpr int kMaxMaterials
Pair-material lookup: flat [K*K*2] table, entry ((a*K + b)*2) = restitution, +1 = friction.
void applyThermostatKokkos(int numReal, V3 vel, Vf invMass, V3 angVel, V3 invInertia, V4 quat, double kB, double tau, double Ttarget, float dt)
Kokkos::DefaultExecutionSpace CpExec
void writeSdfVti(const std::string &filename, const std::vector< float > &grid, int rx, int ry, int rz, const float *minB, const float *maxB)
int calculateGhostCapacity(int nReal, Domain dom, float skin)
Padded particle-array capacity that leaves room for the periodic ghosts generateGhostsKokkos will emi...
dem — portable (Kokkos) narrow-phase: SDF point-shell collision + boundary planes.
dem — portable (Kokkos) SDF-grid reconstruction: the get_sdf_grid pipeline.
dem — portable (Kokkos) particle SoA container: the storage the dem flip pivots on.
dem — portable (Kokkos) periodic ghost generation (periodicity.cu / integration.cu).
dem — portable (host) surface-shell point generators for the analytic shapes.
dem — island sleeping / freezing for the single-GPU PGS statics path.
dem — the shared contact-solve driver: the full modern velocity + position solve sequence (warm-start...
dem — the force-based DEM step driver: explicit soft-contact time stepping (the engine family that co...
dem — portable (Kokkos) Coulomb friction cluster (the single dissipative friction path).
Soft-sphere Hertz–Mindlin DEM (reference force model) for SPHERES.
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).
Kokkos::View< WallSdf *, CpMem > walls
Kokkos::View< float *, CpMem > hertzE
Kokkos::View< int *, CpMem > commitPerm
Kokkos::View< unsigned char *, CpMem > asleep
Kokkos::View< unsigned char *, CpMem > materialId
Kokkos::View< unsigned char *, CpMem > sideFlags
Kokkos::View< unsigned long long *, CpMem > prevContactKeys
Kokkos::View< unsigned char *, CpMem > manifoldPersistent
Kokkos::View< int, CpMem > manifoldCount
Kokkos::View< int *, CpMem > velPerm
Kokkos::View< unsigned char *, CpMem > contactSleep
Kokkos::View< float *, CpMem > prevLambda
void ensureCapacity(int newCap)
Kokkos::View< ManifoldC *, CpMem > manifolds
Kokkos::View< float *, CpMem > vn0
Kokkos::View< int *, CpMem > levelKey
Kokkos::View< int *, CpMem > sleepCurCount
Kokkos::View< int *[2], CpMem > pairs
Kokkos::View< int, CpMem > contactCount
Kokkos::View< unsigned char *, CpMem > sleepMovingWall
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< float *, CpMem > pairMaterials
Kokkos::View< ShapeDesc *, CpMem > shapes
Kokkos::View< int *, CpMem > prevContactColor
Kokkos::View< unsigned char *, CpMem > prevMatched
Kokkos::View< float *, CpMem > prevRestBank
Kokkos::View< float *, CpMem > restVPeak
Kokkos::View< float *, CpMem > restBank
Kokkos::View< int *, CpMem > posCommitPerm
Kokkos::View< unsigned long long *, CpMem > pairKeys
Kokkos::View< float *, CpMem > hertzNu
Kokkos::View< int, CpMem > topGhost
Kokkos::View< float *, CpMem > bodyOrphan
Kokkos::View< unsigned long long *, CpMem > prevPairKeys
Kokkos::View< int *, CpMem > posPerm
Kokkos::View< float *, CpMem > invMassEff
Kokkos::View< float *, CpMem > prevPosImpulse
Kokkos::View< int *, CpMem > contactColor
Kokkos::View< int *, CpMem > sleepPrevCount
Kokkos::View< float *, CpMem > sdfGrid
Kokkos::View< float *[3], CpMem > lambdaT
bool sleepWakeLostContact
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< unsigned char *, CpMem > sleepCounter
Kokkos::View< float *, CpMem > lambdaAcc
Kokkos::View< long long *, CpMem > mlColorPacked
Kokkos::View< float *, CpMem > wallGrid
Kokkos::View< unsigned char *, CpMem > manifoldSleep
void allocate(int cap, int maxPairs_, int maxContacts_, int nShapes, int nShell, int nPlanes)
Kokkos::View< float *[3], CpMem > shell
Kokkos::View< float *, CpMem > prevRestVPeak
Kokkos::View< ContactC *, CpMem > contacts
Kokkos::View< unsigned char *, CpMem > groundedLevel
Kokkos::View< PlaneP *, CpMem > planes
Kokkos::View< int *, CpMem > manifoldColor
Portable mirror of ShapeDescriptor (analytic fields + a flat-array point shell).
Single-GPU hooks: no ghost refresh, residuals are already global. Everything inlines away.
Static, world-space SDF container/geometry the particles collide against (a drum barrel,...