107 Kokkos::View<
const int* [2],
CpMem> pairs,
int numPairs,
108 Kokkos::View<
const float* [3],
CpMem> pos, Kokkos::View<
const float* [3],
CpMem> vel,
109 Kokkos::View<
const float* [3],
CpMem> angVel, Kokkos::View<const float*, CpMem> rad,
111 float eGlobal,
float muGlobal, Kokkos::View<const float*, CpMem> hertzE,
112 Kokkos::View<const float*, CpMem> hertzNu,
float dt, Kokkos::View<
float* [3],
CpMem> xi,
113 Kokkos::View<
float* [3],
CpMem> force, Kokkos::View<
float* [3],
CpMem> torque,
114 Kokkos::View<const float*, CpMem> scale = {},
ScalarI shapeId = {},
115 Kokkos::View<const ShapeDesc*, CpMem> shapes = {},
float globalScale = 1.0f) {
117 Kokkos::parallel_for(
118 "peclet::dem::hertz_pairs", Kokkos::RangePolicy<CpExec>(space, 0, numPairs),
119 KOKKOS_LAMBDA(
int idx) {
120 const int i = pairs(idx, 0), j = pairs(idx, 1);
122 const F3 dx =
sub3(pi, pj);
123 const float d = Kokkos::sqrt(
dot3(dx, dx));
126 const float delta = ri + rj - d;
127 if (delta <= 0.0f || d < 1e-12f) {
128 xi(idx, 0) = xi(idx, 1) = xi(idx, 2) = 0.0f;
131 const F3 nhat =
scale3(dx, 1.0f / d);
132 const F3 rA =
scale3(nhat, -(ri - 0.5f * delta));
133 const F3 rB =
scale3(nhat, (rj - 0.5f * delta));
136 const int ma = matId(i), mb = matId(j);
138 hertzPairEMu(ma, mb, pairTable, eGlobal, muGlobal, e, mu);
139 const float Ei = hertzE(ma), Ej = hertzE(mb);
140 const float ni = hertzNu(ma), nj = hertzNu(mb);
141 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nj * nj) / Ej);
143 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei + 2.0f * (2.0f - nj) * (1.0f + nj) / Ej);
144 const float rStar = ri * rj / (ri + rj);
145 const float imSum = invMass(i) + invMass(j);
146 const float mStar = (imSum > 0.0f) ? 1.0f / imSum : 0.0f;
147 F3 x{xi(idx, 0), xi(idx, 1), xi(idx, 2)};
148 const F3 f =
hertzForce(delta, nhat, vrel, rStar, mStar, eStar, gStar, e, mu, dt, x);
153 for (
int c = 0; c < 3; ++c) {
154 Kokkos::atomic_add(&force(i, c), (&f.x)[c]);
155 Kokkos::atomic_add(&force(j, c), -(&f.x)[c]);
156 Kokkos::atomic_add(&torque(i, c), (&tA.x)[c]);
157 Kokkos::atomic_add(&torque(j, c), (&tB.x)[c]);
166 Kokkos::View<const int*, CpMem> candSlots,
int numCand,
167 Kokkos::View<const WallSdf*, CpMem> walls,
GridView wallGrid,
168 Kokkos::View<
const float* [3],
CpMem> pos, Kokkos::View<
const float* [3],
CpMem> vel,
169 Kokkos::View<
const float* [3],
CpMem> angVel, Kokkos::View<const float*, CpMem> rad,
171 float eGlobal,
float muGlobal, Kokkos::View<const float*, CpMem> hertzE,
172 Kokkos::View<const float*, CpMem> hertzNu,
float dt, Kokkos::View<
float* [3],
CpMem> xiWall,
173 int maxWalls, Kokkos::View<
float* [3],
CpMem> force, Kokkos::View<
float* [3],
CpMem> torque,
174 Kokkos::View<
const float* [4],
CpMem> quat = {}, Kokkos::View<const float*, CpMem> scale = {},
175 ScalarI shapeId = {}, Kokkos::View<const ShapeDesc*, CpMem> shapes = {},
ShellView shell = {},
176 float globalScale = 1.0f,
float contactRadiusFrac = 0.5f,
bool hasShapes =
false,
177 Kokkos::View<float*, CpMem> snWall = {}) {
179 Kokkos::parallel_for(
180 "peclet::dem::hertz_walls", Kokkos::RangePolicy<CpExec>(space, 0, numCand),
181 KOKKOS_LAMBDA(
int ci) {
182 const int enc = candSlots(ci);
183 const int i = enc / 8;
184 const int wi = enc % 8;
185 const F3 p =
loadF3(pos, i);
187 const WallSdf w = walls(wi);
188 const int slot = i * maxWalls + wi;
189 const int ma = matId(i);
190 if (hasShapes && shapes(shapeId(i)).numPoints > 0) {
193 const ShapeDesc dS = shapes(shapeId(i));
194 const F4 qP = F4{quat(i, 0), quat(i, 1), quat(i, 2), quat(i, 3)};
195 const float effScale = scale(i) * globalScale;
196 const float rc = contactRadiusFrac * dS.params.x * effScale;
198 if (w.materialId >= 0 && pairTable.extent(0) > 0)
199 hertzPairEMu(ma, w.materialId, pairTable, eGlobal, muGlobal, e, mu);
204 const int mw = (w.materialId >= 0) ? w.materialId : ma;
205 const float Ei = hertzE(ma), Ew = hertzE(mw);
206 const float ni = hertzNu(ma), nw = hertzNu(mw);
207 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nw * nw) / Ew);
208 const float gStar = 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei +
209 2.0f * (2.0f - nw) * (1.0f + nw) / Ew);
210 const float mStar = (invMass(i) > 0.0f) ? 1.0f / invMass(i) : 0.0f;
213 const float snTotPrev = (snWall.extent(0) > 0) ? snWall(slot) : 0.0f;
214 const float dampC = (mStar > 0.0f) ? -2.0f * 0.9128709f * bd * Kokkos::sqrt(mStar) : 0.0f;
215 float fnSum = 0.0f, snSum = 0.0f, dMax = 0.0f;
216 F3 cSum{0, 0, 0}, nSum{0, 0, 0}, fAcc{0, 0, 0}, tAcc{0, 0, 0};
217 for (
int k = 0; k < dS.numPoints; ++k) {
218 const int sIdx = dS.shellOffset + k;
221 qP,
scale3(F3{shell(sIdx, 0), shell(sIdx, 1), shell(sIdx, 2)}, effScale)));
225 const float delta = -sd;
226 const float hx = 0.5f / w.grid.invSpacing.x;
227 F3 g{(
sampleWallSdf(F3{pW.x + hx, pW.y, pW.z}, w, wallGrid) -
233 const float gl =
len3(g);
236 const F3 nhat =
scale3(g, 1.0f / gl);
237 const F3 rA =
sub3(pW, p);
238 const F3 vWall =
add3(w.linVel,
cross3v(w.angVel,
sub3(pW, w.center)));
240 const float vnP =
dot3(vrelP, nhat);
241 const float sq = Kokkos::sqrt(rc * delta);
242 const float fnSpring = (4.0f / 3.0f) * eStar * sq * delta;
243 const float snI = 2.0f * eStar * sq;
244 const float snTot = (snTotPrev > snI) ? snTotPrev : snI;
245 const float etaI = dampC * snI / Kokkos::sqrt(snTot);
246 const F3 f =
scale3(nhat, fnSpring - etaI * vnP);
247 fAcc =
add3(fAcc, f);
250 snSum += 2.0f * eStar * sq;
257 xiWall(slot, 0) = xiWall(slot, 1) = xiWall(slot, 2) = 0.0f;
258 if (snWall.extent(0) > 0)
262 const F3 cpt =
scale3(cSum, 1.0f / fnSum);
264 const float nl =
len3(nhat);
266 nhat =
scale3(nhat, 1.0f / nl);
267 const F3 rA =
sub3(cpt, p);
268 const F3 vWall =
add3(w.linVel,
cross3v(w.angVel,
sub3(cpt, w.center)));
270 if (snWall.extent(0) > 0)
271 snWall(slot) = snSum;
273 const float st = 8.0f * gStar * Kokkos::sqrt(rc * dMax);
274 const float etaT = -2.0f * 0.9128709f * bd * Kokkos::sqrt(st * mStar);
275 F3 x{xiWall(slot, 0), xiWall(slot, 1), xiWall(slot, 2)};
279 const float ftLen =
len3(ft);
280 const float ftMax = mu * fnSum;
282 const float sc2 = (ftLen > 1e-20f) ? ftMax / ftLen : 0.0f;
287 xiWall(slot, 0) = x.x;
288 xiWall(slot, 1) = x.y;
289 xiWall(slot, 2) = x.z;
290 fAcc =
add3(fAcc, ft);
292 for (
int c = 0; c < 3; ++c) {
293 Kokkos::atomic_add(&force(i, c), (&fAcc.x)[c]);
294 Kokkos::atomic_add(&torque(i, c), (&tAcc.x)[c]);
300 const float delta = r - s;
302 xiWall(slot, 0) = xiWall(slot, 1) = xiWall(slot, 2) = 0.0f;
305 const float hx = 0.5f / w.grid.invSpacing.x;
312 const float gl = Kokkos::sqrt(
dot3(g, g));
315 const F3 nhat =
scale3(g, 1.0f / gl);
316 const F3 rA =
scale3(nhat, -(r - 0.5f * delta));
317 const F3 cpt =
add3(p, rA);
318 const F3 vWall =
add3(w.linVel,
cross3v(w.angVel,
sub3(cpt, w.center)));
321 if (w.materialId >= 0 && pairTable.extent(0) > 0) {
322 hertzPairEMu(ma, w.materialId, pairTable, eGlobal, muGlobal, e, mu);
327 const int mw = (w.materialId >= 0) ? w.materialId : ma;
328 const float Ei = hertzE(ma), Ew = hertzE(mw);
329 const float ni = hertzNu(ma), nw = hertzNu(mw);
330 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nw * nw) / Ew);
331 const float gStar = 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei +
332 2.0f * (2.0f - nw) * (1.0f + nw) / Ew);
333 const float mStar = (invMass(i) > 0.0f) ? 1.0f / invMass(i) : 0.0f;
334 F3 x{xiWall(slot, 0), xiWall(slot, 1), xiWall(slot, 2)};
335 const F3 f =
hertzForce(delta, nhat, vrel, r, mStar, eStar, gStar, e, mu, dt, x);
336 xiWall(slot, 0) = x.x;
337 xiWall(slot, 1) = x.y;
338 xiWall(slot, 2) = x.z;
340 for (
int c = 0; c < 3; ++c) {
341 Kokkos::atomic_add(&force(i, c), (&f.x)[c]);
342 Kokkos::atomic_add(&torque(i, c), (&tA.x)[c]);
381 int numReal, Kokkos::View<
float* [3],
CpMem> force, Kokkos::View<
float* [3],
CpMem> torque,
382 Kokkos::View<const float*, CpMem> invMass, Kokkos::View<
const float* [3],
CpMem> invInertia,
383 F3 gravity,
float dt, Kokkos::View<
float* [3],
CpMem> vel,
384 Kokkos::View<
float* [3],
CpMem> angVel, Kokkos::View<
float* [3],
CpMem> pos,
385 Kokkos::View<
float* [4],
CpMem> quat = {},
bool integrateOrientation =
false) {
387 Kokkos::parallel_for(
388 "peclet::dem::hertz_integrate", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
389 KOKKOS_LAMBDA(
int i) {
390 const float im = invMass(i);
392 const F3 iI{invInertia(i, 0), invInertia(i, 1), invInertia(i, 2)};
394 if (iI.x == iI.y && iI.y == iI.z) {
395 dw = F3{torque(i, 0) * iI.x, torque(i, 1) * iI.x, torque(i, 2) * iI.x};
397 const F4 q =
loadF4(quat, i);
398 const F3 tl =
invRotateVector(q, F3{torque(i, 0), torque(i, 1), torque(i, 2)});
399 dw =
rotateVector(q, F3{tl.x * iI.x, tl.y * iI.y, tl.z * iI.z});
401 for (
int c = 0; c < 3; ++c) {
402 vel(i, c) += (force(i, c) * im + (&gravity.
x)[c]) * dt;
403 angVel(i, c) += (&dw.x)[c] * dt;
404 pos(i, c) += vel(i, c) * dt;
406 if (integrateOrientation) {
408 const F3 w{angVel(i, 0), angVel(i, 1), angVel(i, 2)};
410 F4 dq{0.5f * dt * (w.x * q.w + w.y * q.z - w.z * q.y),
411 0.5f * dt * (w.y * q.w + w.z * q.x - w.x * q.z),
412 0.5f * dt * (w.z * q.w + w.x * q.y - w.y * q.x),
413 0.5f * dt * (-w.x * q.x - w.y * q.y - w.z * q.z)};
414 q = F4{q.x + dq.x, q.y + dq.y, q.z + dq.z, q.w + dq.w};
415 const float qn = Kokkos::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
417 quat(i, 0) = q.x / qn;
418 quat(i, 1) = q.y / qn;
419 quat(i, 2) = q.z / qn;
420 quat(i, 3) = q.w / qn;
424 force(i, 0) = force(i, 1) = force(i, 2) = 0.0f;
425 torque(i, 0) = torque(i, 1) = torque(i, 2) = 0.0f;
457 Kokkos::View<
const int* [2],
CpMem> pairs,
int numPairs,
458 Kokkos::View<
const float* [3],
CpMem> pos, Kokkos::View<
const float* [4],
CpMem> quat,
459 Kokkos::View<
const float* [3],
CpMem> vel, Kokkos::View<
const float* [3],
CpMem> angVel,
460 Kokkos::View<const float*, CpMem> scale,
ScalarI shapeId,
462 float globalScale,
float contactRadiusFrac, Kokkos::View<const float*, CpMem> invMass,
464 Kokkos::View<const float*, CpMem> hertzE, Kokkos::View<const float*, CpMem> hertzNu,
float dt,
465 Kokkos::View<
float* [3],
CpMem> xi, Kokkos::View<float*, CpMem> snPrev,
466 Kokkos::View<
float* [3],
CpMem> force, Kokkos::View<
float* [3],
CpMem> torque) {
468 Kokkos::parallel_for(
469 "peclet::dem::hertz_shape_pairs", Kokkos::RangePolicy<CpExec>(space, 0, numPairs),
470 KOKKOS_LAMBDA(
int idx) {
471 const int idA = pairs(idx, 0), idB = pairs(idx, 1);
472 const ShapeDesc dA = shapes(shapeId(idA));
473 const ShapeDesc dB = shapes(shapeId(idB));
476 const float effScaleA = scale(idA) * globalScale, effScaleB = scale(idB) * globalScale;
479 const int iter = (countA > 0) ? countA : 1;
481 const int ma = matId(idA), mb = matId(idB);
483 hertzPairEMu(ma, mb, pairTable, eGlobal, muGlobal, e, mu);
484 const float Ei = hertzE(ma), Ej = hertzE(mb);
485 const float ni = hertzNu(ma), nj = hertzNu(mb);
486 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nj * nj) / Ej);
488 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei + 2.0f * (2.0f - nj) * (1.0f + nj) / Ej);
491 const float rcA = (sphereA ? 1.0f : contactRadiusFrac) * dA.
params.
x * effScaleA;
494 const float rStar = rcA * rcB / (rcA + rcB);
495 const float imSum = invMass(idA) + invMass(idB);
496 const float mStar = (imSum > 0.0f) ? 1.0f / imSum : 0.0f;
502 float fnSum = 0.0f, snSum = 0.0f;
503 F3 cSum{0, 0, 0}, nSum{0, 0, 0};
505 F3 fAcc{0, 0, 0}, tAccA{0, 0, 0}, tAccB{0, 0, 0};
510 const float snTotPrev = snPrev(idx);
511 const float dampC = (mStar > 0.0f) ? -2.0f * 0.9128709f * bd * Kokkos::sqrt(mStar) : 0.0f;
513 for (
int k = 0; k < iter; ++k) {
515 float pointRadius = 0.0f;
518 pLocalA =
F3{shell(sIdx, 0), shell(sIdx, 1), shell(sIdx, 2)};
519 }
else if (sphereA) {
520 pointRadius = dA.
params.
x * effScaleA;
524 const float dist =
sdfEvalShape(pCanB, dB, sdfGrid) * effScaleB;
525 const float effDist = dist - pointRadius;
528 const float delta = -effDist;
530 const float len =
len3(nLoc);
531 nLoc = (len > 1e-9f) ?
scale3(nLoc, 1.0f / len) :
F3{0, 1, 0};
533 const F3 pSurfA =
sub3(pWorld,
scale3(nW, pointRadius));
534 const F3 rA =
sub3(pSurfA, posA);
538 const float vnP =
dot3(vrelP, nW);
539 const float sq = Kokkos::sqrt(rStar * delta);
540 const float fnSpring = (4.0f / 3.0f) * eStar * sq * delta;
541 const float snI = 2.0f * eStar * sq;
542 const float snTot = (snTotPrev > snI) ? snTotPrev : snI;
543 const float etaI = dampC * snI / Kokkos::sqrt(snTot);
544 const F3 f =
scale3(nW, fnSpring - etaI * vnP);
545 fAcc =
add3(fAcc, f);
549 snSum += 2.0f * eStar * sq;
557 xi(idx, 0) = xi(idx, 1) = xi(idx, 2) = 0.0f;
563 const F3 cpt =
scale3(cSum, 1.0f / fnSum);
565 const float nl =
len3(nhat);
567 nhat =
scale3(nhat, 1.0f / nl);
568 const F3 rA =
sub3(cpt, posA), rB =
sub3(cpt, posB);
572 const float st = 8.0f * gStar * Kokkos::sqrt(rStar * dMax);
573 const float etaT = -2.0f * 0.9128709f * bd * Kokkos::sqrt(st * mStar);
574 F3 x{xi(idx, 0), xi(idx, 1), xi(idx, 2)};
578 const float ftLen =
len3(ft);
579 const float ftMax = mu * fnSum;
581 const float sc = (ftLen > 1e-20f) ? ftMax / ftLen : 0.0f;
589 fAcc =
add3(fAcc, ft);
593 for (
int c = 0; c < 3; ++c) {
594 Kokkos::atomic_add(&force(idA, c), (&fAcc.x)[c]);
595 Kokkos::atomic_add(&force(idB, c), -(&fAcc.x)[c]);
596 Kokkos::atomic_add(&torque(idA, c), (&tAccA.x)[c]);
597 Kokkos::atomic_add(&torque(idB, c), (&tAccB.x)[c]);
void hertzWallForcesKokkos(Kokkos::View< const int *, CpMem > candSlots, int numCand, Kokkos::View< const WallSdf *, CpMem > walls, GridView wallGrid, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > rad, Kokkos::View< const float *, CpMem > invMass, MatIdView matId, PairTableView pairTable, float eGlobal, float muGlobal, Kokkos::View< const float *, CpMem > hertzE, Kokkos::View< const float *, CpMem > hertzNu, float dt, Kokkos::View< float *[3], CpMem > xiWall, int maxWalls, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque, Kokkos::View< const float *[4], CpMem > quat={}, Kokkos::View< const float *, CpMem > scale={}, ScalarI shapeId={}, Kokkos::View< const ShapeDesc *, CpMem > shapes={}, ShellView shell={}, float globalScale=1.0f, float contactRadiusFrac=0.5f, bool hasShapes=false, Kokkos::View< float *, CpMem > snWall={})
SDF-wall forces (per particle x wall).
void hertzPairForcesKokkos(Kokkos::View< const int *[2], CpMem > pairs, int numPairs, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > rad, Kokkos::View< const float *, CpMem > invMass, MatIdView matId, PairTableView pairTable, float eGlobal, float muGlobal, Kokkos::View< const float *, CpMem > hertzE, Kokkos::View< const float *, CpMem > hertzNu, float dt, Kokkos::View< float *[3], CpMem > xi, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque, Kokkos::View< const float *, CpMem > scale={}, ScalarI shapeId={}, Kokkos::View< const ShapeDesc *, CpMem > shapes={}, float globalScale=1.0f)
Cached-pair forces: overlap from current positions; history resets when a cached pair is currently se...
void hertzShapePairForcesKokkos(Kokkos::View< const int *[2], CpMem > pairs, int numPairs, Kokkos::View< const float *[3], CpMem > pos, Kokkos::View< const float *[4], CpMem > quat, Kokkos::View< const float *[3], CpMem > vel, Kokkos::View< const float *[3], CpMem > angVel, Kokkos::View< const float *, CpMem > scale, ScalarI shapeId, Kokkos::View< const ShapeDesc *, CpMem > shapes, ShellView shell, GridView sdfGrid, float globalScale, float contactRadiusFrac, Kokkos::View< const float *, CpMem > invMass, MatIdView matId, PairTableView pairTable, float eGlobal, float muGlobal, Kokkos::View< const float *, CpMem > hertzE, Kokkos::View< const float *, CpMem > hertzNu, float dt, Kokkos::View< float *[3], CpMem > xi, Kokkos::View< float *, CpMem > snPrev, Kokkos::View< float *[3], CpMem > force, Kokkos::View< float *[3], CpMem > torque)
Non-spherical pairs: per-point Hertz springs over A's point shell against B's SDF (the same one-sided...