peclet-dem 1.1.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
Loading...
Searching...
No Matches
particles.hpp
Go to the documentation of this file.
1
10#ifndef DEM_PARTICLES_HPP
11#define DEM_PARTICLES_HPP
12
13#include <cstdint>
14#include <Kokkos_Core.hpp>
15#include <vector>
16
17#include "contact_preprocessing.hpp" // ContactC, ManifoldC
18#include "integration.hpp" // Domain, V3/V4/Vf/Vi
19#include "narrowphase.hpp" // ShapeDesc, PlaneP
20
21namespace peclet::dem {
22
27 // per owned contact: global ids of bodyA / bodyB (-1 for a wall), the periodic image of each
28 // body's slot (integer box lengths per axis; 0 for an owned row and on a closed axis) and dist
29 std::vector<int> gidA, gidB, imageA, imageB; // image*: 3 per contact
30 std::vector<float> dist;
31 // per owned body: global id, predicted position (3), world radius
32 std::vector<int> gid;
33 std::vector<float> posPred, rad;
34};
35
45 int nHubs = 0, nCopies = 0, nGroups = 0, slotBase = 0;
46 int maxHubDegree = 0; // diagnostics: the largest hub degree
47 Kokkos::View<int*, CpMem> slotA, slotB; // per edge: override slot of the A / B end, -1
48 Kokkos::View<int*, CpMem> copyBase; // per copy slot (slot - slotBase): its hub's vertex
49 Kokkos::View<int*, CpMem> hubVertex, hubS; // per hub: base vertex, copy count s (incl. base)
50 Kokkos::View<int*, CpMem> groupStart, groupSlot, groupK;
51 Kokkos::View<float* [3], CpMem> groupShift; // per member
52 Kokkos::View<unsigned char*, CpMem> groupActive; // per member: >= 1 active edge (counts in k)
53 Kokkos::View<float* [3], CpMem> seedX, seedW; // per group: sigma (velPred / posPred; angVelPred)
54};
55
72
73struct Particles {
74 // --- per-particle state (size = capacity) ---
94 // Global particle id (stable across halo rebuilds and MPI ownership migration; identity == local
95 // index on the single-GPU path). The distributed step builds the persistent-contact pair keys
96 // from it — local slots are not stable identities there. Ghost slots carry the owner's gid.
98 Kokkos::View<float* [2], CpMem> planeFriction;
99 Vf rad; // effective broadphase radius scratch (scale * globalScale)
100 V3 extForce; // per-particle external FORCE (e.g. fluid drag); F=ma => dv = extForce*invMass*dt
101 // Per-particle external TORQUE in the WORLD frame (resolved CFD-DEM hydrodynamic torque, a
102 // magnetic couple, ...). Rotated into the body frame in the predictor, where the gyroscopic
103 // Euler term already lives: dw_body = invI * (tau_body - w x I w) * dt. World frame is the
104 // caller-facing convention because that is what every force/torque source produces; the body
105 // frame is an internal detail of the principal-axis inertia representation.
107
108 // --- collision/contact/manifold buffers ---
109 Kokkos::View<int* [2], CpMem> pairs; // broadphase candidates (maxPairs)
110 Kokkos::View<ContactC*, CpMem> contacts; // narrowphase output (maxContacts)
111 Kokkos::View<ManifoldC*, CpMem> manifolds; // reduction output (maxContacts)
112 // Graph-colouring scratch for the single-GPU colored Gauss–Seidel velocity solve: per-manifold
113 // colour (maxContacts; -2 inactive, -1 uncoloured, >=0 colour), plus per-body arbitration winner
114 // and committed-colour bitmask (both indexed by REAL body index, sized capacity).
115 Kokkos::View<int*, CpMem> manifoldColor; // per-manifold colour (velocity solve)
116 // Incremental (warm-started) colouring (single-GPU PGS path): the previous substep's per-manifold
117 // colour, sorted alongside prevPairKeys (committed by pair key exactly like prevLambda). A
118 // surviving pair keeps its colour so the Jones-Plassmann arbitration only re-runs over the NEW
119 // manifolds; velLastFullColors is the colour count at the last FULL recolour (creep-recompaction
120 // reference). See colorManifoldsIncrementalKokkos.
121 Kokkos::View<int*, CpMem> prevManifoldColor;
123 // Persistent-contact restitution (gravity-gated): pair keys of this/last substep's manifolds +
124 // the per-manifold "existed last substep" flag. A persistent contact is LOADED, not a fresh
125 // impact — it gets e = 0 (the impulse still cancels the approach: pure inelastic support), which
126 // is how the velocity solve carries a pile's static weight through impulse chains. Restitution
127 // stays reserved for newly formed contacts (genuine impacts). |g| = 0 leaves all of this idle.
128 Kokkos::View<unsigned long long*, CpMem> pairKeys;
129 Kokkos::View<unsigned long long*, CpMem> prevPairKeys;
130 Kokkos::View<unsigned char*, CpMem> manifoldPersistent;
132 // Grounded level per REAL body (Guendelman support levels, warm-started + decayed): 255 at a
133 // wall/plane contact, propagated lower -> upper through the contact graph a few sweeps per
134 // substep. One-sided (shock-propagation) impulses require the LOWER body grounded > 0, so a
135 // gas-borne emulsion or lifted slug (no path to the floor) keeps momentum-conserving impulses
136 // and its weight stays on the gas -- only genuinely supported chains drain into the ground.
137 Kokkos::View<unsigned char*, CpMem> groundedLevel;
138 // Warm-started PGS (projected Gauss-Seidel) velocity solve: per-manifold accumulated push
139 // impulse (this substep), the previous substep's converged impulses (sorted alongside
140 // prevPairKeys for the warm-start gather), and the pre-solve approach velocity (restitution
141 // bias). At convergence lambdaAcc IS the contact force network (x dt).
142 Kokkos::View<float*, CpMem> lambdaAcc;
143 Kokkos::View<float*, CpMem> prevLambda;
144 Kokkos::View<float*, CpMem> vn0;
145 Kokkos::View<float* [3], CpMem> vt0; // pre-solve tangential surface velocity (beta reference)
146 // Friction-cone PGS: per-manifold accumulated tangential impulse (world frame, kept in the
147 // contact tangent plane by projection) and the previous substep's converged values (sorted
148 // alongside prevPairKeys for the warm-start gather). |lambdaT| <= mu * lambdaAcc at all times.
149 Kokkos::View<float* [3], CpMem> lambdaT;
150 Kokkos::View<float* [3], CpMem> prevLambdaT;
151 // Position-channel normal load (see solvePositionColoredGSKokkos): per-contact positional
152 // lambda this substep, its per-manifold impulse-equivalent, the previous substep's value
153 // (warm-gathered) that tops up the friction cone's Coulomb bound, and the sorted store.
154 Kokkos::View<float*, CpMem> hertzSnPair; // per cached pair: last step's patch stiffness sum
155 Kokkos::View<float*, CpMem> hertzSnWall; // per (particle, wall): same, for wall patches
156 Kokkos::View<float*, CpMem> posLambdaContact;
157 Kokkos::View<float*, CpMem> posImpulse; // gathered: LAST substep's position-channel load
158 Kokkos::View<float*, CpMem> prevPosImpulse; // sorted alongside prevPairKeys
159 // Event-level (Poisson) restitution (restitutionModel == 1): per-pair OWED separation impulse
160 // (physical units) — e x the event's banked kinetic-compression impulse, minus what has already
161 // been returned. Carried by pair key like lambdaT (gathered into restBank, committed to
162 // prevRestBank); restRel is the per-substep release accumulator (clamped 0..owed inside the PGS
163 // sweep — the friction-cone-shaped budget cap). See updateRestitutionBankKokkos.
164 Kokkos::View<float*, CpMem> restBank;
165 Kokkos::View<float*, CpMem> prevRestBank; // sorted alongside prevPairKeys
166 Kokkos::View<float*, CpMem> restRel; // this substep's released impulse (lambda units)
167 // Event state: peak physical approach speed of the pair's current impact event (> 0 = event
168 // active). Set/refreshed by kinetic approaches, decays 1/256 per substep, cleared once it ages
169 // below the resting threshold — so a buried/absorbed event's bank evaporates instead of popping.
170 // While active the contact banks its applied normal-impulse flux EVERY substep (the co-moving
171 // compression plateau has vn0 ~ 0, which a per-substep kinetic gate would miss), and the release
172 // separation velocity is capped at e x vPeak (sustained unloading push, never an impulsive dump).
173 Kokkos::View<float*, CpMem> restVPeak;
174 Kokkos::View<float*, CpMem> prevRestVPeak; // sorted alongside prevPairKeys
175 // Orphan transfer (pair-churn fix): a pair that DIES with owed budget credits it to its
176 // endpoint bodies mass-weighted (per-body balance + the event peak speed it carried, both
177 // decayed 1/256 per substep so stranded credit evaporates). Live releasing pairs draw the
178 // balance back on demand inside the PGS sweep — a penetrating impactor's event budget then
179 // survives the ~20-substep turnover of its contact partners instead of dying with each pair.
180 // Indexed by REAL body slot (owned range authoritative; MPI ghosts mirrored owner->ghost).
181 Kokkos::View<float*, CpMem> bodyOrphan;
182 Kokkos::View<float*, CpMem> bodyOrphanVPeak;
183 Kokkos::View<unsigned char*, CpMem> prevMatched; // scratch: prev-ledger entry seen this substep
184 // Side flags for the STABILIZATION pass (0 = symmetric): zeroed for the main momentum-
185 // conserving sweeps, filled from persistence+grounding only if statics fail to converge.
186 Kokkos::View<unsigned char*, CpMem> sideFlags;
187 // Level-ordered ("ordered") stabilization: per-REAL-body height-from-floor BFS level
188 // (recomputed fresh each time the pass triggers) + the per-manifold (level, colour) bucket
189 // key and permutation the ordered sweeps iterate through.
190 Kokkos::View<int*, CpMem> heightLevel;
191 Kokkos::View<int*, CpMem> levelKey;
192 Kokkos::View<int*, CpMem> levelPerm;
193 // Multilevel (GraphMG) stabilization scratch (solver_multilevel.hpp): packed per-manifold
194 // 6-bit colour per level, pooled parent maps / group mass / group velocity arrays (levels
195 // shrink >= 10% each, so the pools hold every level), the composed body -> group map, and
196 // the matching scratch.
197 Kokkos::View<long long*, CpMem> mlColorPacked;
198 Kokkos::View<int*, CpMem> mlParent;
199 Kokkos::View<float*, CpMem> mlInvMassG;
200 Kokkos::View<float* [3], CpMem> mlVelG;
201 Kokkos::View<float* [3], CpMem> mlVelG0;
202 Kokkos::View<float*, CpMem> mlMassG;
203 Kokkos::View<int*, CpMem> mlGrp;
204 Kokkos::View<int*, CpMem> mlMate;
205 // Rigid 6-DOF aggregates (docs/contact_physics_followups.md §2.3; MlScratch documents each):
206 // allocated LAZILY on the first multilevel pass with the group pools' extent (mlAccD: one
207 // level's groups, <= the body count), so the default path allocates nothing.
208 Kokkos::View<float* [3], CpMem> mlOriginG;
209 Kokkos::View<float* [3], CpMem> mlComOffG;
210 Kokkos::View<float* [3], CpMem> mlAngG;
211 Kokkos::View<float* [3], CpMem> mlAngG0;
212 Kokkos::View<float* [6], CpMem> mlInvIG;
213 Kokkos::View<double* [7], CpMem> mlAccD;
214 // --- Hertz-Mindlin soft-sphere engine (solver_hertz.hpp): cached Verlet pair list state ---
215 Kokkos::View<float* [3], CpMem> hertzXi; // per cached pair: Mindlin shear history
216 Kokkos::View<unsigned long long*, CpMem> hertzKeys; // keys of the cached pairs
217 Kokkos::View<unsigned long long*, CpMem> hertzPrevKeys; // sorted keys of the PREVIOUS list
218 Kokkos::View<float* [3], CpMem> hertzPrevXi; // xi aligned with hertzPrevKeys
219 Kokkos::View<float* [3], CpMem> hertzXiWall; // per (particle, wall) shear history
220 Kokkos::View<int*, CpMem> hertzWallCand; // near-wall candidate slots (i * 8 + wallIdx)
221 Kokkos::View<int, CpMem> hertzWallCandCount;
223 // Effective Hertz contact-curvature radius for non-spherical shapes, as a fraction of the
224 // bounding radius (true curvature is undefined at faces/edges; spheres use their real radius).
226 Kokkos::View<float* [3], CpMem> hertzRefPos; // positions at the last pair build
227 Kokkos::View<float, CpMem> hertzDispMax; // max |pos-ref|^2 since the build
228 Kokkos::View<float*, CpMem> hertzE, hertzNu; // per-material Young / Poisson
229 int hertzNumPairs = -1; // -1: no valid cached list
231 static constexpr int kHertzMaxWalls = 4;
232 // Stabilization mode of the staged velocity solve (Phase B; see sim.hpp): 0 = off (pure
233 // symmetric PGS), 1 = one-sided grounded pass (default), 2 = multilevel (level-ordered
234 // symmetric sweeps -- momentum is transported, never deleted), 3 = escalate (extra symmetric
235 // sweeps; diagnostic/fallback).
237 // Restitution model of the PGS velocity solve: 0 = newton (default; per-substep restitution on
238 // the pre-solve approach — unchanged behaviour), 1 = poisson (event-level: kinetic compression
239 // impulse banked per pair, released as a budget-capped separation-velocity target during
240 // unloading — restores the multi-substep-impact rebound per-substep Newton cannot return).
242 // Per-particle material id + flat pair-material table [kMaxMaterials^2 * 2] of (restitution,
243 // friction) rows; zero-length pairMaterials = feature off (global material everywhere).
244 Kokkos::View<unsigned char*, CpMem> materialId;
245 Kokkos::View<float*, CpMem> pairMaterials;
246 Kokkos::View<int*, CpMem> contactSlot; // contact -> manifold slot (PGS friction bound)
247 Kokkos::View<int*, CpMem> contactColor; // per-contact colour (position solve; = its unit's)
248 // Position units (docs/contact_solve_framework.md §4.3): the contacts of one body pair, or of one
249 // body and one wall, swept sequentially in one work item. CSR over the solved contacts
250 // [0, nc): unitStart (numPosUnits + 1), unitContacts (nc; ascending inside a unit), and the
251 // per-unit colour. Rebuilt every substep on the Gauss-Seidel path; numPosUnits = 0 otherwise.
252 Kokkos::View<int*, CpMem> unitStart;
253 Kokkos::View<int*, CpMem> unitContacts;
254 Kokkos::View<int*, CpMem> unitColor;
255 int numPosUnits = 0;
256 // Incremental (warm-started) position colouring (single-GPU PGS path): this substep's per-contact
257 // pair keys + the previous substep's (sorted keys, colour) ledger, so a surviving contact keeps
258 // its colour and only NEW contacts re-arbitrate. Unlike the manifold graph a pair CAN own several
259 // contacts (non-spherical multi-point patches), so carried colours are conflict-CHECKED (a shared
260 // colour on a shared body -> full recolour that substep). posLastFullColors = colours at the last
261 // full recolour (creep-recompaction reference). See colorContactsIncrementalKokkos.
262 Kokkos::View<unsigned long long*, CpMem> contactKeys;
263 Kokkos::View<unsigned long long*, CpMem> prevContactKeys;
264 Kokkos::View<int*, CpMem> prevContactColor;
265 Kokkos::View<int*, CpMem> posCommitPerm;
268 // Per-body round-winner key for the colouring arbitration. 64-bit: hashed-random priority in the
269 // high word (splitmix32 of the edge index), the unique edge index in the low word. Random
270 // priorities give O(log n) arbitration rounds w.h.p.; RAW indices are adversarial for poured
271 // lattice beds (monotone index chains -> O(chain) rounds -> minutes per step at 1M grains).
272 // Dense colour-bucket scratch (buildColorBucketsKokkos): per-manifold permutation for the PGS
273 // velocity sweeps, the pooled commit permutation, a 64-int cursor, and the lazily-grown
274 // per-level coarse-cycle permutation (numLevels x numManifolds segments).
275 Kokkos::View<int*, CpMem> velPerm;
276 Kokkos::View<int*, CpMem> commitPerm;
277 Kokkos::View<int*, CpMem> bucketCursor;
278 Kokkos::View<int*, CpMem> mlBucketPerm;
279 // Fused colour sweeps (solver_fused.hpp): position-colour bucket permutation, pooled device
280 // copies of the host colour offsets (velocity / position / flat multilevel), and the software
281 // grid-barrier arrival counter (memset per fused launch, shared by all fused kernels — they
282 // are stream-ordered).
283 Kokkos::View<int*, CpMem> posPerm;
284 Kokkos::View<int*, CpMem> velOffsDev;
285 Kokkos::View<int*, CpMem> posOffsDev;
286 Kokkos::View<int*, CpMem> mlOffsDev;
287 Kokkos::View<unsigned*, CpMem> fusedBar;
288 // Cross-step CUDA-graph executable cache (opaque cudaGraphExec_t per iteration loop:
289 // velocity / onesided / multilevel / position). Owned here; leaked at teardown by design
290 // (freeing needs the CUDA context, which Kokkos may already have torn down).
291 void* graphCache[4] = {nullptr, nullptr, nullptr, nullptr};
292 Kokkos::View<long long*, CpMem> bodyWinner;
293 Kokkos::View<std::uint64_t*, CpMem> bodyColorMask; // per-body committed-colour bitmask
294 // --- island sleeping / freezing (single-GPU statics path; see sleeping.hpp) ---
295 // Per-REAL-body asleep flag + low-motion counter; effective inverse mass for the solve (asleep
296 // bodies + their ghosts -> 0, swapped in for the solve so a sleeper is immovable); the
297 // moving-wall "never sleep" flag + this-substep live contact count (contact-set-change wake); the
298 // stored count. Per-manifold / per-contact "both endpoints asleep" masks exclude a frozen island
299 // from the colouring / sweeps / multilevel hierarchy (the ledger still carries their force
300 // network).
301 Kokkos::View<unsigned char*, CpMem> asleep;
302 Kokkos::View<unsigned char*, CpMem> sleepCounter;
303 Kokkos::View<unsigned char*, CpMem> sleepMovingWall;
304 Kokkos::View<int*, CpMem> sleepCurCount;
305 Kokkos::View<int*, CpMem> sleepPrevCount;
306 Kokkos::View<float*, CpMem> invMassEff;
307 Kokkos::View<unsigned char*, CpMem> manifoldSleep;
308 Kokkos::View<unsigned char*, CpMem> contactSleep;
309 bool sleepingEnabled = true; // set_sleeping(enabled=False) disables; default ON
310 float sleepScale = 2.0f; // cSleep: sleep threshold = sleepScale * vRest
311 float wakeScale = 40.0f; // cWake: wake if an awake neighbour exceeds wakeScale * vRest
312 // (hysteresis: >> the residual settling jitter so a frozen bed
313 // stays frozen; only a genuine impact/disturbance wakes it)
314 int sleepK = 64; // substeps below threshold before sleeping (high enough that an
315 // impact's unloading/rebound completes before the network re-sleeps)
316 // rule (b): wake on a LOST contact (support removed); set_sleeping(wake_on_lost_contact=)
318 // Effective inverse-mass fraction of a sleeper for the solve (0 = exactly immovable). A small
319 // POSITIVE value keeps the sleeper very heavy but not infinitely rigid, so an awake body wedged
320 // at a frozen-pocket boundary can relieve against it instead of the PGS normal impulse diverging
321 // (trapped-between-two-rigid-constraints blow-up that a settling column reliably hit, ejected via
322 // the friction cone to NaN); the sleeper's velocity is re-zeroed each substep so no momentum
323 // accumulates and both-asleep interior manifolds are still fully excluded (the speed win). 0.01 =
324 // sleeper 100x a grain's mass: stable through the 96k column + violent pour, case3 penetration
325 // and the settled-bed freeze both preserved. set_sleeping(immovable_frac=) overrides.
326 float sleepImmovableFrac = 0.01f;
327 bool extForceActive = false; // CFD-DEM drag present -> sleeping disabled this step
328 bool extTorqueActive = false; // external couple present -> sleeping disabled this step
329 // --- Verlet-cached broadphase for the impulse step (single-GPU, non-periodic; see demStep) ---
330 // The impulse broadphase rebuilds the ArborX pair list every step; between rebuilds no new pair
331 // can appear if no particle has moved more than skin/2 (with the list built at margin + skin).
332 // impRefPos = posPred at the last build; impNumPairs = the cached candidate count (-1 = invalid,
333 // forces a build). Periodic ghosts are regenerated per step (unstable slot ids), so this is used
334 // only when the domain is non-periodic. Off by default (rebuild every step).
335 Kokkos::View<float* [3], CpMem> impRefPos;
336 Kokkos::View<float, CpMem> impDispMax;
337 int impNumPairs = -1;
338 float impRefMaxRad = 0.0f; // max effective radius at the last build (growth bound)
339 float verletSkinFrac = 0.0f; // set_verlet_skin; 0 = off (rebuild every step)
340
341 // --- solver execution policy (Simulation setters; see solve_driver.hpp / solver_fused.hpp) ---
342 // cudaGraphs and fusedSweeps only choose HOW the same arithmetic is submitted to the GPU (both
343 // paths are bit-identical, and both are inert on a non-CUDA backend). incrementalColoring does
344 // change results: the colouring fixes the Gauss-Seidel sweep order.
345 bool cudaGraphs = true; // set_cuda_graphs: capture+replay the sweep loops (CUDA)
346 int fusedSweeps = -1; // set_fused_sweeps: -1 auto, 0 off, 1 on (CUDA)
347 bool incrementalColoring = true; // set_incremental_coloring: warm-started recolouring
348
349 // --- atomic counters / scalars (rank-0 Views) ---
350 Kokkos::View<int, CpMem> pairCount, contactCount, manifoldCount, topGhost;
351 Kokkos::View<float, CpMem> maxOverlap;
352 // The accumulated position projection's stop residual max |d| w per iteration (WO-12), and its
353 // over-relaxation (internal; kPositionOmega by default, a test hook for the omega scan).
354 Kokkos::View<float, CpMem> posResidual;
355 float positionOmega = 1.5f;
356 // Max physical approach speed among approaching manifolds in the last velocity sweep — drives the
357 // colored-GS velocity loop's adaptive stop (converged once no pair approaches above the resting
358 // threshold). maxOverlap plays the same role for the position loop.
359 Kokkos::View<float, CpMem> maxApproach;
360 // Quasi-static share of maxApproach (corrections on contacts with |vn0| <= 4 vRest): the
361 // multilevel stabilization loop's stop criterion -- flowing scenes keep ballistic churn out
362 // of it, so the pass ends after ~one cycle instead of burning its full budget as an
363 // over-convergence brake on discharge.
364 Kokkos::View<float, CpMem> maxApproachQS;
365 // The largest consensus correction since the last stop vote (docs/contact_solve_framework.md
366 // §12 S14): |mean - copy| of any active copy at a local fold (velocity: velPred; position:
367 // posPred) or a rank-level M reconciliation, absolute like the phase's residual. A phase with
368 // copies folds it into its stop vote (the same Allreduce-MAX) and zeroes it after the read; a
369 // phase without copies never writes or reads it.
370 Kokkos::View<float, CpMem> maxConsensus;
371
372 // --- static geometry ---
373 Kokkos::View<ShapeDesc*, CpMem> shapes;
374 Kokkos::View<float* [3], CpMem> shell;
375 Kokkos::View<PlaneP*, CpMem> planes;
376 Kokkos::View<float*, CpMem> sdfGrid; // concatenated grid-SDF samples (imported shapes)
377 // static world-space SDF walls (drum barrel, hopper, vibrating tray) + their concatenated
378 // samples.
379 Kokkos::View<WallSdf*, CpMem> walls;
380 Kokkos::View<float*, CpMem> wallGrid;
381 // shape nodes backing ANALYTIC walls (Layer 1); WallSdf::nodes points into this
382 Kokkos::View<peclet::core::geom::ShapeNode<float>*, CpMem> wallNodes;
383 // SHAPE_SCENE particle trees: the pooled node table (base pointer + absolute indices)
384 Kokkos::View<peclet::core::geom::ShapeNode<float>*, CpMem> shapeNodes;
385
386 // --- sizes & params (host) ---
387 int capacity = 0, numReal = 0, numParticles = 0;
388 int maxPairs = 0, maxContacts = 0, numPlanes = 0, numWalls = 0;
389 // LARGEST surface-shell size across the registered shapes, mirrored from Simulation so the
390 // free-function contact-buffer growth (growContactBuffers) can size itself without reading the
391 // device shape descriptors back to the host every step.
392 int shellPoints = 0;
393 // Narrow-phase shell detection (Simulation::setShellDetection; detectContactsKokkos): 0 =
394 // one-way (default; the lower-index body's probes against the other's SDF), 1 = two-way (shell
395 // pairs probe both ways, sphere-shell pairs take the sphere probe). XPBD engine only.
397 // max wall friction (host) — gates the friction path so a frictional wall works even with a
398 // frictionless body-body material (global frictionDynamic == 0).
399 float wallFrictionMax = 0.0f;
401 F3 gravity{0, 0, 0};
402 float dt = 1e-3f, globalScale = 1.0f, growthRate = 0.0f, growthFactor = -1.0f;
404 1.0f; // shape canonical radius; effective radius = scale * globalScale * baseRadius
405 float thermostatTau = 0.0f, thermostatTemp = 0.0f,
406 thermostatKB = 1.0f; // Berendsen (tau>0 enables)
407 float frictionDynamic = 0.0f, restitutionNormal = 0.0f, skin = 0.1f;
408 // Walton tangential restitution beta (0 = tangentially dead stick, the pre-beta behaviour;
409 // > 0 reverses the pre-collision tangential surface velocity of COLLIDING contacts).
410 float restitutionTangent = 0.0f;
412 // Single-GPU collision solves: true = colored Gauss–Seidel for BOTH the restitution (velocity)
413 // and the overlap (position) solve — correct coupled multi-contact impulses + non-penetration,
414 // default; false = count-averaged Jacobi (the legacy robust path, still used by step_mpi).
415 bool velocityUseGS = true;
416
417 // --- contact-solve copies (docs/contact_solve_framework.md §4.4, §4.5) ---
419 // Solve views (§4.5): per slot k x invMass / k x invInertia of its body while the phase has
420 // copies (else the sweeps take invMass / invInertia themselves), and splitSlot = (k > 1).
421 // Grow-only, sized to the slots the phase touches.
422 Kokkos::View<float*, CpMem> invMassSolve;
423 Kokkos::View<float* [3], CpMem> invInertiaSolve;
424 Kokkos::View<unsigned char*, CpMem> splitSlot;
425 Kokkos::View<int*, CpMem> vertexDegree; // scratch: per colouring vertex, active edges
426 // Rank-level M (docs/contact_solve_framework.md §13.3; the distributed step only, recomputed
427 // every substep): per slot the local active copy counts aVel / aPos (the activity pass: 0 or 1
428 // at a vertex outside any group, the group's count at a hub base) and the global active copy
429 // counts kVel / kPos (owner: max(1, a(own) + sum of the ghosts' a), forwarded to the ghosts);
430 // activityHit the pass's per-slot scratch; invMassCoarse the multilevel coarse vertex's inverse
431 // mass invMass k / max(1, a) (§13.2). Grow-only.
432 Kokkos::View<int*, CpMem> aVel, aPos, kVel, kPos;
433 Kokkos::View<unsigned char*, CpMem> activityHit;
434 // Rank-level X (docs/contact_solve_framework.md §1.4, §13.5 WO-6; the g = 0 one-shot on an
435 // exchanging rank): per slot the velocity activity mask (bit col(r) of every rank on which the
436 // body is active, made global by the g = 0 opening), the per-manifold fire gate of the current
437 // sync interval, and the solve counter that starts each substep's holder cycle one step later.
438 // solveEpoch is incremented by every demSolveContacts, so it is identical on all ranks.
439 Kokkos::View<unsigned long long*, CpMem> velMask;
440 Kokkos::View<unsigned char*, CpMem> xGate;
441 long long solveEpoch = 0;
442 Kokkos::View<float*, CpMem> invMassCoarse;
443 // ... and its inverse inertia invInertia k / max(1, a) (docs/contact_physics_followups.md §2.5),
444 // built with invMassCoarse under rank-level M. Grow-only, lazy.
445 Kokkos::View<float* [3], CpMem> invInertiaCoarse;
446 // split_stats.orphanClamps, accumulated on the device by the owner apply (read by
447 // Simulation::debugSplitStats, reset by the step entry points; no fence in the step).
448 Kokkos::View<int, CpMem> orphanClampCount;
449 Kokkos::View<float* [3], CpMem>
450 imageShift; // demStep: posPred(image) - posPred(real) at generation
451 // The velocity incremental colouring carries colours by pair key; after a substep coloured
452 // through hub copies those colours are per COPY and may repeat at the body, so the next substep
453 // recolours in full (§4.2 item 4).
456 // The last multilevel hierarchy's shape (host), for the coarse-colouring validity check
457 // (Simulation::debugMultilevelColoringConflicts). numLevels = 0: none built last substep.
458 struct MlLast {
460 std::vector<int> parentOff, numGroups;
462
463 // Diagnostics (Simulation::debugIterationCounters; docs/contact_solve_framework.md §12 S12):
464 // with iterCounters on, a single-rank device-side (fused) main velocity / position loop writes
465 // its iteration count to iterCountDev(0) / (1), read back into splitStats.velItersUsed /
466 // posItersUsed. Off (the default): nothing is written or read back, the counters read -1.
467 bool iterCounters = false;
468 // TEST-ONLY (Simulation::debugNoAdaptiveStop; §12 S13): every adaptive stop of the contact solve
469 // is disabled, so each loop runs exactly its iteration cap (the votes still run: they are
470 // collective and carry the colouring invariant). Off (the default) changes nothing.
471 bool noAdaptiveStop = false;
472 Kokkos::View<int*, CpMem> iterCountDev;
473
474 // TEST-ONLY contact capture (Simulation::debugCaptureContacts; see DebugContactCapture).
475 bool debugCapture = false;
477
478 // nPlanes is the plane-array CAPACITY; numPlanes (the live count) stays 0 until planes are added.
479 void allocate(int cap, int maxPairs_, int maxContacts_, int nShapes, int nShell, int nPlanes) {
480 capacity = cap;
481 maxPairs = maxPairs_;
482 maxContacts = maxContacts_;
483 numPlanes = 0;
484 pos = V3("pos", cap);
485 invMass = Vf("invMass", cap);
486 quat = V4("quat", cap);
487 vel = V3("vel", cap);
488 angVel = V3("angVel", cap);
489 invInertia = V3("invInertia", cap);
490 scale = Vf("scale", cap);
491 targetScale = Vf("targetScale", cap);
492 shapeId = Vi("shapeId", cap);
493 posPred = V3("posPred", cap);
494 quatPred = V4("quatPred", cap);
495 velPred = V3("velPred", cap);
496 angVelPred = V3("angVelPred", cap);
497 deltaPos = V3("deltaPos", cap);
498 deltaQuat = V4("deltaQuat", cap);
499 deltaVel = V3("deltaVel", cap);
500 deltaAngVel = V3("deltaAngVel", cap);
501 constraintCounts = Vi("constraintCounts", cap);
502 realIndices = Vi("realIndices", cap);
503 gid = Vi("gid", cap);
504 planeFriction = Kokkos::View<float* [2], CpMem>("planeFriction", cap);
505 rad = Vf("rad", cap);
506 extForce = V3("extForce", cap); // zero-initialised => no external force by default
507 extTorque = V3("extTorque", cap);
508 pairs = Kokkos::View<int* [2], CpMem>("pairs", maxPairs);
509 contacts = Kokkos::View<ContactC*, CpMem>("contacts", maxContacts);
510 manifolds = Kokkos::View<ManifoldC*, CpMem>("manifolds", maxContacts);
511 manifoldColor = Kokkos::View<int*, CpMem>("manifoldColor", maxContacts);
512 prevManifoldColor = Kokkos::View<int*, CpMem>("prevManifoldColor", maxContacts);
513 pairKeys = Kokkos::View<unsigned long long*, CpMem>("pairKeys", maxContacts);
514 prevPairKeys = Kokkos::View<unsigned long long*, CpMem>("prevPairKeys", maxContacts);
515 manifoldPersistent = Kokkos::View<unsigned char*, CpMem>("manifoldPersistent", maxContacts);
516 prevPairCount = 0;
517 contactColor = Kokkos::View<int*, CpMem>("contactColor", maxContacts);
518 unitStart = Kokkos::View<int*, CpMem>("unitStart", maxContacts + 1);
519 unitContacts = Kokkos::View<int*, CpMem>("unitContacts", maxContacts);
520 unitColor = Kokkos::View<int*, CpMem>("unitColor", maxContacts);
521 contactKeys = Kokkos::View<unsigned long long*, CpMem>("contactKeys", maxContacts);
522 prevContactKeys = Kokkos::View<unsigned long long*, CpMem>("prevContactKeys", maxContacts);
523 prevContactColor = Kokkos::View<int*, CpMem>("prevContactColor", maxContacts);
524 posCommitPerm = Kokkos::View<int*, CpMem>("posCommitPerm", maxContacts);
525 velPerm = Kokkos::View<int*, CpMem>("velPerm", maxContacts);
526 commitPerm = Kokkos::View<int*, CpMem>("commitPerm", maxContacts);
527 bucketCursor = Kokkos::View<int*, CpMem>("bucketCursor", 64);
528 mlBucketPerm = Kokkos::View<int*, CpMem>("mlBucketPerm", 0);
529 posPerm = Kokkos::View<int*, CpMem>("posPerm", maxContacts);
530 velOffsDev = Kokkos::View<int*, CpMem>("velOffsDev", 65);
531 posOffsDev = Kokkos::View<int*, CpMem>("posOffsDev", 65);
532 mlOffsDev = Kokkos::View<int*, CpMem>("mlOffsDev", 65 * 10); // 10 = kMlMaxLevels
533 fusedBar = Kokkos::View<unsigned*, CpMem>("fusedBar", 32769); // 4096 blocks x 8 + 1
534 bodyWinner = Kokkos::View<long long*, CpMem>("bodyWinner", cap);
535 bodyColorMask = Kokkos::View<std::uint64_t*, CpMem>("bodyColorMask", cap);
536 asleep = Kokkos::View<unsigned char*, CpMem>("asleep", cap);
537 sleepCounter = Kokkos::View<unsigned char*, CpMem>("sleepCounter", cap);
538 sleepMovingWall = Kokkos::View<unsigned char*, CpMem>("sleepMovingWall", cap);
539 sleepCurCount = Kokkos::View<int*, CpMem>("sleepCurCount", cap);
540 sleepPrevCount = Kokkos::View<int*, CpMem>("sleepPrevCount", cap);
541 invMassEff = Kokkos::View<float*, CpMem>("invMassEff", cap);
542 manifoldSleep = Kokkos::View<unsigned char*, CpMem>("manifoldSleep", maxContacts);
543 contactSleep = Kokkos::View<unsigned char*, CpMem>("contactSleep", maxContacts);
544 impRefPos = Kokkos::View<float* [3], CpMem>("impRefPos", cap);
545 impDispMax = Kokkos::View<float, CpMem>("impDispMax");
546 groundedLevel = Kokkos::View<unsigned char*, CpMem>("groundedLevel", cap);
547 materialId = Kokkos::View<unsigned char*, CpMem>("materialId", cap);
548 lambdaAcc = Kokkos::View<float*, CpMem>("lambdaAcc", maxContacts);
549 lambdaT = Kokkos::View<float* [3], CpMem>("lambdaT", maxContacts);
550 posLambdaContact = Kokkos::View<float*, CpMem>("posLambdaContact", maxContacts);
551 posImpulse = Kokkos::View<float*, CpMem>("posImpulse", maxContacts);
552 prevPosImpulse = Kokkos::View<float*, CpMem>("prevPosImpulse", maxContacts);
553 restBank = Kokkos::View<float*, CpMem>("restBank", maxContacts);
554 prevRestBank = Kokkos::View<float*, CpMem>("prevRestBank", maxContacts);
555 restRel = Kokkos::View<float*, CpMem>("restRel", maxContacts);
556 restVPeak = Kokkos::View<float*, CpMem>("restVPeak", maxContacts);
557 prevRestVPeak = Kokkos::View<float*, CpMem>("prevRestVPeak", maxContacts);
558 bodyOrphan = Kokkos::View<float*, CpMem>("bodyOrphan", cap);
559 bodyOrphanVPeak = Kokkos::View<float*, CpMem>("bodyOrphanVPeak", cap);
560 prevMatched = Kokkos::View<unsigned char*, CpMem>("prevMatched", maxContacts);
561 sideFlags = Kokkos::View<unsigned char*, CpMem>("sideFlags", maxContacts);
562 heightLevel = Kokkos::View<int*, CpMem>("heightLevel", cap);
563 levelKey = Kokkos::View<int*, CpMem>("levelKey", maxContacts);
564 levelPerm = Kokkos::View<int*, CpMem>("levelPerm", maxContacts);
565 mlColorPacked = Kokkos::View<long long*, CpMem>("mlColorPacked", maxContacts);
566 mlParent = Kokkos::View<int*, CpMem>("mlParent", 5 * cap);
567 mlInvMassG = Kokkos::View<float*, CpMem>("mlInvMassG", 4 * cap);
568 mlVelG = Kokkos::View<float* [3], CpMem>("mlVelG", 4 * cap);
569 mlVelG0 = Kokkos::View<float* [3], CpMem>("mlVelG0", 4 * cap);
570 mlMassG = Kokkos::View<float*, CpMem>("mlMassG", 4 * cap);
571 mlGrp = Kokkos::View<int*, CpMem>("mlGrp", cap);
572 mlMate = Kokkos::View<int*, CpMem>("mlMate", cap);
573 hertzXiWall = Kokkos::View<float* [3], CpMem>("hertzXiWall", cap * kHertzMaxWalls);
574 hertzWallCand = Kokkos::View<int*, CpMem>("hertzWallCand", cap * 2);
575 hertzSnWall = Kokkos::View<float*, CpMem>("hertzSnWall", cap * kHertzMaxWalls);
576 hertzWallCandCount = Kokkos::View<int, CpMem>("hertzWallCandCount");
577 hertzRefPos = Kokkos::View<float* [3], CpMem>("hertzRefPos", cap);
578 hertzDispMax = Kokkos::View<float, CpMem>("hertzDispMax");
579 hertzE = Kokkos::View<float*, CpMem>("hertzE", 8);
580 hertzNu = Kokkos::View<float*, CpMem>("hertzNu", 8);
581 {
582 auto he = Kokkos::create_mirror_view(hertzE);
583 auto hn = Kokkos::create_mirror_view(hertzNu);
584 for (int i = 0; i < 8; ++i) {
585 he(i) = 1.0e9f;
586 hn(i) = 0.25f;
587 }
588 Kokkos::deep_copy(hertzE, he);
589 Kokkos::deep_copy(hertzNu, hn);
590 }
591 prevLambdaT = Kokkos::View<float* [3], CpMem>("prevLambdaT", maxContacts);
592 contactSlot = Kokkos::View<int*, CpMem>("contactSlot", maxContacts);
593 prevLambda = Kokkos::View<float*, CpMem>("prevLambda", maxContacts);
594 vn0 = Kokkos::View<float*, CpMem>("vn0", maxContacts);
595 vt0 = Kokkos::View<float* [3], CpMem>("vt0", maxContacts);
596 pairCount = Kokkos::View<int, CpMem>("pairCount");
597 contactCount = Kokkos::View<int, CpMem>("contactCount");
598 manifoldCount = Kokkos::View<int, CpMem>("manifoldCount");
599 topGhost = Kokkos::View<int, CpMem>("topGhost");
600 maxOverlap = Kokkos::View<float, CpMem>("maxOverlap");
601 posResidual = Kokkos::View<float, CpMem>("posResidual");
602 maxApproach = Kokkos::View<float, CpMem>("maxApproach");
603 maxApproachQS = Kokkos::View<float, CpMem>("maxApproachQS");
604 maxConsensus = Kokkos::View<float, CpMem>("maxConsensus");
605 shapes = Kokkos::View<ShapeDesc*, CpMem>("shapes", nShapes > 0 ? nShapes : 1);
606 shell = Kokkos::View<float* [3], CpMem>("shell", nShell > 0 ? nShell : 1);
607 planes = Kokkos::View<PlaneP*, CpMem>("planes", nPlanes > 0 ? nPlanes : 1);
608 sdfGrid = Kokkos::View<float*, CpMem>("sdfGrid", 1); // resized by setSdfShape
609 walls = Kokkos::View<WallSdf*, CpMem>("walls", 1); // resized by addSdfWall
610 wallGrid = Kokkos::View<float*, CpMem>("wallGrid", 1); // concatenated wall samples
611 wallNodes = Kokkos::View<peclet::core::geom::ShapeNode<float>*, CpMem>("wallNodes", 1);
612 shapeNodes = Kokkos::View<peclet::core::geom::ShapeNode<float>*, CpMem>("shapeNodes", 1);
613 numWalls = 0;
614 }
615
616 // Grow the per-particle SoA to hold at least `newCap` particles (real + periodic-ghost headroom),
617 // preserving the existing [0,numReal) state (Kokkos::resize copies the overlapping subextent).
618 // The single-GPU step sizes this from the domain before generating ghosts; without the headroom
619 // every ghost slot overflows `capacity` and cross-boundary contacts silently vanish. A no-op when
620 // the SoA is already large enough (e.g. the MPI path, whose caller pre-sizes capacity for the
621 // worst-case ghost band). The collision buffers (pairs/contacts/manifolds) keep their
622 // construction-time sizing — each real particle still issues one broad-phase query.
623 void ensureCapacity(int newCap) {
624 if (newCap <= capacity)
625 return;
626 Kokkos::resize(pos, newCap);
627 Kokkos::resize(invMass, newCap);
628 Kokkos::resize(quat, newCap);
629 Kokkos::resize(vel, newCap);
630 Kokkos::resize(angVel, newCap);
631 Kokkos::resize(invInertia, newCap);
632 Kokkos::resize(scale, newCap);
633 Kokkos::resize(targetScale, newCap);
634 Kokkos::resize(shapeId, newCap);
635 Kokkos::resize(posPred, newCap);
636 Kokkos::resize(quatPred, newCap);
637 Kokkos::resize(velPred, newCap);
638 Kokkos::resize(angVelPred, newCap);
639 Kokkos::resize(deltaPos, newCap);
640 Kokkos::resize(deltaQuat, newCap);
641 Kokkos::resize(deltaVel, newCap);
642 Kokkos::resize(deltaAngVel, newCap);
643 Kokkos::resize(constraintCounts, newCap);
644 Kokkos::resize(realIndices, newCap);
645 Kokkos::resize(gid, newCap);
646 Kokkos::resize(bodyWinner, newCap);
647 Kokkos::resize(bodyColorMask, newCap);
648 Kokkos::resize(groundedLevel, newCap);
649 Kokkos::resize(heightLevel, newCap);
650 Kokkos::resize(planeFriction, newCap);
651 Kokkos::resize(rad, newCap);
652 Kokkos::resize(extForce, newCap);
653 Kokkos::resize(extTorque, newCap);
654 // materialId is written per GHOST slot by generateGhostsKokkos (guarded by `capacity`),
655 // so it MUST track the padded capacity like every other per-slot array. Its absence here
656 // was a silent out-of-bounds write into the neighbouring allocation — harmless or
657 // catastrophic depending on the device allocator's layout (the 2026-08 H100 packing
658 // corruption: contacts silently unresolved, phi_voxel 0.40 instead of 0.50).
659 Kokkos::resize(materialId, newCap);
660 // Not ghost-indexed today, but per-particle and cap-sized at construction — keep them in
661 // lockstep so a future ghost-slot consumer cannot reintroduce the same class of bug.
662 Kokkos::resize(asleep, newCap);
663 Kokkos::resize(sleepCounter, newCap);
664 Kokkos::resize(sleepMovingWall, newCap);
665 // The rest of the capacity-sized per-body arrays. These were the LAST twelve left behind, and
666 // the same class of bug as materialId above: every one of them is written up to numParticles
667 // (or numReal) by some kernel, so any that keeps the pre-growth extent is an out-of-bounds
668 // write. Found via peclet-examples/pall-ring-packing, where a 48-ring pour reported
669 // "corrupted double-linked list" from inside step() -- mlGrp/mlMate (the multilevel
670 // stabiliser's per-body group and mate arrays) and invMassEff (written for numParticles by
671 // buildInvMassEffKokkos) are the ones that bit. A cap-sized array that ensureCapacity does not
672 // resize is a latent heap corruption, full stop; there is no reason to keep any of them out.
673 Kokkos::resize(invMassEff, newCap);
674 Kokkos::resize(sleepCurCount, newCap);
675 Kokkos::resize(sleepPrevCount, newCap);
676 Kokkos::resize(bodyOrphan, newCap);
677 Kokkos::resize(bodyOrphanVPeak, newCap);
678 Kokkos::resize(mlGrp, newCap);
679 Kokkos::resize(mlMate, newCap);
680 Kokkos::resize(impRefPos, newCap);
681 Kokkos::resize(hertzRefPos, newCap);
682 Kokkos::resize(hertzWallCand, newCap);
683 Kokkos::resize(hertzSnWall, newCap);
684 Kokkos::resize(hertzXiWall, newCap);
685 capacity = newCap;
686 }
687
688 // Const views for the read-only kernel inputs.
689 Kokkos::View<const float* [3], CpMem> cpos() const { return pos; }
690 Kokkos::View<const float*, CpMem> crad() const { return rad; }
691};
692
693} // namespace peclet::dem
694
695#endif // DEM_PARTICLES_HPP
dem — portable (Kokkos) contact->manifold reduction, replacing the thrust-based reduce_contacts_to_ma...
dem — portable (Kokkos) time integration kernels (integration.cu).
Kokkos::View< float *, CpMem > Vf
Kokkos::View< int *, CpMem > Vi
Kokkos::View< float *[3], CpMem > V3
CpExec::memory_space CpMem
Kokkos::View< float *[4], CpMem > V4
dem — portable (Kokkos) narrow-phase: SDF point-shell collision + boundary planes.
TEST-ONLY host capture of one distributed substep's contact ownership (C++ only; filled by demStepMpi...
Definition particles.hpp:26
std::vector< float > dist
Definition particles.hpp:30
std::vector< float > posPred
Definition particles.hpp:33
std::vector< int > parentOff
std::vector< int > numGroups
Kokkos::View< WallSdf *, CpMem > walls
Kokkos::View< float, CpMem > posResidual
Kokkos::View< const float *[3], CpMem > cpos() const
Kokkos::View< float *, CpMem > hertzE
Kokkos::View< int *, CpMem > commitPerm
Kokkos::View< float *[3], CpMem > hertzXi
Kokkos::View< unsigned *, CpMem > fusedBar
Kokkos::View< unsigned char *, CpMem > asleep
Kokkos::View< int *, CpMem > bucketCursor
Kokkos::View< unsigned char *, CpMem > materialId
Kokkos::View< unsigned char *, CpMem > sideFlags
Kokkos::View< unsigned long long *, CpMem > prevContactKeys
Kokkos::View< int *, CpMem > mlGrp
Kokkos::View< unsigned char *, CpMem > xGate
Kokkos::View< unsigned char *, CpMem > manifoldPersistent
Kokkos::View< int *, CpMem > aPos
Kokkos::View< int, CpMem > hertzWallCandCount
Kokkos::View< float *[3], CpMem > impRefPos
Kokkos::View< int, CpMem > manifoldCount
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
void ensureCapacity(int newCap)
Kokkos::View< int *, CpMem > unitStart
Kokkos::View< ManifoldC *, CpMem > manifolds
Kokkos::View< float *[3], CpMem > mlOriginG
Kokkos::View< float *, CpMem > vn0
Kokkos::View< float *, CpMem > mlMassG
Kokkos::View< int *, CpMem > levelKey
Kokkos::View< int *, CpMem > sleepCurCount
Kokkos::View< int *[2], CpMem > pairs
Kokkos::View< float *[3], CpMem > invInertiaSolve
Kokkos::View< float *[3], CpMem > imageShift
Kokkos::View< int, CpMem > contactCount
DebugContactCapture debugCaptured
Kokkos::View< int *, CpMem > hertzWallCand
Kokkos::View< unsigned char *, CpMem > sleepMovingWall
Kokkos::View< float, CpMem > hertzDispMax
Kokkos::View< float *[3], CpMem > mlAngG0
Kokkos::View< float *[3], CpMem > vt0
Kokkos::View< int *, CpMem > vertexDegree
Kokkos::View< float *, CpMem > restRel
Kokkos::View< int *, CpMem > levelPerm
Kokkos::View< int *, CpMem > prevManifoldColor
Kokkos::View< float *[3], CpMem > mlAngG
static constexpr int kHertzMaxWalls
Kokkos::View< unsigned char *, CpMem > splitSlot
Kokkos::View< int *, CpMem > kVel
Kokkos::View< float *[3], CpMem > mlComOffG
Kokkos::View< float, CpMem > impDispMax
Kokkos::View< unsigned long long *, CpMem > contactKeys
Kokkos::View< float *, CpMem > pairMaterials
Kokkos::View< ShapeDesc *, CpMem > shapes
Kokkos::View< unsigned long long *, CpMem > hertzPrevKeys
Kokkos::View< int *, CpMem > prevContactColor
Kokkos::View< unsigned char *, CpMem > prevMatched
Kokkos::View< unsigned char *, CpMem > activityHit
Kokkos::View< float, CpMem > maxApproach
Kokkos::View< float *, CpMem > prevRestBank
Kokkos::View< float *, CpMem > restVPeak
Kokkos::View< peclet::core::geom::ShapeNode< float > *, CpMem > wallNodes
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 > hertzNu
Kokkos::View< unsigned long long *, CpMem > hertzKeys
struct peclet::dem::Particles::MlLast mlLast
Kokkos::View< int, CpMem > topGhost
Kokkos::View< int *, CpMem > aVel
Kokkos::View< float, CpMem > maxConsensus
Kokkos::View< float *, CpMem > bodyOrphan
Kokkos::View< unsigned long long *, CpMem > prevPairKeys
Kokkos::View< float *, CpMem > hertzSnWall
Kokkos::View< int *, CpMem > posPerm
Kokkos::View< float *, CpMem > invMassEff
Kokkos::View< float *, CpMem > prevPosImpulse
Kokkos::View< int *, CpMem > contactColor
Kokkos::View< float *[3], CpMem > mlVelG
Kokkos::View< float *, CpMem > invMassSolve
Kokkos::View< peclet::core::geom::ShapeNode< float > *, CpMem > shapeNodes
Kokkos::View< float *[3], CpMem > mlVelG0
Kokkos::View< int *, CpMem > sleepPrevCount
Kokkos::View< int *, CpMem > mlBucketPerm
Kokkos::View< float *[3], CpMem > hertzRefPos
Kokkos::View< float *[3], CpMem > invInertiaCoarse
Kokkos::View< int *, CpMem > mlParent
Kokkos::View< float *, CpMem > sdfGrid
Kokkos::View< float *[3], CpMem > lambdaT
Kokkos::View< float *, CpMem > hertzSnPair
Kokkos::View< float *[3], CpMem > prevLambdaT
Kokkos::View< int *, CpMem > unitColor
Kokkos::View< int *, CpMem > kPos
Kokkos::View< float, CpMem > maxOverlap
Kokkos::View< float *, CpMem > posLambdaContact
Kokkos::View< unsigned long long *, CpMem > velMask
Kokkos::View< float *, CpMem > posImpulse
Kokkos::View< int *, CpMem > contactSlot
Kokkos::View< unsigned char *, CpMem > sleepCounter
Kokkos::View< float *, CpMem > mlInvMassG
Kokkos::View< int *, CpMem > heightLevel
Kokkos::View< long long *, CpMem > bodyWinner
Kokkos::View< float *, CpMem > lambdaAcc
Kokkos::View< double *[7], CpMem > mlAccD
Kokkos::View< long long *, CpMem > mlColorPacked
Kokkos::View< float *, CpMem > invMassCoarse
Kokkos::View< float *, CpMem > wallGrid
Kokkos::View< int *, CpMem > iterCountDev
Kokkos::View< float, CpMem > maxApproachQS
Kokkos::View< unsigned char *, CpMem > manifoldSleep
Kokkos::View< const float *, CpMem > crad() const
Kokkos::View< int, CpMem > orphanClampCount
void allocate(int cap, int maxPairs_, int maxContacts_, int nShapes, int nShell, int nPlanes)
Kokkos::View< float *[2], CpMem > planeFriction
Definition particles.hpp:98
Kokkos::View< float *[3], CpMem > shell
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< float *[3], CpMem > hertzXiWall
Kokkos::View< int *, CpMem > unitContacts
Kokkos::View< PlaneP *, CpMem > planes
Kokkos::View< float *[3], CpMem > hertzPrevXi
Kokkos::View< int *, CpMem > manifoldColor
Kokkos::View< float *[6], CpMem > mlInvIG
One solve phase's body copies (docs/contact_solve_framework.md §4.4, §4.5, §WO-4 item 2): the hub cop...
Definition particles.hpp:44
Kokkos::View< float *[3], CpMem > seedX
Definition particles.hpp:53
Kokkos::View< int *, CpMem > hubS
Definition particles.hpp:49
Kokkos::View< float *[3], CpMem > seedW
Definition particles.hpp:53
Kokkos::View< int *, CpMem > slotB
Definition particles.hpp:47
Kokkos::View< float *[3], CpMem > groupShift
Definition particles.hpp:51
Kokkos::View< int *, CpMem > hubVertex
Definition particles.hpp:49
Kokkos::View< int *, CpMem > copyBase
Definition particles.hpp:48
Kokkos::View< int *, CpMem > slotA
Definition particles.hpp:47
Kokkos::View< int *, CpMem > groupK
Definition particles.hpp:50
Kokkos::View< int *, CpMem > groupStart
Definition particles.hpp:50
Kokkos::View< unsigned char *, CpMem > groupActive
Definition particles.hpp:52
Kokkos::View< int *, CpMem > groupSlot
Definition particles.hpp:50
diagnostics.split_stats() (docs/contact_solve_framework.md §WO-4 item 4, §13.5 WO-4b): the last subst...
Definition particles.hpp:66
long long unfiredSplitContacts
Definition particles.hpp:68