89 Kokkos::View<
const float* [3],
CpMem> pos,
90 Kokkos::View<
const float* [3],
CpMem> vel,
91 Kokkos::View<
const float* [3],
CpMem> angVel,
92 Kokkos::View<const float*, CpMem> rad,
93 Kokkos::View<const float*, CpMem> invMass,
95 float muGlobal, Kokkos::View<const float*, CpMem> hertzE,
96 Kokkos::View<const float*, CpMem> hertzNu,
float dt,
97 Kokkos::View<
float* [3],
CpMem> xi,
99 Kokkos::View<
float* [3],
CpMem> torque) {
101 Kokkos::parallel_for(
102 "peclet::dem::hertz_pairs", Kokkos::RangePolicy<CpExec>(space, 0, numPairs),
103 KOKKOS_LAMBDA(
int idx) {
104 const int i = pairs(idx, 0), j = pairs(idx, 1);
106 const F3 dx =
sub3(pi, pj);
107 const float d = Kokkos::sqrt(
dot3(dx, dx));
108 const float ri = rad(i), rj = rad(j);
109 const float delta = ri + rj - d;
110 if (delta <= 0.0f || d < 1e-12f) {
111 xi(idx, 0) = xi(idx, 1) = xi(idx, 2) = 0.0f;
114 const F3 nhat =
scale3(dx, 1.0f / d);
115 const F3 rA =
scale3(nhat, -(ri - 0.5f * delta));
116 const F3 rB =
scale3(nhat, (rj - 0.5f * delta));
119 const int ma = matId(i), mb = matId(j);
121 hertzPairEMu(ma, mb, pairTable, eGlobal, muGlobal, e, mu);
122 const float Ei = hertzE(ma), Ej = hertzE(mb);
123 const float ni = hertzNu(ma), nj = hertzNu(mb);
124 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nj * nj) / Ej);
126 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei + 2.0f * (2.0f - nj) * (1.0f + nj) / Ej);
127 const float rStar = ri * rj / (ri + rj);
128 const float imSum = invMass(i) + invMass(j);
129 const float mStar = (imSum > 0.0f) ? 1.0f / imSum : 0.0f;
130 F3 x{xi(idx, 0), xi(idx, 1), xi(idx, 2)};
131 const F3 f =
hertzForce(delta, nhat, vrel, rStar, mStar, eStar, gStar, e, mu, dt, x);
136 for (
int c = 0; c < 3; ++c) {
137 Kokkos::atomic_add(&
force(i, c), (&f.
x)[c]);
138 Kokkos::atomic_add(&
force(j, c), -(&f.
x)[c]);
139 Kokkos::atomic_add(&torque(i, c), (&tA.
x)[c]);
140 Kokkos::atomic_add(&torque(j, c), (&tB.x)[c]);
149 Kokkos::View<const WallSdf*, CpMem> walls,
GridView wallGrid,
150 Kokkos::View<
const float* [3],
CpMem> pos,
151 Kokkos::View<
const float* [3],
CpMem> vel,
152 Kokkos::View<
const float* [3],
CpMem> angVel,
153 Kokkos::View<const float*, CpMem> rad,
154 Kokkos::View<const float*, CpMem> invMass,
156 float muGlobal, Kokkos::View<const float*, CpMem> hertzE,
157 Kokkos::View<const float*, CpMem> hertzNu,
float dt,
158 Kokkos::View<
float* [3],
CpMem> xiWall,
int maxWalls,
160 Kokkos::View<
float* [3],
CpMem> torque,
161 Kokkos::View<
const float* [4],
CpMem> quat = {},
162 Kokkos::View<const float*, CpMem> scale = {},
164 Kokkos::View<const ShapeDesc*, CpMem> shapes = {},
165 ShellView shell = {},
float globalScale = 1.0f,
166 float contactRadiusFrac = 0.5f,
bool hasShapes =
false,
167 Kokkos::View<float*, CpMem> snWall = {}) {
169 Kokkos::parallel_for(
170 "peclet::dem::hertz_walls", Kokkos::RangePolicy<CpExec>(space, 0, numCand),
171 KOKKOS_LAMBDA(
int ci) {
172 const int enc = candSlots(ci);
173 const int i = enc / 8;
174 const int wi = enc % 8;
176 const float r = rad(i);
177 const WallSdf w = walls(wi);
178 const int slot = i * maxWalls + wi;
179 const int ma = matId(i);
180 if (hasShapes && shapes(shapeId(i)).numPoints > 0) {
183 const ShapeDesc dS = shapes(shapeId(i));
184 const F4 qP = F4{quat(i, 0), quat(i, 1), quat(i, 2), quat(i, 3)};
185 const float effScale = scale(i) * globalScale;
186 const float rc = contactRadiusFrac * dS.params.x * effScale;
188 if (w.materialId >= 0 && pairTable.extent(0) > 0)
189 hertzPairEMu(ma, w.materialId, pairTable, eGlobal, muGlobal, e, mu);
194 const int mw = (w.materialId >= 0) ? w.materialId : ma;
195 const float Ei = hertzE(ma), Ew = hertzE(mw);
196 const float ni = hertzNu(ma), nw = hertzNu(mw);
197 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nw * nw) / Ew);
198 const float gStar = 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei +
199 2.0f * (2.0f - nw) * (1.0f + nw) / Ew);
200 const float mStar = (invMass(i) > 0.0f) ? 1.0f / invMass(i) : 0.0f;
203 const float snTotPrev = (snWall.extent(0) > 0) ? snWall(slot) : 0.0f;
205 (mStar > 0.0f) ? -2.0f * 0.9128709f * bd * Kokkos::sqrt(mStar) : 0.0f;
206 float fnSum = 0.0f, snSum = 0.0f, dMax = 0.0f;
207 F3 cSum{0, 0, 0}, nSum{0, 0, 0}, fAcc{0, 0, 0}, tAcc{0, 0, 0};
208 for (
int k = 0; k < dS.numPoints; ++k) {
209 const int sIdx = dS.shellOffset + k;
216 const float delta = -sd;
217 const float hx = 0.5f / w.invSpacing.x;
224 const float gl =
len3(g);
227 const F3 nhat =
scale3(g, 1.0f / gl);
228 const F3 rA =
sub3(pW, p);
231 const float vnP =
dot3(vrelP, nhat);
232 const float sq = Kokkos::sqrt(rc * delta);
233 const float fnSpring = (4.0f / 3.0f) * eStar * sq * delta;
234 const float snI = 2.0f * eStar * sq;
235 const float snTot = (snTotPrev > snI) ? snTotPrev : snI;
236 const float etaI = dampC * snI / Kokkos::sqrt(snTot);
237 const F3 f =
scale3(nhat, fnSpring - etaI * vnP);
238 fAcc =
add3(fAcc, f);
241 snSum += 2.0f * eStar * sq;
248 xiWall(slot, 0) = xiWall(slot, 1) = xiWall(slot, 2) = 0.0f;
249 if (snWall.extent(0) > 0)
253 const F3 cpt =
scale3(cSum, 1.0f / fnSum);
255 const float nl =
len3(nhat);
257 nhat =
scale3(nhat, 1.0f / nl);
258 const F3 rA =
sub3(cpt, p);
261 if (snWall.extent(0) > 0)
262 snWall(slot) = snSum;
264 const float st = 8.0f * gStar * Kokkos::sqrt(rc * dMax);
265 const float etaT = -2.0f * 0.9128709f * bd * Kokkos::sqrt(st * mStar);
266 F3 x{xiWall(slot, 0), xiWall(slot, 1), xiWall(slot, 2)};
270 const float ftLen =
len3(ft);
271 const float ftMax = mu * fnSum;
273 const float sc2 = (ftLen > 1e-20f) ? ftMax / ftLen : 0.0f;
278 xiWall(slot, 0) = x.x;
279 xiWall(slot, 1) = x.y;
280 xiWall(slot, 2) = x.z;
281 fAcc =
add3(fAcc, ft);
283 for (
int c = 0; c < 3; ++c) {
284 Kokkos::atomic_add(&
force(i, c), (&fAcc.x)[c]);
285 Kokkos::atomic_add(&torque(i, c), (&tAcc.x)[c]);
291 const float delta = r - s;
293 xiWall(slot, 0) = xiWall(slot, 1) = xiWall(slot, 2) = 0.0f;
296 const float hx = 0.5f / w.invSpacing.x;
303 const float gl = Kokkos::sqrt(
dot3(g, g));
306 const F3 nhat =
scale3(g, 1.0f / gl);
307 const F3 rA =
scale3(nhat, -(r - 0.5f * delta));
308 const F3 cpt =
add3(p, rA);
312 if (w.materialId >= 0 && pairTable.extent(0) > 0) {
313 hertzPairEMu(ma, w.materialId, pairTable, eGlobal, muGlobal, e, mu);
318 const int mw = (w.materialId >= 0) ? w.materialId : ma;
319 const float Ei = hertzE(ma), Ew = hertzE(mw);
320 const float ni = hertzNu(ma), nw = hertzNu(mw);
321 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nw * nw) / Ew);
322 const float gStar = 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei +
323 2.0f * (2.0f - nw) * (1.0f + nw) / Ew);
324 const float mStar = (invMass(i) > 0.0f) ? 1.0f / invMass(i) : 0.0f;
325 F3 x{xiWall(slot, 0), xiWall(slot, 1), xiWall(slot, 2)};
326 const F3 f =
hertzForce(delta, nhat, vrel, r, mStar, eStar, gStar, e, mu, dt, x);
327 xiWall(slot, 0) = x.x;
328 xiWall(slot, 1) = x.y;
329 xiWall(slot, 2) = x.z;
331 for (
int c = 0; c < 3; ++c) {
332 Kokkos::atomic_add(&
force(i, c), (&f.x)[c]);
333 Kokkos::atomic_add(&torque(i, c), (&tA.x)[c]);
375 Kokkos::View<
float* [3],
CpMem> torque,
376 Kokkos::View<const float*, CpMem> invMass,
377 Kokkos::View<
const float* [3],
CpMem> invInertia,
F3 gravity,
378 float dt, Kokkos::View<
float* [3],
CpMem> vel,
379 Kokkos::View<
float* [3],
CpMem> angVel,
380 Kokkos::View<
float* [3],
CpMem> pos,
381 Kokkos::View<
float* [4],
CpMem> quat = {},
382 bool integrateOrientation =
false) {
384 Kokkos::parallel_for(
385 "peclet::dem::hertz_integrate", Kokkos::RangePolicy<CpExec>(space, 0, numReal),
386 KOKKOS_LAMBDA(
int i) {
387 const float im = invMass(i);
389 const F3 iI{invInertia(i, 0), invInertia(i, 1), invInertia(i, 2)};
391 if (iI.x == iI.y && iI.y == iI.z) {
392 dw =
F3{torque(i, 0) * iI.x, torque(i, 1) * iI.x, torque(i, 2) * iI.x};
394 const F4 q =
loadF4(quat, i);
398 for (
int c = 0; c < 3; ++c) {
399 vel(i, c) += (
force(i, c) * im + (&gravity.
x)[c]) * dt;
400 angVel(i, c) += (&dw.x)[c] * dt;
401 pos(i, c) += vel(i, c) * dt;
403 if (integrateOrientation) {
405 const F3 w{angVel(i, 0), angVel(i, 1), angVel(i, 2)};
407 F4 dq{0.5f * dt * (w.x * q.w + w.y * q.z - w.z * q.y),
408 0.5f * dt * (w.y * q.w + w.z * q.x - w.x * q.z),
409 0.5f * dt * (w.z * q.w + w.x * q.y - w.y * q.x),
410 0.5f * dt * (-w.x * q.x - w.y * q.y - w.z * q.z)};
411 q = F4{q.x + dq.x, q.y + dq.y, q.z + dq.z, q.w + dq.w};
412 const float qn = Kokkos::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
414 quat(i, 0) = q.x / qn;
415 quat(i, 1) = q.y / qn;
416 quat(i, 2) = q.z / qn;
417 quat(i, 3) = q.w / qn;
422 torque(i, 0) = torque(i, 1) = torque(i, 2) = 0.0f;
455 Kokkos::View<
const int* [2],
CpMem> pairs,
int numPairs,
456 Kokkos::View<
const float* [3],
CpMem> pos, Kokkos::View<
const float* [4],
CpMem> quat,
457 Kokkos::View<
const float* [3],
CpMem> vel, Kokkos::View<
const float* [3],
CpMem> angVel,
458 Kokkos::View<const float*, CpMem> scale,
ScalarI shapeId,
460 float globalScale,
float contactRadiusFrac, Kokkos::View<const float*, CpMem> invMass,
462 Kokkos::View<const float*, CpMem> hertzE, Kokkos::View<const float*, CpMem> hertzNu,
float dt,
463 Kokkos::View<
float* [3],
CpMem> xi, Kokkos::View<float*, CpMem> snPrev,
464 Kokkos::View<
float* [3],
CpMem>
force, Kokkos::View<
float* [3],
CpMem> torque) {
466 Kokkos::parallel_for(
467 "peclet::dem::hertz_shape_pairs", Kokkos::RangePolicy<CpExec>(space, 0, numPairs),
468 KOKKOS_LAMBDA(
int idx) {
469 const int idA = pairs(idx, 0), idB = pairs(idx, 1);
470 const ShapeDesc dA = shapes(shapeId(idA));
471 const ShapeDesc dB = shapes(shapeId(idB));
474 const float effScaleA = scale(idA) * globalScale, effScaleB = scale(idB) * globalScale;
477 const int iter = (countA > 0) ? countA : 1;
479 const int ma = matId(idA), mb = matId(idB);
481 hertzPairEMu(ma, mb, pairTable, eGlobal, muGlobal, e, mu);
482 const float Ei = hertzE(ma), Ej = hertzE(mb);
483 const float ni = hertzNu(ma), nj = hertzNu(mb);
484 const float eStar = 1.0f / ((1.0f - ni * ni) / Ei + (1.0f - nj * nj) / Ej);
486 1.0f / (2.0f * (2.0f - ni) * (1.0f + ni) / Ei + 2.0f * (2.0f - nj) * (1.0f + nj) / Ej);
489 const float rcA = (sphereA ? 1.0f : contactRadiusFrac) * dA.
params.
x * effScaleA;
492 const float rStar = rcA * rcB / (rcA + rcB);
493 const float imSum = invMass(idA) + invMass(idB);
494 const float mStar = (imSum > 0.0f) ? 1.0f / imSum : 0.0f;
500 float fnSum = 0.0f, snSum = 0.0f;
501 F3 cSum{0, 0, 0}, nSum{0, 0, 0};
503 F3 fAcc{0, 0, 0}, tAccA{0, 0, 0}, tAccB{0, 0, 0};
508 const float snTotPrev = snPrev(idx);
510 (mStar > 0.0f) ? -2.0f * 0.9128709f * bd * Kokkos::sqrt(mStar) : 0.0f;
512 for (
int k = 0; k < iter; ++k) {
514 float pointRadius = 0.0f;
517 pLocalA =
F3{shell(sIdx, 0), shell(sIdx, 1), shell(sIdx, 2)};
518 }
else if (sphereA) {
519 pointRadius = dA.
params.
x * effScaleA;
523 const float dist =
sdfEvalShape(pCanB, dB, sdfGrid) * effScaleB;
524 const float effDist = dist - pointRadius;
527 const float delta = -effDist;
528 const float eps = 1e-4f;
535 const float len =
len3(nLoc);
536 nLoc = (len > 1e-9f) ?
scale3(nLoc, 1.0f / len) :
F3{0, 1, 0};
538 const F3 pSurfA =
sub3(pWorld,
scale3(nW, pointRadius));
539 const F3 rA =
sub3(pSurfA, posA);
543 const float vnP =
dot3(vrelP, nW);
544 const float sq = Kokkos::sqrt(rStar * delta);
545 const float fnSpring = (4.0f / 3.0f) * eStar * sq * delta;
546 const float snI = 2.0f * eStar * sq;
547 const float snTot = (snTotPrev > snI) ? snTotPrev : snI;
548 const float etaI = dampC * snI / Kokkos::sqrt(snTot);
549 const F3 f =
scale3(nW, fnSpring - etaI * vnP);
550 fAcc =
add3(fAcc, f);
554 snSum += 2.0f * eStar * sq;
562 xi(idx, 0) = xi(idx, 1) = xi(idx, 2) = 0.0f;
568 const F3 cpt =
scale3(cSum, 1.0f / fnSum);
570 const float nl =
len3(nhat);
572 nhat =
scale3(nhat, 1.0f / nl);
573 const F3 rA =
sub3(cpt, posA), rB =
sub3(cpt, posB);
577 const float st = 8.0f * gStar * Kokkos::sqrt(rStar * dMax);
578 const float etaT = -2.0f * 0.9128709f * bd * Kokkos::sqrt(st * mStar);
579 F3 x{xi(idx, 0), xi(idx, 1), xi(idx, 2)};
583 const float ftLen =
len3(ft);
584 const float ftMax = mu * fnSum;
586 const float sc = (ftLen > 1e-20f) ? ftMax / ftLen : 0.0f;
594 fAcc =
add3(fAcc, ft);
598 for (
int c = 0; c < 3; ++c) {
599 Kokkos::atomic_add(&
force(idA, c), (&fAcc.x)[c]);
600 Kokkos::atomic_add(&
force(idB, c), -(&fAcc.x)[c]);
601 Kokkos::atomic_add(&torque(idA, c), (&tAccA.x)[c]);
602 Kokkos::atomic_add(&torque(idB, c), (&tAccB.x)[c]);
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)
Cached-pair forces: overlap from current positions; history resets when a cached pair is currently se...
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 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...