peclet-dem
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 <Kokkos_Core.hpp>
14
15#include "contact_preprocessing.hpp" // ContactC, ManifoldC
16#include "integration.hpp" // Domain, V3/V4/Vf/Vi
17#include "narrowphase.hpp" // ShapeDesc, PlaneP
18
19namespace peclet::dem {
20
21struct Particles {
22 // --- per-particle state (size = capacity) ---
42 Kokkos::View<float* [2], CpMem> planeFriction;
43 Vf rad; // effective broadphase radius scratch (scale * globalScale)
44 V3 extForce; // per-particle external FORCE (e.g. fluid drag); F=ma => dv = extForce*invMass*dt
45
46 // --- collision/contact/manifold buffers ---
47 Kokkos::View<int* [2], CpMem> pairs; // broadphase candidates (maxPairs)
48 Kokkos::View<ContactC*, CpMem> contacts; // narrowphase output (maxContacts)
49 Kokkos::View<ManifoldC*, CpMem> manifolds; // reduction output (maxContacts)
50
51 // --- atomic counters / scalars (rank-0 Views) ---
52 Kokkos::View<int, CpMem> pairCount, contactCount, manifoldCount, topGhost;
53 Kokkos::View<float, CpMem> maxOverlap;
54
55 // --- static geometry ---
56 Kokkos::View<ShapeDesc*, CpMem> shapes;
57 Kokkos::View<float* [3], CpMem> shell;
58 Kokkos::View<PlaneP*, CpMem> planes;
59 Kokkos::View<float*, CpMem> sdfGrid; // concatenated grid-SDF samples (imported shapes)
60 // static world-space SDF walls (drum barrel, hopper, vibrating tray) + their concatenated samples.
61 Kokkos::View<WallSdf*, CpMem> walls;
62 Kokkos::View<float*, CpMem> wallGrid;
63
64 // --- sizes & params (host) ---
65 int capacity = 0, numReal = 0, numParticles = 0;
66 int maxPairs = 0, maxContacts = 0, numPlanes = 0, numWalls = 0;
67 // max wall friction (host) — gates the friction path so a frictional wall works even with a
68 // frictionless body-body material (global frictionDynamic == 0).
69 float wallFrictionMax = 0.0f;
71 F3 gravity{0, 0, 0};
72 float dt = 1e-3f, globalScale = 1.0f, growthRate = 0.0f, growthFactor = -1.0f;
73 float baseRadius = 1.0f; // shape canonical radius; effective radius = scale * globalScale * baseRadius
74 float thermostatTau = 0.0f, thermostatTemp = 0.0f,
75 thermostatKB = 1.0f; // Berendsen (tau>0 enables)
76 float frictionDynamic = 0.0f, restitutionNormal = 0.0f, skin = 0.1f;
78
79 // nPlanes is the plane-array CAPACITY; numPlanes (the live count) stays 0 until planes are added.
80 void allocate(int cap, int maxPairs_, int maxContacts_, int nShapes, int nShell, int nPlanes) {
81 capacity = cap;
82 maxPairs = maxPairs_;
83 maxContacts = maxContacts_;
84 numPlanes = 0;
85 pos = V3("pos", cap);
86 invMass = Vf("invMass", cap);
87 quat = V4("quat", cap);
88 vel = V3("vel", cap);
89 angVel = V3("angVel", cap);
90 invInertia = V3("invInertia", cap);
91 scale = Vf("scale", cap);
92 targetScale = Vf("targetScale", cap);
93 shapeId = Vi("shapeId", cap);
94 posPred = V3("posPred", cap);
95 quatPred = V4("quatPred", cap);
96 velPred = V3("velPred", cap);
97 angVelPred = V3("angVelPred", cap);
98 deltaPos = V3("deltaPos", cap);
99 deltaQuat = V4("deltaQuat", cap);
100 deltaVel = V3("deltaVel", cap);
101 deltaAngVel = V3("deltaAngVel", cap);
102 constraintCounts = Vi("constraintCounts", cap);
103 realIndices = Vi("realIndices", cap);
104 planeFriction = Kokkos::View<float* [2], CpMem>("planeFriction", cap);
105 rad = Vf("rad", cap);
106 extForce = V3("extForce", cap); // zero-initialised => no external force by default
107 pairs = Kokkos::View<int* [2], CpMem>("pairs", maxPairs);
108 contacts = Kokkos::View<ContactC*, CpMem>("contacts", maxContacts);
109 manifolds = Kokkos::View<ManifoldC*, CpMem>("manifolds", maxContacts);
110 pairCount = Kokkos::View<int, CpMem>("pairCount");
111 contactCount = Kokkos::View<int, CpMem>("contactCount");
112 manifoldCount = Kokkos::View<int, CpMem>("manifoldCount");
113 topGhost = Kokkos::View<int, CpMem>("topGhost");
114 maxOverlap = Kokkos::View<float, CpMem>("maxOverlap");
115 shapes = Kokkos::View<ShapeDesc*, CpMem>("shapes", nShapes > 0 ? nShapes : 1);
116 shell = Kokkos::View<float* [3], CpMem>("shell", nShell > 0 ? nShell : 1);
117 planes = Kokkos::View<PlaneP*, CpMem>("planes", nPlanes > 0 ? nPlanes : 1);
118 sdfGrid = Kokkos::View<float*, CpMem>("sdfGrid", 1); // resized by setSdfShape
119 walls = Kokkos::View<WallSdf*, CpMem>("walls", 1); // resized by addSdfWall
120 wallGrid = Kokkos::View<float*, CpMem>("wallGrid", 1); // concatenated wall samples
121 numWalls = 0;
122 }
123
124 // Grow the per-particle SoA to hold at least `newCap` particles (real + periodic-ghost headroom),
125 // preserving the existing [0,numReal) state (Kokkos::resize copies the overlapping subextent). The
126 // single-GPU step sizes this from the domain before generating ghosts; without the headroom every
127 // ghost slot overflows `capacity` and cross-boundary contacts silently vanish. A no-op when the
128 // SoA is already large enough (e.g. the MPI path, whose caller pre-sizes capacity for the
129 // worst-case ghost band). The collision buffers (pairs/contacts/manifolds) keep their
130 // construction-time sizing — each real particle still issues one broad-phase query.
131 void ensureCapacity(int newCap) {
132 if (newCap <= capacity)
133 return;
134 Kokkos::resize(pos, newCap);
135 Kokkos::resize(invMass, newCap);
136 Kokkos::resize(quat, newCap);
137 Kokkos::resize(vel, newCap);
138 Kokkos::resize(angVel, newCap);
139 Kokkos::resize(invInertia, newCap);
140 Kokkos::resize(scale, newCap);
141 Kokkos::resize(targetScale, newCap);
142 Kokkos::resize(shapeId, newCap);
143 Kokkos::resize(posPred, newCap);
144 Kokkos::resize(quatPred, newCap);
145 Kokkos::resize(velPred, newCap);
146 Kokkos::resize(angVelPred, newCap);
147 Kokkos::resize(deltaPos, newCap);
148 Kokkos::resize(deltaQuat, newCap);
149 Kokkos::resize(deltaVel, newCap);
150 Kokkos::resize(deltaAngVel, newCap);
151 Kokkos::resize(constraintCounts, newCap);
152 Kokkos::resize(realIndices, newCap);
153 Kokkos::resize(planeFriction, newCap);
154 Kokkos::resize(rad, newCap);
155 Kokkos::resize(extForce, newCap);
156 capacity = newCap;
157 }
158
159 // Const views for the read-only kernel inputs.
160 Kokkos::View<const float* [3], CpMem> cpos() const { return pos; }
161 Kokkos::View<const float*, CpMem> crad() const { return rad; }
162};
163
164} // namespace peclet::dem
165
166#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
Kokkos::View< float *[4], CpMem > V4
dem — portable (Kokkos) narrow-phase: SDF point-shell collision + boundary planes.
Kokkos::View< WallSdf *, CpMem > walls
Definition particles.hpp:61
Kokkos::View< const float *[3], CpMem > cpos() const
Kokkos::View< int, CpMem > manifoldCount
Definition particles.hpp:52
void ensureCapacity(int newCap)
Kokkos::View< ManifoldC *, CpMem > manifolds
Definition particles.hpp:49
Kokkos::View< int *[2], CpMem > pairs
Definition particles.hpp:47
Kokkos::View< int, CpMem > contactCount
Definition particles.hpp:52
Kokkos::View< ShapeDesc *, CpMem > shapes
Definition particles.hpp:56
Kokkos::View< int, CpMem > topGhost
Definition particles.hpp:52
Kokkos::View< float *, CpMem > sdfGrid
Definition particles.hpp:59
Kokkos::View< float, CpMem > maxOverlap
Definition particles.hpp:53
Kokkos::View< float *, CpMem > wallGrid
Definition particles.hpp:62
Kokkos::View< const float *, CpMem > crad() const
void allocate(int cap, int maxPairs_, int maxContacts_, int nShapes, int nShell, int nPlanes)
Definition particles.hpp:80
Kokkos::View< float *[2], CpMem > planeFriction
Definition particles.hpp:42
Kokkos::View< float *[3], CpMem > shell
Definition particles.hpp:57
Kokkos::View< ContactC *, CpMem > contacts
Definition particles.hpp:48
Kokkos::View< int, CpMem > pairCount
Definition particles.hpp:52
Kokkos::View< PlaneP *, CpMem > planes
Definition particles.hpp:58