peclet-dem 0.4.0
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
Loading...
Searching...
No Matches
sleeping.hpp
Go to the documentation of this file.
1
19#ifndef DEM_SLEEPING_HPP
20#define DEM_SLEEPING_HPP
21
22#include <Kokkos_Core.hpp>
23
24#include "contact_preprocessing.hpp" // ManifoldC, CpExec/CpMem
25#include "dem_portable.hpp"
26
27namespace peclet::dem {
28
31inline void freezeAsleepKokkos(int numReal, Kokkos::View<const unsigned char*, CpMem> asleep,
32 Kokkos::View<const float* [3], CpMem> pos,
33 Kokkos::View<const float* [4], CpMem> quat,
34 Kokkos::View<float* [3], CpMem> posPred,
35 Kokkos::View<float* [4], CpMem> quatPred,
36 Kokkos::View<float* [3], CpMem> velPred,
37 Kokkos::View<float* [3], CpMem> angVelPred) {
38 CpExec space;
39 Kokkos::parallel_for(
40 "peclet::dem::freeze_asleep", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
41 KOKKOS_LAMBDA(int i) {
42 if (!asleep(i))
43 return;
44 for (int c = 0; c < 3; ++c) {
45 posPred(i, c) = pos(i, c);
46 velPred(i, c) = 0.0f;
47 angVelPred(i, c) = 0.0f;
48 }
49 for (int c = 0; c < 4; ++c)
50 quatPred(i, c) = quat(i, c);
51 });
52 space.fence();
53}
54
58inline void buildInvMassEffKokkos(int numBodies, Kokkos::View<const unsigned char*, CpMem> asleep,
59 Kokkos::View<const int*, CpMem> realIdx,
60 Kokkos::View<const float*, CpMem> invMass,
61 Kokkos::View<float*, CpMem> invMassEff, float sleeperFrac) {
62 CpExec space;
63 Kokkos::parallel_for(
64 "peclet::dem::inv_mass_eff", Kokkos::RangePolicy<CpExec>(space, 0, numBodies),
65 KOKKOS_LAMBDA(int i) {
66 invMassEff(i) = asleep(realIdx(i)) ? sleeperFrac * invMass(i) : invMass(i);
67 });
68 space.fence();
69}
70
74inline void computeManifoldSleepKokkos(Kokkos::View<const ManifoldC*, CpMem> manifolds,
75 int numManifolds, Kokkos::View<const int*, CpMem> realIdx,
76 Kokkos::View<const unsigned char*, CpMem> asleep,
77 Kokkos::View<unsigned char*, CpMem> manifoldSleep) {
78 CpExec space;
79 Kokkos::parallel_for(
80 "peclet::dem::manifold_sleep", Kokkos::RangePolicy<CpExec>(space, 0, numManifolds),
81 KOKKOS_LAMBDA(int idx) {
82 const ManifoldC m = manifolds(idx);
83 unsigned char s = 0;
84 if (m.num_points > 0) {
85 const bool aA = asleep(realIdx(m.bodyA)) != 0;
86 const bool aB = (m.bodyB < 0) ? true : (asleep(realIdx(m.bodyB)) != 0);
87 s = (aA && aB) ? 1 : 0;
88 }
89 manifoldSleep(idx) = s;
90 });
91 space.fence();
92}
93
95inline void computeContactSleepKokkos(Kokkos::View<const ContactC*, CpMem> contacts,
96 int numContacts, Kokkos::View<const int*, CpMem> realIdx,
97 Kokkos::View<const unsigned char*, CpMem> asleep,
98 Kokkos::View<unsigned char*, CpMem> contactSleep) {
99 CpExec space;
100 Kokkos::parallel_for(
101 "peclet::dem::contact_sleep", Kokkos::RangePolicy<CpExec>(space, 0, numContacts),
102 KOKKOS_LAMBDA(int idx) {
103 const ContactC c = contacts(idx);
104 const bool aA = asleep(realIdx(c.bodyA)) != 0;
105 const bool aB = (c.bodyB < 0) ? true : (asleep(realIdx(c.bodyB)) != 0);
106 contactSleep(idx) = (aA && aB) ? 1 : 0;
107 });
108 space.fence();
109}
110
117inline void wakeDisturbedKokkos(Kokkos::View<const ManifoldC*, CpMem> manifolds, int numManifolds,
118 Kokkos::View<const int*, CpMem> realIdx,
119 Kokkos::View<const float* [3], CpMem> velPred, float wakeSpeed,
120 Kokkos::View<unsigned char*, CpMem> asleep,
121 Kokkos::View<unsigned char*, CpMem> sleepCounter,
122 Kokkos::View<unsigned char*, CpMem> movingWall,
123 Kokkos::View<int*, CpMem> curCount, int numReal) {
124 CpExec space;
125 Kokkos::parallel_for(
126 "peclet::dem::wake_reset", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
127 KOKKOS_LAMBDA(int i) {
128 movingWall(i) = 0;
129 curCount(i) = 0;
130 });
131 const float wakeSpeed2 = wakeSpeed * wakeSpeed;
132 Kokkos::parallel_for(
133 "peclet::dem::wake_disturbed", Kokkos::RangePolicy<CpExec>(space, 0, numManifolds),
134 KOKKOS_LAMBDA(int idx) {
135 const ManifoldC m = manifolds(idx);
136 if (m.num_points <= 0)
137 return;
138 const int ra = realIdx(m.bodyA);
139 Kokkos::atomic_add(&curCount(ra), 1);
140 int rb = -1;
141 if (m.bodyB >= 0) {
142 rb = realIdx(m.bodyB);
143 if (rb == ra)
144 return; // periodic self-pair
145 Kokkos::atomic_add(&curCount(rb), 1);
146 }
147 // Moving wall (boundary manifold with nonzero wall velocity): never sleeps.
148 if (m.bodyB < 0) {
149 const F4 wv = m.wallVel_sum;
150 if (wv.x != 0.0f || wv.y != 0.0f || wv.z != 0.0f) {
151 movingWall(ra) = 1;
152 if (asleep(ra)) {
153 asleep(ra) = 0;
154 sleepCounter(ra) = 0;
155 }
156 }
157 return;
158 }
159 const bool sA = asleep(ra) != 0, sB = asleep(rb) != 0;
160 if (sA == sB)
161 return; // both awake or both asleep: no cross-wake here
162 // Exactly one asleep: wake it if the awake side moves faster than wakeSpeed.
163 const int awake = sA ? rb : ra, sleeper = sA ? ra : rb;
164 const float vx = velPred(awake, 0), vy = velPred(awake, 1), vz = velPred(awake, 2);
165 if (vx * vx + vy * vy + vz * vz > wakeSpeed2) {
166 asleep(sleeper) = 0;
167 sleepCounter(sleeper) = 0;
168 }
169 });
170 space.fence();
171}
172
176inline void wakeContactChangeKokkos(int numReal, Kokkos::View<const int*, CpMem> curCount,
177 Kokkos::View<int*, CpMem> prevCount,
178 Kokkos::View<const unsigned char*, CpMem> movingWall,
179 Kokkos::View<unsigned char*, CpMem> asleep,
180 Kokkos::View<unsigned char*, CpMem> sleepCounter,
181 bool wakeOnChange) {
182 CpExec space;
183 Kokkos::parallel_for(
184 "peclet::dem::wake_contact_change", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
185 KOKKOS_LAMBDA(int i) {
186 // Rule (b): a change in the live contact count. In a near-threshold settled bed contacts
187 // FLICKER in and out every substep, so waking on any change stops the bed ever freezing;
188 // waking only on a LOST contact (support removed), and only when enabled, is the robust
189 // form. A gained contact is extra support and never a reason to wake.
190 if (wakeOnChange && asleep(i) && curCount(i) < prevCount(i)) {
191 asleep(i) = 0;
192 sleepCounter(i) = 0;
193 }
194 if (movingWall(i))
195 sleepCounter(i) = 0;
196 prevCount(i) = curCount(i);
197 });
198 space.fence();
199}
200
205inline void updateSleepKokkos(int numReal, Kokkos::View<const float* [3], CpMem> vel,
206 Kokkos::View<const float* [3], CpMem> angVel,
207 Kokkos::View<const float*, CpMem> rad,
208 Kokkos::View<const unsigned char*, CpMem> grounded,
209 Kokkos::View<const unsigned char*, CpMem> movingWall,
210 Kokkos::View<unsigned char*, CpMem> asleep,
211 Kokkos::View<unsigned char*, CpMem> sleepCounter, float sleepSpeed,
212 int K, Kokkos::View<float* [3], CpMem> velOut,
213 Kokkos::View<float* [3], CpMem> angVelOut) {
214 CpExec space;
215 const float s2 = sleepSpeed * sleepSpeed;
216 Kokkos::parallel_for(
217 "peclet::dem::update_sleep", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
218 KOKKOS_LAMBDA(int i) {
219 if (asleep(i))
220 return; // stays asleep until an explicit wake
221 const float vx = vel(i, 0), vy = vel(i, 1), vz = vel(i, 2);
222 const float wx = angVel(i, 0), wy = angVel(i, 1), wz = angVel(i, 2);
223 const float r = rad(i);
224 const bool lowLin = (vx * vx + vy * vy + vz * vz) < s2;
225 const bool lowAng = (wx * wx + wy * wy + wz * wz) * r * r < s2;
226 if (lowLin && lowAng && grounded(i) > 0 && !movingWall(i)) {
227 int c = static_cast<int>(sleepCounter(i)) + 1;
228 if (c >= K) {
229 asleep(i) = 1;
230 for (int k = 0; k < 3; ++k) {
231 velOut(i, k) = 0.0f;
232 angVelOut(i, k) = 0.0f;
233 }
234 c = K; // saturate the counter
235 }
236 sleepCounter(i) = static_cast<unsigned char>(c > 255 ? 255 : c);
237 } else {
238 sleepCounter(i) = 0;
239 }
240 });
241 space.fence();
242}
243
244} // namespace peclet::dem
245
246#endif // DEM_SLEEPING_HPP
dem — portable (Kokkos) contact->manifold reduction, replacing the thrust-based reduce_contacts_to_ma...
dem — portable POD types + math + analytic SDFs shared by the Kokkos kernel ports.
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.
Definition sleeping.hpp:95
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...
Definition sleeping.hpp:205
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 —...
Definition sleeping.hpp:31
CpExec::memory_space CpMem
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...
Definition sleeping.hpp:58
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.
Definition sleeping.hpp:117
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).
Definition sleeping.hpp:74
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...
Definition sleeping.hpp:176
Kokkos::DefaultExecutionSpace CpExec
Portable mirror of ParticleSystem.cuh ContactConstraint (the fields this reduction touches).
Portable mirror of ManifoldConstraint.