UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
GaussSeidelCorotatedCodimensionalConstraints.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
5#include "ChaosStats.h"
10#include "Chaos/Vector.h"
11
12
13namespace Chaos::Softs
14{
15 template <typename T, typename ParticleType>
17 {
18
19 public:
21 const ParticleType& InParticles,
23 const bool bRecordMetricIn = true,
24 const T& EMesh = (T)10.0,
25 const T& NuMesh = (T).3
26 )
28 {
29 Measure.Init((T)0., MeshConstraints.Num());
30 Lambda = EMesh * NuMesh / (((T)1. + NuMesh) * ((T)1. - (T)2. * NuMesh));
31 Mu = EMesh / ((T)2. * ((T)1. + NuMesh));
32
35
37 }
38
40 const ParticleType& InParticles,
42 const TArray<T>& EMeshArray,
43 const T& NuMesh = (T).3
44 )
46 {
47 ensureMsgf(EMeshArray.Num() == InMesh.Num(), TEXT("Input Young Modulus Array Size is wrong"));
48 Measure.Init((T)0., MeshConstraints.Num());
49
53
54 for (int32 e = 0; e < InMesh.Num(); e++)
55 {
56 LambdaElementArray[e] = EMeshArray[e] * NuMesh / (((T)1. + NuMesh) * ((T)1. - (T)2. * NuMesh));
57 MuElementArray[e] = EMeshArray[e] / ((T)2. * ((T)1. + NuMesh));
58 }
59 }
60
62
63 PMatrix<T, 3, 3> DsInit(const int32 E, const ParticleType& InParticles)
64 {
65 PMatrix<T, 3, 3> Result((T)0.);
66 for (int32 i = 0; i < 3; i++)
67 {
68 for (int32 c = 0; c < 3; c++)
69 {
70 Result.SetAt(c, i, InParticles.X(MeshConstraints[E][i + 1])[c] - InParticles.X(MeshConstraints[E][0])[c]);
71 }
72 }
73 return Result;
74 }
75
76 PMatrix<T, 3, 2> Ds(const int32 E, const ParticleType& InParticles) const
77 {
78 if (INDEX_NONE < E && E< MeshConstraints.Num()
82 {
85
86 return PMatrix<T, 3, 2>(
87 P1P0[0], P1P0[1], P1P0[2],
88 P2P0[0], P2P0[1], P2P0[2]);
89 }
90 else
91 {
92 return PMatrix<T, 3, 2>(
93 (T)0., (T)0, (T)0,
94 (T)0, (T)0, (T)0);
95 }
96
97 }
98
99 PMatrix<T, 3, 2> F(const int32 E, const ParticleType& InParticles) const
100 {
101 if (INDEX_NONE < E && E < DmInverse.Num())
102 {
103 return Ds(E, InParticles) * DmInverse[E];
104 }
105 else
106 {
107 return PMatrix<T, 3, 2>(
108 (T)0., (T)0, (T)0,
109 (T)0, (T)0, (T)0);
110 }
111 }
112
114 {
116 Constraints.SetNum(MeshConstraints.Num());
117 for (int32 i = 0; i < MeshConstraints.Num(); i++)
118 {
119 Constraints[i].SetNum(3);
120 for (int32 j = 0; j < 3; j++)
121 {
122 Constraints[i][j] = MeshConstraints[i][j];
123 }
124 }
125 return Constraints;
126 }
127
128 void ComputeNodalMass(const T InDensity, const int32 NumParticles, TArray<T>& NodalMass) const
129 {
130 NodalMass.Init((T)0., NumParticles);
131 for (int32 e = 0; e < Measure.Num(); e++)
132 {
133 const T TotalMass = InDensity * Measure[e];
134 for (int32 j = 0; j < 3; j++)
135 {
136 NodalMass[MeshConstraints[e][j]] += TotalMass / (T)3.;
137 }
138 }
139 }
140
141
142
143 protected:
144
145 void InitializeCodimensionData(const ParticleType& Particles)
146 {
147 Measure.Init((T)0., MeshConstraints.Num());
148 DmInverse.Init(PMatrix<FSolverReal, 2, 2>(0.f, 0.f, 0.f), MeshConstraints.Num());
149 for (int32 e = 0; e < MeshConstraints.Num(); e++)
150 {
151 check(MeshConstraints[e][0] < (int32)Particles.Size() && MeshConstraints[e][0] > INDEX_NONE);
152 check(MeshConstraints[e][1] < (int32)Particles.Size() && MeshConstraints[e][1] > INDEX_NONE);
153 check(MeshConstraints[e][2] < (int32)Particles.Size() && MeshConstraints[e][2] > INDEX_NONE);
154 if (MeshConstraints[e][0] < (int32)Particles.Size() && MeshConstraints[e][0] > INDEX_NONE
155 && MeshConstraints[e][1] < (int32)Particles.Size() && MeshConstraints[e][1] > INDEX_NONE
156 && MeshConstraints[e][2] < (int32)Particles.Size() && MeshConstraints[e][2] > INDEX_NONE)
157 {
158 const TVec3<T> X1X0 = Particles.GetX(MeshConstraints[e][1]) - Particles.GetX(MeshConstraints[e][0]);
159 const TVec3<T> X2X0 = Particles.GetX(MeshConstraints[e][2]) - Particles.GetX(MeshConstraints[e][0]);
160 PMatrix<T, 2, 2> Dm((T)0., (T)0., (T)0.);
161 Dm.M[0] = X1X0.Size();
162 Dm.M[2] = X1X0.Dot(X2X0) / Dm.M[0];
163 Dm.M[3] = Chaos::TVector<T, 3>::CrossProduct(X1X0, X2X0).Size() / Dm.M[0];
165 ensureMsgf(Measure[e] > (T)0., TEXT("Degenerate triangle detected"));
166
167 PMatrix<T, 2, 2> DmInv = Dm.Inverse();
168 DmInverse[e] = DmInv;
169 }
170 }
171 }
172
173 static T SafeRecip(const T Len, const T Fallback)
174 {
175 if (Len > (T)UE_SMALL_NUMBER)
176 {
177 return (T)1. / Len;
178 }
179 return Fallback;
180 }
181
182 static inline void SymSchur2D(const T Aqq, const T App, const T Apq, T& c, T& s)
183 {
184 // A is an n x n matrix
185 // (p, q) is an index pair satisfying 1 <= p < q <= n
186 //
187 // This function computes a (c, s) pair such that
188 //
189 // B = [ c, s]^T [a_pp, a_pq] [ c, s]
190 // [-s, c] [a_pq, a_qq] [-s, c]
191 //
192 // is diagonal
193
194 if (Apq != 0)
195 {
196 T Tau = T(0.5) * (Aqq - App) / Apq;
197 T t;
198 if (Tau >= 0)
199 t = T(1) / (Tau + FMath::Sqrt((T)1. + Tau * Tau));
200 else
201 t = T(-1) / (-Tau + FMath::Sqrt((T)1. + Tau * Tau));
202 c = T(1) / FMath::Sqrt((T)1. + t * t);
203 s = t * c;
204 }
205 else
206 {
207 c = (T)1.;
208 s = (T)0.;
209 }
210 }
211
212
214 {
215 T c, s;
216 SymSchur2D(B.M[3], B.M[0], B.M[1], c, s);
217
218 V.M[0] = c;
219 V.M[1] = -s;
220 V.M[2] = s;
221 V.M[3] = c;
222
223 D = V.GetTransposed() * B * V;
224 }
225
227 {
228 PMatrix<T, 2, 2> FTF = ComputeFTF(Fe), D((T)0., (T)0., (T)0.), U((T)0., (T)0., (T)0.);
229 Jacobi(FTF, D, U);
230 PMatrix<T, 2, 2> SDiag(FMath::Sqrt(D.M[0]), (T)0., (T)0., FMath::Sqrt(D.M[3]));
231 PMatrix<T, 2, 2> S = U * SDiag * U.GetTransposed(), SInv = S.Inverse();;
232 return Fe * S.Inverse();
233 }
234
236 {
237 TVec3<T> Col1(InputMatrix.M[0], InputMatrix.M[1], InputMatrix.M[2]), Col2(InputMatrix.M[3], InputMatrix.M[4], InputMatrix.M[5]), a(T(0)), b(T(0));
238 if (FMath::Abs(Col1[0]) < (T)UE_SMALL_NUMBER && FMath::Abs(Col1[1]) < (T)UE_SMALL_NUMBER)
239 {
240 a[0] = T(1);
241 }
242 else
243 {
244 a[0] = -Col1[1];
245 a[1] = Col1[0];
246 const T OneOveraNorm = SafeRecip(a.Length(), 0.f);
247 a *= OneOveraNorm;
248 }
250 const T OneOverbNorm = SafeRecip(b.Length(), 0.f);
251 b *= OneOverbNorm;
252 return Chaos::PMatrix<T, 3, 2>(b[0], b[1], b[2], a[0], a[1], a[2]);
253 }
254
255 //Does Gram Schmidt on a 3*2 matrix and returns an orthogonal one
268
270 {
271 return PMatrix<T, 2, 2>(InputMatrix.M[0] * InputMatrix.M[0] + InputMatrix.M[1] * InputMatrix.M[1] + InputMatrix.M[2] * InputMatrix.M[2],
272 InputMatrix.M[0] * InputMatrix.M[3] + InputMatrix.M[1] * InputMatrix.M[4] + InputMatrix.M[2] * InputMatrix.M[5],
273 InputMatrix.M[3] * InputMatrix.M[3] + InputMatrix.M[4] * InputMatrix.M[4] + InputMatrix.M[5] * InputMatrix.M[5]);
274 }
275
276 //Computes det(FTF)^{1/2} * F * (FTF)^-1
278 {
280 const T J2 = FTF.Determinant();
281
282 const PMatrix<T, 2, 2> J2invT(FTF.M[3], -FTF.M[2], -FTF.M[1], FTF.M[0]);
283
284 if (J2 > T(0))
285 {
286 dJ = (T(1) / FMath::Sqrt(J2)) * (F * J2invT);
287 }
288 else
289 {
290 dJ = PMatrix<T, 3, 2>(TVec3<T>((T)0.), TVec3<T>((T)0.));
291 }
292 }
293
294 public:
295 void AddHyperelasticResidualAndHessian(const ParticleType& Particles, const int32 ElementIndex, const int32 ElementIndexLocal, const T Dt, TVec3<T>& ParticleResidual, Chaos::PMatrix<T, 3, 3>& ParticleHessian)
296 {
297 check(ElementIndex < DmInverse.Num() && ElementIndex > INDEX_NONE);
298 check(ElementIndex < MuElementArray.Num());
299 check(ElementIndex < Measure.Num());
300 check(ElementIndex < LambdaElementArray.Num());
302 if (ElementIndexLocal < 3
304 && ElementIndex < Measure.Num()
305 && ElementIndex < MuElementArray.Num()
306 && ElementIndex < LambdaElementArray.Num()
307 && ElementIndex < DmInverse.Num()
308 && ElementIndex > INDEX_NONE)
309 {
310 const Chaos::PMatrix<T, 2, 2> DmInvT = DmInverse[ElementIndex].GetTransposed(), DmInv = DmInverse[ElementIndex];
311 const Chaos::PMatrix<T, 3, 2> Fe = F(ElementIndex, Particles);
312
313 const PMatrix<T, 3, 2> Re = ComputeR(Fe);
315 const T J = FMath::Sqrt(FTF.Determinant());
316
317 PMatrix<T, 3, 2> Pe(TVec3<T>((T)0.), TVec3<T>((T)0.)), ForceTerm(TVec3<T>((T)0.), TVec3<T>((T)0.));
318 Pe = T(2) * MuElementArray[ElementIndex] * (Fe - Re) + LambdaElementArray[ElementIndex] * (J - T(1)) * J * Fe * ComputeFTF(Fe).Inverse();
319
320 ForceTerm = -Measure[ElementIndex] * Pe * DmInverse[ElementIndex].GetTransposed();
321
322 Chaos::TVector<T, 3> Dx((T)0.);
323 if (ElementIndexLocal > 0)
324 {
325 for (int32 c = 0; c < 3; c++)
326 {
327 Dx[c] += ForceTerm.M[ElementIndexLocal * 3 - 3 + c];
328 }
329 }
330 else
331 {
332 for (int32 c = 0; c < 3; c++)
333 {
334 for (int32 h = 0; h < 2; h++)
335 {
336 Dx[c] -= ForceTerm.M[h * 3 + c];
337 }
338 }
339 }
340
341 Dx *= Dt * Dt;
342
343 ParticleResidual -= Dx;
344
345 PMatrix<T, 3, 2> dJ(TVec3<T>((T)0.), TVec3<T>((T)0.));
346
347 dJdF32(Fe, dJ);
348
349 T Coeff = Dt * Dt * Measure[ElementIndex];
350
351 if (ElementIndexLocal == 0)
352 {
353 T DmInvsum = T(0);
354 for (int32 nu = 0; nu < 2; nu++)
355 {
356 T localDmsum = T(0);
357 for (int32 k = 0; k < 2; k++)
358 {
359 localDmsum += DmInv.M[nu * 2 + k];
360 }
362 }
363 for (int32 alpha = 0; alpha < 3; alpha++)
364 {
365 ParticleHessian.SetAt(alpha, alpha, ParticleHessian.GetAt(alpha, alpha) + Coeff * T(2) * MuElementArray[ElementIndex] * DmInvsum);
366 }
367
369 Chaos::TVector<T, 3> L((T)0.);
370 for (int32 alpha = 0; alpha < 3; alpha++)
371 {
372 for (int32 k = 0; k < 2; k++)
373 {
374 L[alpha] += dJDmInvT.M[3 * k + alpha];
375 }
376 }
377 for (int32 alpha = 0; alpha < 3; alpha++)
378 {
379 ParticleHessian.SetRow(alpha, ParticleHessian.GetRow(alpha) + Coeff * LambdaElementArray[ElementIndex] * L[alpha] * L);
380 }
381 }
382 else
383 {
384 T DmInvsum = T(0);
385 for (int32 nu = 0; nu < 2; nu++)
386 {
387 DmInvsum += DmInv.GetAt(ElementIndexLocal - 1, nu) * DmInv.GetAt(ElementIndexLocal - 1, nu);
388 }
389 for (int32 alpha = 0; alpha < 3; alpha++)
390 {
391 ParticleHessian.SetAt(alpha, alpha, ParticleHessian.GetAt(alpha, alpha) + Dt * Dt * Measure[ElementIndex] * T(2) * MuElementArray[ElementIndex] * DmInvsum);
392 }
393
395
396 Chaos::TVector<T, 3> L((T)0.);
397 for (int32 alpha = 0; alpha < 3; alpha++)
398 {
399 const int32 IndexVisited = ElementIndexLocal* 3 - 3 + alpha;
401 {
402 L[alpha] = dJDmInvT.M[IndexVisited];
403 }
404 }
405 for (int32 alpha = 0; alpha < 3; alpha++)
406 {
407 ParticleHessian.SetRow(alpha, ParticleHessian.GetRow(alpha) + Dt * Dt * Measure[ElementIndex] * LambdaElementArray[ElementIndex] * L[alpha] * L);
408 }
409 }
410 }
411 }
412
413
414
415 protected:
417
418 //material constants calculated from E:
419 T Mu;
425
428 };
429
430} // End namespace Chaos::Softs
431
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define UE_SMALL_NUMBER
Definition UnrealMathUtility.h:130
Definition Matrix.h:21
Definition GaussSeidelCorotatedCodimensionalConstraints.h:17
bool bRecordMetric
Definition GaussSeidelCorotatedCodimensionalConstraints.h:424
TArray< T > LambdaElementArray
Definition GaussSeidelCorotatedCodimensionalConstraints.h:422
static T SafeRecip(const T Len, const T Fallback)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:173
FGaussSeidelCorotatedCodimensionalConstraints(const ParticleType &InParticles, const TArray< TVector< int32, 3 > > &InMesh, const TArray< T > &EMeshArray, const T &NuMesh=(T).3)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:39
PMatrix< T, 3, 2 > Ds(const int32 E, const ParticleType &InParticles) const
Definition GaussSeidelCorotatedCodimensionalConstraints.h:76
void AddHyperelasticResidualAndHessian(const ParticleType &Particles, const int32 ElementIndex, const int32 ElementIndexLocal, const T Dt, TVec3< T > &ParticleResidual, Chaos::PMatrix< T, 3, 3 > &ParticleHessian)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:295
static void SymSchur2D(const T Aqq, const T App, const T Apq, T &c, T &s)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:182
T Mu
Definition GaussSeidelCorotatedCodimensionalConstraints.h:419
static PMatrix< T, 3, 2 > ComputeR(const PMatrix< T, 3, 2 > &Fe)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:226
TArray< T > MuElementArray
Definition GaussSeidelCorotatedCodimensionalConstraints.h:421
TArray< T > Measure
Definition GaussSeidelCorotatedCodimensionalConstraints.h:427
FGaussSeidelCorotatedCodimensionalConstraints(const ParticleType &InParticles, const TArray< TVector< int32, 3 > > &InMesh, const bool bRecordMetricIn=true, const T &EMesh=(T) 10.0, const T &NuMesh=(T).3)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:20
void ComputeNodalMass(const T InDensity, const int32 NumParticles, TArray< T > &NodalMass) const
Definition GaussSeidelCorotatedCodimensionalConstraints.h:128
static PMatrix< T, 3, 2 > ComputeRSimple(const PMatrix< T, 3, 2 > &InputMatrix)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:235
static PMatrix< T, 2, 2 > ComputeFTF(const PMatrix< T, 3, 2 > &InputMatrix)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:269
TArray< TVector< int32, 3 > > MeshConstraints
Definition GaussSeidelCorotatedCodimensionalConstraints.h:426
virtual ~FGaussSeidelCorotatedCodimensionalConstraints()
Definition GaussSeidelCorotatedCodimensionalConstraints.h:61
TArray< T > AlphaJArray
Definition GaussSeidelCorotatedCodimensionalConstraints.h:423
static void Jacobi(const PMatrix< T, 2, 2 > &B, PMatrix< T, 2, 2 > &D, PMatrix< T, 2, 2 > &V)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:213
static void dJdF32(const PMatrix< T, 3, 2 > &F, PMatrix< T, 3, 2 > &dJ)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:277
PMatrix< T, 3, 3 > DsInit(const int32 E, const ParticleType &InParticles)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:63
void InitializeCodimensionData(const ParticleType &Particles)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:145
T Lambda
Definition GaussSeidelCorotatedCodimensionalConstraints.h:420
TArray< TArray< int32 > > GetConstraintsArray() const
Definition GaussSeidelCorotatedCodimensionalConstraints.h:113
PMatrix< T, 3, 2 > F(const int32 E, const ParticleType &InParticles) const
Definition GaussSeidelCorotatedCodimensionalConstraints.h:99
TArray< FSolverMatrix22 > DmInverse
Definition GaussSeidelCorotatedCodimensionalConstraints.h:416
static Chaos::PMatrix< T, 3, 2 > GramSchmidt(const Chaos::PMatrix< T, 3, 2 > &InputMatrix)
Definition GaussSeidelCorotatedCodimensionalConstraints.h:256
Definition Vector.h:1000
Definition Vector.h:41
Definition Constraints.Build.cs:6
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void Init(const ElementType &Element, SizeType Number)
Definition Array.h:3043
Definition CollectionEmbeddedSpringConstraintFacade.cpp:6