9#ifndef DEM_INTEGRATION_HPP
10#define DEM_INTEGRATION_HPP
12#include <Kokkos_Core.hpp>
24using V3 = Kokkos::View<float* [3], CpMem>;
25using V4 = Kokkos::View<float* [4], CpMem>;
26using Vf = Kokkos::View<float*, CpMem>;
27using Vi = Kokkos::View<int*, CpMem>;
30KOKKOS_INLINE_FUNCTION
void st3(
const V3& v,
int i,
F3 a) {
35KOKKOS_INLINE_FUNCTION
void st4(
const V4& v,
int i,
F4 a) {
45 V3 invInertia,
V3 posPred,
V4 quatPred,
V3 velPred,
V3 angVelPred,
46 V3 deltaPos,
V4 deltaQuat,
V3 deltaVel,
V3 deltaAngVel,
47 Vi constraintCounts,
F3 gravity,
float dt,
V3 extForce,
51 "peclet::dem::predict_velocity", Kokkos::RangePolicy<CpExec>(space, 0, n),
52 KOKKOS_LAMBDA(
int i) {
53 const float invM = invMass(i);
63 F3 wpred =
ldF3(angVel, i);
65 const F3 invI =
ldF3(invInertia, i);
66 if (invI.
x > 0.0f || invI.
y > 0.0f || invI.
z > 0.0f) {
67 const F4 q =
ldF4(quat, i);
69 const F3 Ib{(invI.
x > 1e-9f) ? 1.0f / invI.
x : 0.0f,
70 (invI.
y > 1e-9f) ? 1.0f / invI.
y : 0.0f,
71 (invI.
z > 1e-9f) ? 1.0f / invI.
z : 0.0f};
72 const F3 Lb{Ib.
x * wb.
x, Ib.y * wb.
y, Ib.z * wb.
z};
79 const F3 alpha{invI.
x * (tb.
x - wxL.
x), invI.
y * (tb.
y - wxL.
y),
80 invI.
z * (tb.
z - wxL.
z)};
97 constraintCounts(i) = 0;
107 Kokkos::parallel_for(
108 "peclet::dem::apply_velocity_deltas", Kokkos::RangePolicy<CpExec>(space, 0, n),
109 KOKKOS_LAMBDA(
int i) {
120 V3 velPred,
V3 angVelPred,
V3 posPred,
121 V4 quatPred,
V3 angVel,
float dt) {
123 Kokkos::parallel_for(
124 "peclet::dem::apply_vel_predict_pos", Kokkos::RangePolicy<CpExec>(space, 0, n),
125 KOKKOS_LAMBDA(
int i) {
126 const F3 vStart =
ldF3(vel, i);
127 const F3 vFinal =
ldF3(velPred, i);
131 const float invM = invMass(i);
137 const F4 q =
ldF4(quat, i);
138 const F3 omega =
ldF3(angVelPred, i);
142 qp.
x += 0.5f * dt * (omega.
x * q.
w + omega.
y * q.
z - omega.
z * q.
y);
143 qp.
y += 0.5f * dt * (omega.
y * q.
w + omega.
z * q.
x - omega.
x * q.
z);
144 qp.
z += 0.5f * dt * (omega.
z * q.
w + omega.
x * q.
y - omega.
y * q.
x);
145 qp.
w += 0.5f * dt * (-omega.
x * q.
x - omega.
y * q.
y - omega.
z * q.
z);
146 const float len = Kokkos::sqrt(qp.
x * qp.
x + qp.
y * qp.
y + qp.
z * qp.
z + qp.
w * qp.
w);
148 const float s = 1.0f / len;
149 qp =
F4{qp.
x * s, qp.
y * s, qp.
z * s, qp.
w * s};
159 int numContacts,
Vi constraintCounts) {
161 Kokkos::parallel_for(
162 "peclet::dem::contact_counts", Kokkos::RangePolicy<CpExec>(space, 0, numContacts),
163 KOKKOS_LAMBDA(
int i) {
167 Kokkos::atomic_add(&constraintCounts(c.
bodyA), 1);
169 Kokkos::atomic_add(&constraintCounts(c.
bodyB), 1);
179 Vi constraintCounts,
bool averaged =
true) {
181 Kokkos::parallel_for(
182 "peclet::dem::apply_updates", Kokkos::RangePolicy<CpExec>(space, 0, n), KOKKOS_LAMBDA(
int i) {
183 const int count = constraintCounts(i);
186 const float f = averaged ? 1.0f /
static_cast<float>(count) : 1.0f;
191 constraintCounts(i) = 0;
200 Kokkos::parallel_for(
201 "peclet::dem::final_commit", Kokkos::RangePolicy<CpExec>(space, 0, n), KOKKOS_LAMBDA(
int i) {
206 else if (p.
x >= dom.
max.
x)
212 else if (p.
y >= dom.
max.
y)
218 else if (p.
z >= dom.
max.
z)
232 double t = 0.0,
r = 0.0;
240 V4 quat,
double kB,
double tau,
double Ttarget,
float dt) {
243 Kokkos::parallel_reduce(
244 "peclet::dem::thermo_energy", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
245 KOKKOS_LAMBDA(
int i,
KE2& acc) {
246 const float invM = invMass(i);
247 const F3 v =
ldF3(vel, i);
249 acc.
t += 0.5 * (1.0 / invM) * (v.
x * v.
x + v.
y * v.
y + v.
z * v.
z);
250 const F3 invI =
ldF3(invInertia, i);
251 if (invI.
x > 0.0f || invI.
y > 0.0f || invI.
z > 0.0f) {
253 const double Ix = (invI.
x > 0.0f) ? 1.0 / invI.
x : 0.0;
254 const double Iy = (invI.
y > 0.0f) ? 1.0 / invI.
y : 0.0;
255 const double Iz = (invI.
z > 0.0f) ? 1.0 / invI.
z : 0.0;
256 acc.
r += 0.5 * (Ix * wb.
x * wb.
x + Iy * wb.
y * wb.
y + Iz * wb.
z * wb.
z);
261 const double ndof = 3.0 * numReal;
262 auto lambda = [&](
double ke) {
263 if (ndof <= 0 || kB <= 0)
265 const double Tcur = (2.0 * ke) / (ndof * kB);
268 double f = 1.0 + (dt / tau) * (Ttarget / Tcur - 1.0);
271 return static_cast<float>(Kokkos::sqrt(f));
273 const float lt = lambda(sum.
t), lr = lambda(sum.
r);
275 Kokkos::parallel_for(
276 "peclet::dem::thermo_scale", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
277 KOKKOS_LAMBDA(
int i) {
286 if (!(factor > 0.0f))
289 Kokkos::parallel_for(
290 "peclet::dem::growth", Kokkos::RangePolicy<CpExec>(space, 0, n),
291 KOKKOS_LAMBDA(
int i) { scale(i) = targetScale(i) * factor; });
dem — portable POD types + math + analytic SDFs shared by the Kokkos kernel ports.
void st3(const V3 &v, int i, F3 a)
void st4(const V4 &v, int i, F4 a)
Kokkos::View< float *, CpMem > Vf
Kokkos::View< int *, CpMem > Vi
Kokkos::View< float *[3], CpMem > V3
void applyVelocityDeltasKokkos(int n, V3 velPred, V3 angVelPred, V3 deltaVel, V3 deltaAngVel)
Add accumulated velocity/angular deltas onto the predicted velocity, then clear the delta buffers.
F3 invRotateVector(F4 q, F3 v)
F3 ldF3(const V &v, int i)
F3 rotateVector(F4 q, F3 v)
void applyVelocityAndPredictPositionKokkos(int n, V3 pos, Vf invMass, V3 vel, V4 quat, V3 velPred, V3 angVelPred, V3 posPred, V4 quatPred, V3 angVel, float dt)
Re-integration: persist solved velocity, trapezoidal position predict, quaternion integrate.
F4 ldF4(const V &v, int i)
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.
Kokkos::View< float *[4], CpMem > V4
void updateGrowthScalesKokkos(int n, Vf scale, Vf targetScale, float factor)
Growth mode: scale = target * factor (when active).
void applyUpdatesKokkos(int n, V3 posPred, V3 velPred, V3 deltaPos, V3 deltaVel, Vi constraintCounts, bool averaged=true)
Jacobi count-averaged apply of position/velocity deltas, then clear deltas + counts.
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, V3 extTorque)
Predict velocity (gravity + gyroscopic precession), speculative position, and clear all deltas.
void computeContactCountsKokkos(Kokkos::View< const ContactC *, CpMem > contacts, int numContacts, Vi constraintCounts)
Per-contact constraint-count pre-pass (active contacts, dist <= 0).
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
Berendsen thermostat: reduce translational + rotational KE over real particles, compute the two scali...
KE2 & operator+=(const KE2 &o)