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) {
50 "peclet::dem::predict_velocity", Kokkos::RangePolicy<CpExec>(space, 0, n),
51 KOKKOS_LAMBDA(
int i) {
52 const float invM = invMass(i);
62 F3 wpred =
ldF3(angVel, i);
64 const F3 invI =
ldF3(invInertia, i);
65 if (invI.
x > 0.0f || invI.
y > 0.0f || invI.
z > 0.0f) {
66 const F4 q =
ldF4(quat, i);
68 const F3 Ib{(invI.
x > 1e-9f) ? 1.0f / invI.
x : 0.0f,
69 (invI.
y > 1e-9f) ? 1.0f / invI.
y : 0.0f,
70 (invI.
z > 1e-9f) ? 1.0f / invI.
z : 0.0f};
71 const F3 Lb{Ib.
x * wb.
x, Ib.y * wb.
y, Ib.z * wb.
z};
73 const F3 alpha{-invI.
x * wxL.
x, -invI.
y * wxL.
y, -invI.
z * wxL.
z};
90 constraintCounts(i) = 0;
100 Kokkos::parallel_for(
101 "peclet::dem::apply_velocity_deltas", Kokkos::RangePolicy<CpExec>(space, 0, n),
102 KOKKOS_LAMBDA(
int i) {
113 V3 velPred,
V3 angVelPred,
V3 posPred,
114 V4 quatPred,
V3 angVel,
float dt) {
116 Kokkos::parallel_for(
117 "peclet::dem::apply_vel_predict_pos", Kokkos::RangePolicy<CpExec>(space, 0, n),
118 KOKKOS_LAMBDA(
int i) {
119 const F3 vStart =
ldF3(vel, i);
120 const F3 vFinal =
ldF3(velPred, i);
124 const float invM = invMass(i);
130 const F4 q =
ldF4(quat, i);
131 const F3 omega =
ldF3(angVelPred, i);
135 qp.
x += 0.5f * dt * (omega.
x * q.
w + omega.
y * q.
z - omega.
z * q.
y);
136 qp.
y += 0.5f * dt * (omega.
y * q.
w + omega.
z * q.
x - omega.
x * q.
z);
137 qp.
z += 0.5f * dt * (omega.
z * q.
w + omega.
x * q.
y - omega.
y * q.
x);
138 qp.
w += 0.5f * dt * (-omega.
x * q.
x - omega.
y * q.
y - omega.
z * q.
z);
139 const float len = Kokkos::sqrt(qp.
x * qp.
x + qp.
y * qp.
y + qp.
z * qp.
z + qp.
w * qp.
w);
141 const float s = 1.0f / len;
142 qp =
F4{qp.
x * s, qp.
y * s, qp.
z * s, qp.
w * s};
152 int numContacts,
Vi constraintCounts) {
154 Kokkos::parallel_for(
155 "peclet::dem::contact_counts", Kokkos::RangePolicy<CpExec>(space, 0, numContacts),
156 KOKKOS_LAMBDA(
int i) {
160 Kokkos::atomic_add(&constraintCounts(c.
bodyA), 1);
162 Kokkos::atomic_add(&constraintCounts(c.
bodyB), 1);
169 Vi constraintCounts) {
171 Kokkos::parallel_for(
172 "peclet::dem::apply_updates", Kokkos::RangePolicy<CpExec>(space, 0, n), KOKKOS_LAMBDA(
int i) {
173 const int count = constraintCounts(i);
176 const float f = 1.0f /
static_cast<float>(count);
181 constraintCounts(i) = 0;
190 Kokkos::parallel_for(
191 "peclet::dem::final_commit", Kokkos::RangePolicy<CpExec>(space, 0, n), KOKKOS_LAMBDA(
int i) {
196 else if (p.
x >= dom.
max.
x)
202 else if (p.
y >= dom.
max.
y)
208 else if (p.
z >= dom.
max.
z)
222 double t = 0.0,
r = 0.0;
230 V4 quat,
double kB,
double tau,
double Ttarget,
float dt) {
233 Kokkos::parallel_reduce(
234 "peclet::dem::thermo_energy", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
235 KOKKOS_LAMBDA(
int i,
KE2& acc) {
236 const float invM = invMass(i);
237 const F3 v =
ldF3(vel, i);
239 acc.
t += 0.5 * (1.0 / invM) * (v.
x * v.
x + v.
y * v.
y + v.
z * v.
z);
240 const F3 invI =
ldF3(invInertia, i);
241 if (invI.
x > 0.0f || invI.
y > 0.0f || invI.
z > 0.0f) {
243 const double Ix = (invI.
x > 0.0f) ? 1.0 / invI.
x : 0.0;
244 const double Iy = (invI.
y > 0.0f) ? 1.0 / invI.
y : 0.0;
245 const double Iz = (invI.
z > 0.0f) ? 1.0 / invI.
z : 0.0;
246 acc.
r += 0.5 * (Ix * wb.
x * wb.
x + Iy * wb.
y * wb.
y + Iz * wb.
z * wb.
z);
251 const double ndof = 3.0 * numReal;
252 auto lambda = [&](
double ke) {
253 if (ndof <= 0 || kB <= 0)
255 const double Tcur = (2.0 * ke) / (ndof * kB);
258 double f = 1.0 + (dt / tau) * (Ttarget / Tcur - 1.0);
261 return static_cast<float>(Kokkos::sqrt(f));
263 const float lt = lambda(sum.
t), lr = lambda(sum.
r);
265 Kokkos::parallel_for(
266 "peclet::dem::thermo_scale", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
267 KOKKOS_LAMBDA(
int i) {
276 if (!(factor > 0.0f))
279 Kokkos::parallel_for(
280 "peclet::dem::growth", Kokkos::RangePolicy<CpExec>(space, 0, n),
281 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)
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.
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 applyUpdatesKokkos(int n, V3 posPred, V3 velPred, V3 deltaPos, V3 deltaVel, Vi constraintCounts)
Jacobi count-averaged apply of position/velocity deltas, then clear deltas + counts.
void updateGrowthScalesKokkos(int n, Vf scale, Vf targetScale, float factor)
Growth mode: scale = target * factor (when active).
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)