PhysicsBasedAnimationToolkit 0.0.10
Cross-platform C++20 library of algorithms and data structures commonly used in computer graphics research on physically-based simulation.
Loading...
Searching...
No Matches
Kernels.h
1#ifndef PBAT_SIM_VBD_KERNELS_H
2#define PBAT_SIM_VBD_KERNELS_H
3
4#include "Enums.h"
5#include "pbat/HostDevice.h"
13
14#include <cmath>
15#include <limits>
16
17namespace pbat {
18namespace sim {
19namespace vbd {
20namespace kernels {
21
22namespace mini = math::linalg::mini;
23
24template <
25 mini::CMatrix TMatrixXT,
26 mini::CMatrix TMatrixVT,
27 mini::CMatrix TMatrixA,
28 class ScalarType = typename TMatrixXT::ScalarType>
29PBAT_HOST_DEVICE mini::SVector<ScalarType, TMatrixXT::kRows> InertialTarget(
30 TMatrixXT const& xt,
31 TMatrixVT const& vt,
32 TMatrixA const& aext,
33 ScalarType dt,
34 ScalarType dt2)
35{
36 return xt + dt * vt + dt2 * aext;
37}
38
39template <
40 mini::CMatrix TMatrixXT,
41 mini::CMatrix TMatrixVTM1,
42 mini::CMatrix TMatrixVT,
43 mini::CMatrix TMatrixA,
44 class ScalarType = typename TMatrixXT::ScalarType>
45PBAT_HOST_DEVICE mini::SVector<ScalarType, TMatrixXT::kRows> InitialPositionsForSolve(
46 TMatrixXT const& xt,
47 TMatrixVTM1 const& vtm1,
48 TMatrixVT const& vt,
49 TMatrixA const& aext,
50 ScalarType dt,
51 ScalarType dt2,
53{
54 using namespace mini;
55 if (strategy == EInitializationStrategy::Position)
56 {
57 return xt;
58 }
59 else if (strategy == EInitializationStrategy::Inertia)
60 {
61 return xt + dt * vt;
62 }
63 else if (strategy == EInitializationStrategy::KineticEnergyMinimum)
64 {
65 return xt + dt * vt + dt2 * aext;
66 }
67 else // (strategy == EInitializationStrategy::AdaptiveVbd)
68 {
69 ScalarType const aextn2 = SquaredNorm(aext);
70 bool const bHasZeroExternalAcceleration = (aextn2 == ScalarType(0));
71 ScalarType atilde{0};
72 if (not bHasZeroExternalAcceleration)
73 {
74 using namespace std;
75 auto constexpr kRows = TMatrixXT::kRows;
76 if (strategy == EInitializationStrategy::AdaptiveVbd)
77 {
78 SVector<ScalarType, kRows> const ati = (vt - vtm1) / dt;
79 atilde = Dot(ati, aext) / aextn2;
80 atilde = min(max(atilde, ScalarType(0)), ScalarType(1));
81 }
82 if (strategy == EInitializationStrategy::AdaptivePbat)
83 {
84 SVector<ScalarType, kRows> const dti =
85 vt / (Norm(vt) + std::numeric_limits<ScalarType>::min());
86 atilde = Dot(dti, aext) / aextn2;
87 // Discard the sign of atilde, because motion that goes against
88 // gravity should "feel" gravity, rather than ignore it (i.e. clamping).
89 atilde = min(abs(atilde), ScalarType(1));
90 }
91 }
92 return xt + dt * vt + dt2 * atilde * aext;
93 }
94}
95
96template <class ScalarType, class IndexType>
97PBAT_HOST [[maybe_unused]] ScalarType ChebyshevOmega(IndexType k, ScalarType rho2, ScalarType omega)
98{
99 return (k == IndexType(0)) ? ScalarType{1} :
100 (k == IndexType(1)) ? ScalarType{2} / (ScalarType{2} - rho2) :
101 ScalarType{4} / ScalarType{4} - rho2 * omega;
102}
103
104template <
105 mini::CMatrix TMatrixXKM2,
106 mini::CMatrix TMatrixXKM1,
107 mini::CMatrix TMatrixXK,
108 class IndexType,
109 class ScalarType = typename TMatrixXK::ScalarType>
110PBAT_HOST_DEVICE [[maybe_unused]] void
111ChebyshevUpdate(IndexType k, ScalarType omega, TMatrixXKM2& xkm2, TMatrixXKM1& xkm1, TMatrixXK& xk)
112{
113 if (k > 1)
114 {
115 xk = omega * (xk - xkm2) + xkm2;
116 }
117 xkm2 = xkm1;
118 xkm1 = xk;
119}
120
121template <
122 mini::CMatrix TMatrixXT,
123 mini::CMatrix TMatrixX,
124 class ScalarType = typename TMatrixXT::ScalarType>
125PBAT_HOST_DEVICE mini::SVector<ScalarType, TMatrixXT::kRows>
126IntegrateVelocity(TMatrixXT const& xt, TMatrixX const& x, ScalarType dt)
127{
128 return (x - xt) / dt;
129}
130
131template <
132 mini::CMatrix TMatrixGP,
133 mini::CMatrix TMatrixHF,
134 mini::CMatrix TMatrixHI,
135 class IndexType,
136 class ScalarType = typename TMatrixGP::ScalarType>
137PBAT_HOST_DEVICE void AccumulateElasticHessian(
138 IndexType ilocal,
139 ScalarType wg,
140 TMatrixGP const& GP,
141 TMatrixHF const& HF,
142 TMatrixHI& Hi)
143{
144 auto constexpr kDims = TMatrixGP::kCols;
145 // Contract (d^k Psi / dF^k) with (d F / dx)^k. See pbat/fem/DeformationGradient.h.
146 common::ForRange<0, kDims>([&]<auto kj>() {
147 common::ForRange<0, kDims>([&]<auto ki>() {
148 Hi += wg * GP(ilocal, ki) * GP(ilocal, kj) *
149 HF.template Slice<kDims, kDims>(ki * kDims, kj * kDims);
150 });
151 });
152}
153
154template <
155 mini::CMatrix TMatrixGP,
156 mini::CMatrix TMatrixGF,
157 mini::CMatrix TMatrixGI,
158 class IndexType,
159 class ScalarType = typename TMatrixGP::ScalarType>
160PBAT_HOST_DEVICE void AccumulateElasticGradient(
161 IndexType ilocal,
162 ScalarType wg,
163 TMatrixGP const& GP,
164 TMatrixGF const& gF,
165 TMatrixGI& gi)
166{
167 auto constexpr kDims = TMatrixGP::kCols;
168 // Contract (d^k Psi / dF^k) with (d F / dx)^k. See pbat/fem/DeformationGradient.h.
170 [&]<auto k>() { gi += wg * GP(ilocal, k) * gF.template Slice<kDims, 1>(k * kDims, 0); });
171}
172
173template <
174 mini::CMatrix TMatrixXT,
175 mini::CMatrix TMatrixX,
176 mini::CMatrix TMatrixG,
177 mini::CMatrix TMatrixH,
178 class ScalarType = typename TMatrixXT::ScalarType>
179PBAT_HOST_DEVICE void AddDamping(
180 ScalarType dt,
181 TMatrixXT const& xt,
182 TMatrixX const& x,
183 ScalarType kD,
184 TMatrixG& g,
185 TMatrixH& H)
186{
187 // Add Rayleigh damping terms
188 ScalarType const D = kD / dt;
189 g += D * (H * (x - xt));
190 H *= ScalarType{1} + D;
191}
192
215template <
216 mini::CMatrix TMatrixXTV,
217 mini::CMatrix TMatrixXV,
218 mini::CMatrix TMatrixXTF,
219 mini::CMatrix TMatrixXF,
220 mini::CMatrix TMatrixG,
221 mini::CMatrix TMatrixH,
222 class ScalarType = typename TMatrixXV::ScalarType>
223PBAT_HOST_DEVICE ScalarType AccumulateVertexTriangleContact(
224 TMatrixXTV const& xtv,
225 TMatrixXV const& xv,
226 TMatrixXTF const& xtf,
227 TMatrixXF const& xf,
228 ScalarType dt,
229 ScalarType muC,
230 ScalarType muF,
231 ScalarType epsv,
232 TMatrixG* g = nullptr,
233 TMatrixH* H = nullptr)
234{
235 using namespace mini;
236 ScalarType E{0};
237
238 // Compute triangle normal
239 SMatrix<ScalarType, 3, 2> T{};
240 T.Col(0) = xf.Col(1) - xf.Col(0);
241 T.Col(1) = xf.Col(2) - xf.Col(0);
242 SVector<ScalarType, 3> n = Cross(T.Col(0), T.Col(1));
243 ScalarType const doublearea = Norm(n);
244 bool const bIsTriangleDegenerate = doublearea <= ScalarType(1e-8);
245 if (bIsTriangleDegenerate)
246 return E;
247
248 n /= doublearea;
249 using namespace pbat::geometry;
250 SVector<ScalarType, 3> xc = ClosestPointQueries::PointOnPlane(xv, xf.Col(0), n);
251 // Check if xv projects to the triangle's interior by checking its barycentric coordinates
252 SVector<ScalarType, 3> b =
253 IntersectionQueries::TriangleBarycentricCoordinates(xc - xf.Col(0), T.Col(0), T.Col(1));
254 // If xv doesn't project inside triangle, then we don't generate a contact response
255 // clang-format off
256 bool const bIsVertexInsideTriangle = All(b >= ScalarType(0) and b <= ScalarType(1));
257 // clang-format on
258 if (not bIsVertexInsideTriangle)
259 return E;
260
261 // Collision energy is \f$ \frac{1}{2} \mu_C [(x_v - x_b)^T n]^2 \f$
262 SVector<ScalarType, 3> xb = xf * b;
263 ScalarType d = min(ScalarType(0), Dot(xv - xb, n));
264 ScalarType lambda = muC * d;
265 E += ScalarType(0.5) * lambda * d;
266 // Gradient is \f$ \mu_C [(x_v - x_b)^T n] I_{d \times d} n \f$
267 if (g)
268 (*g) += lambda * n;
269 // Hessian is \f$ \mu_C n n^T \f$
270 if (H)
271 (*H) += muC * (n * n.Transpose());
272
273 // IPC smooth friction energy
274 T.Col(1) = Cross(n, T.Col(0));
275 auto xtb = xtf * b;
276 auto dx = (xv - xtv) - (xb - xtb);
277 SVector<ScalarType, 2> u = T.Transpose() * dx;
278 ScalarType unorm = Norm(u) + std::numeric_limits<ScalarType>::epsilon();
279 ScalarType epsvh = epsv * dt;
280 ScalarType muFlambda = muF * abs(lambda);
281 ScalarType uepsvh = unorm / epsvh;
282 ScalarType f1 = (uepsvh < 1) ? 2 * uepsvh - (uepsvh * uepsvh) : ScalarType(1);
283 // Gradient is \f$ \mu_F \lambda_N T f1(|u|) \frac{u}{|u|}} \f$
284 ScalarType muFlambdaf1unorm = muFlambda * f1 / unorm;
285 if (g)
286 (*g) += muFlambdaf1unorm * T * u;
287 if (H)
288 (*H) += muFlambdaf1unorm * T * T.Transpose();
289 // Energy is \f$ \mu_F \lambda_N f_0(|u|) \f$, where
290 // \f$ f_0(y) = f_1'(y) \f$ and \f$ f_0(\eps_\nu h) = \eps_\nu h \f$
291 // This yields \f$ f_0(y) = 1/3 \eps_\nu h + \frac{y^2}{\eps_\nu h} - \frac{y^3}{3 \eps_\nu^2
292 // h^2} \f$
293 ScalarType unorm2 = unorm * unorm;
294 // clang-format off
295 ScalarType f0 =
296 (ScalarType(1) / ScalarType(3) * epsvh) +
297 (unorm2 / epsvh) -
298 (unorm2 * unorm / (ScalarType(3) * epsvh * epsvh));
299 // clang-format on
300 E += muFlambda * f0;
301 return E;
302}
303
304template <
305 mini::CMatrix TMatrixXTL,
306 mini::CMatrix TMatrixX,
307 mini::CMatrix TMatrixG,
308 mini::CMatrix TMatrixH,
309 class ScalarType = typename TMatrixXTL::ScalarType>
310PBAT_HOST_DEVICE void AddInertiaDerivatives(
311 ScalarType dt2,
312 ScalarType m,
313 TMatrixXTL const& xtilde,
314 TMatrixX const& x,
315 TMatrixG& g,
316 TMatrixH& H)
317{
318 // Add inertial energy derivatives
319 ScalarType const K = m / dt2;
320 Diag(H) += K;
321 g += K * (x - xtilde);
322}
323
324template <
325 mini::CMatrix TMatrixX,
326 mini::CMatrix TMatrixG,
327 mini::CMatrix TMatrixH,
328 class ScalarType = typename TMatrixX::ScalarType>
329PBAT_HOST_DEVICE void IntegratePositions(
330 TMatrixG const& g,
331 TMatrixH const& H,
332 TMatrixX& x,
333 ScalarType detHZero = ScalarType(1e-7))
334{
335 // 3. Newton step
336 if (abs(Determinant(H)) <= detHZero) // Skip nearly rank-deficient hessian
337 return;
338 x -= (Inverse(H) * g);
339}
340
341} // namespace kernels
342} // namespace vbd
343} // namespace sim
344} // namespace pbat
345
346#endif // PBAT_SIM_VBD_KERNELS_H
This file contains functions to answer closest point queries.
Compile-time for loops.
Functions to compute deformation gradient and its derivatives.
This file contains functions to answer intersection queries.
This file includes all the mini linear algebra headers.
Tetrahedron finite element.
constexpr void ForRange(F &&f)
Compile-time for loop over a range of values.
Definition ConstexprFor.h:55
Mini linear algebra related functionality.
Definition Assign.h:12
PBAT's Vertex Block Descent (VBD) anka2024vbd API.
Definition AndersonIntegrator.cpp:10
EInitializationStrategy
Initialization strategies for the VBD time step minimization.
Definition Enums.h:9
PBAT simulation algorithms.
The main namespace of the library.
Definition Aliases.h:15