UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MPMTransfer.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
4#include "Chaos/Vector.h"
5#include "ChaosCheck.h"
8#include "Chaos/UniformGrid.h"
9#include "Algo/Unique.h"
10
11namespace Chaos {
12
13template<class T>
15{
16public:
17
18 uint32 NPerSec = 2 * 2;
19 uint32 NPerEle = 2 * 2 * 2;
22
23 //TODO(Yizhou): Think whether mpm transfer should just own the grid
24 //(Is the grid used by the constraint as well?)
26
29 TArray<TArray<int32>> CellData; //CellData[i] registers which particles are in ith cell
30 //TArray<TArray<int32>> CellColors;
31
32 //meta data for grid based cons
37
38 //APIC data;
41
44 {
45 ensure(Grid.NPerDir == 2 || Grid.NPerDir == 3);
46 NPerSec = Grid.NPerDir * Grid.NPerDir;
47 NPerEle = NPerSec * Grid.NPerDir;
48 //CellColors.SetNum(NPerEle);
49 }
50 TMPMTransfer(TMPMGrid<T>& _Grid, const int32 NumParticles) :Grid(_Grid)
51 {
52 ensure(Grid.NPerDir == 2 || Grid.NPerDir == 3);
53 NPerSec = Grid.NPerDir * Grid.NPerDir;
54 NPerEle = NPerSec * Grid.NPerDir;
55 AArray.Init((T)0., 3 * 3 * NumParticles);
56 }
57
58 //template <typename ReorderFunctor, typename SplatFunctor>
59 //This one does an initial splat of momentum and mass to the grid.
60 //One can add splat functor in the future passibly for other kinds of splat
62 {
63 int32 N = InParticles.Size();
64
65 {
67 Indices.SetNum(N);
68 Weights.SetNum(N);
69
71 // compute weights and bin
73
74 //TODO(Yizhou): Do a timing and determine whether the following loop should
75 //use physics parallel for:
76 for (int32 p = 0; p < N; p++)
77 {
78 Grid.BaseNodeIndex(InParticles.GetX(p), Indices[p], Weights[p]);
79 }
80
81 }
83 // Computes which particles in the same cell
85 {
87 NumCells = Grid.Size();
89 for (int32 c = 0; c < NumCells; c++)
90 {
91 CellData[c].SetNum(0);
92 }
93 for (int32 p = 0; p < N; p++)
94 {
95 CellData[Grid.FlatIndex(Indices[p])].Emplace(p);
96 }
97 }
98
100 // splat data to cells
102 {
104 GridData.Init((T)0., CellData.Num() * (NTransfer + 1));
105
106 TVector<int32, 3> GridCells = Grid.GetCells();
107
108 for (int32 ii = 0; ii < int32(Grid.NPerDir); ii++)
109 {
110 for (int32 jj = 0; jj < int32(Grid.NPerDir); jj++)
111 {
112 for (int32 kk = 0; kk < int32(Grid.NPerDir); kk++)
113 {
114 int32 CurrentLocIndex = ii * NPerSec + jj * Grid.NPerDir + kk;
115 PhysicsParallelFor(GridCells[0] / Grid.NPerDir, [&](const int32 iii)
116 //{
117 //for (int32 iii = 0; iii < int32(GridCells[0] / Grid.NPerDir); iii++)
118 {
119 for (int32 jjj = 0; jjj < int32(GridCells[1] / Grid.NPerDir); jjj++)
120 {
121 for (int32 kkk = 0; kkk < int32(GridCells[2] / Grid.NPerDir); kkk++)
122 {
123 TVector<int32, 3> MultiIndex = { iii * int32(Grid.NPerDir) + ii, jjj * int32(Grid.NPerDir) + jj, kkk * int32(Grid.NPerDir) + kk };
124 int32 CellIndex = Grid.FlatIndex(MultiIndex);
125 P2GApplyHelper(InParticles, CellIndex, GridData);
126 }
127 }
128 });
129 //}
130
131 }
132 }
133 }
134
135 }
136
137 }
138
139 //currently only splats mass and momentum
140 void P2GApplyHelper(const TDynamicParticles<T, 3>& InParticles, const int32 CellIndex, TArray<T>& GridData)
141 {
142 //check if valid cell:
143 if (CellIndex < NumCells && CellData[CellIndex].Num() > 0)
144 {
145 for (int32 i = 0; i < CellData[CellIndex].Num(); i++)
146 {
147 int32 p = CellData[CellIndex][i];
148 for (int iii = 0; iii < int32(Grid.NPerDir); iii++)
149 {
150 T Nii = Grid.Nijk(Weights[p][0], iii);
151 for (int jjj = 0; jjj < int32(Grid.NPerDir); jjj++)
152 {
153 T Njj = Grid.Nijk(Weights[p][1], jjj);
154 for (int kkk = 0; kkk < int32(Grid.NPerDir); kkk++)
155 {
157 TVector<int32, 3> GlobMultiIndex = Grid.Loc2GlobIndex(Indices[p], LocIndex);
158 int32 GlobIndex = Grid.FlatIndex(GlobMultiIndex);
159 T Nkk = Grid.Nijk(Weights[p][2], kkk);
160 T NProd = Nii * Njj * Nkk;
161 GridData[(NTransfer + 1) * GlobIndex] += NProd * InParticles.M(p);
162 for (int32 alpha = 0; alpha < 3; alpha++)
163 {
164 GridData[(NTransfer + 1) * GlobIndex + alpha + 1] += NProd * InParticles.M(p) * InParticles.V(p)[alpha];
165 }
166 APICP2G(p, GlobIndex, NProd * InParticles.M(p), InParticles, GridData);
167 }
168 }
169 }
170 }
171 }
172 }
173
174 void APICP2G(const int32 p, const int32 GlobIndex, const T mip, const TDynamicParticles<T, 3>& Particles, TArray<T>& GridData)
175 {
176 TVector<T, 3> xi_minus_xp = Grid.Node(GlobIndex) - Particles.GetX(p);
177 for (int32 l = 0; l < 3; ++l)
178 {
179 T vl = T(0);
180 for (int32 m = 0; m < int32(NumModes); ++m)
181 vl += AArray[NumModes * 3 * p + NumModes * l + m] * xi_minus_xp[m];
182
183 GridData[l + (NTransfer + 1) * GlobIndex + 1] += mip * vl;
184 }
185
186 }
187
189 {
190 ElementGridNodes.SetNum(InMesh.Num());
191 ElementGridNodeWeights.SetNum(InMesh.Num());
192 ElementGridNodeIncidentElements.SetNum(InMesh.Num());
193 ElementGridNodesSet.SetNum(InMesh.Num());
194 //TODO(Yizhou): make following loop parallel for with appropriate bool condition
195 for (int32 e = 0; e < InMesh.Num(); e++)
196 {
197 ElementGridNodes[e].SetNum(NPerEle * 4);
198 ElementGridNodeWeights[e].SetNum(NPerEle * 4);
199 for (int32 ie = 0; ie < 4; ie++)
200 {
201 int32 p = InMesh[e][ie];
202 TVector<int32, 3> Index = Indices[p];
203 for (int32 ii = 0; ii < int32(Grid.NPerDir); ii++)
204 {
205 T Nii = Grid.Nijk(Weights[p][0], ii);
206 for (int32 jj = 0; jj < int32(Grid.NPerDir); jj++)
207 {
208 T Njj = Grid.Nijk(Weights[p][1], jj);
209 for (int32 kk = 0; kk < int32(Grid.NPerDir); kk++)
210 {
211 T Nkk = Grid.Nijk(Weights[p][2], kk);
214 int32 GlobIndexFlat = Grid.FlatIndex(GlobIndex);
215 ElementGridNodes[e][ie * NPerEle + ii * NPerSec + jj * Grid.NPerDir + kk] = GlobIndexFlat;
216 ElementGridNodeWeights[e][ie * NPerEle + ii * NPerSec + jj * Grid.NPerDir + kk] = Nii * Njj * Nkk;
217 }
218 }
219 }
220 }
221 ComputeIncidentElements(ElementGridNodes[e], ElementGridNodeIncidentElements[e]);
222 ElementGridNodesSet[e].SetNum(ElementGridNodeIncidentElements[e].Num());
223 for (int32 kk = 0; kk < ElementGridNodeIncidentElements[e].Num(); kk++)
224 {
225 ElementGridNodesSet[e][kk] = ElementGridNodes[e][ElementGridNodeIncidentElements[e][kk][0]];
226 }
227 }
228 }
229
230 //computes incident elements in serial
231 static void ComputeIncidentElements(const TArray<int32>& ArrayIn, TArray<TArray<int32>>& IncidentElements)
232 {
233 TArray<int32> Ordering, Ranges;
234 Ordering.SetNum(ArrayIn.Num());
235 Ranges.SetNum(ArrayIn.Num()+1);
236
237 for (int32 i = 0; i < ArrayIn.Num(); ++i)
238 {
239 Ordering[i] = i;
240 Ranges[i] = i;
241 }
242
243 //TODO(Yizhou): decide to use sort or heap sort or merge sort.
244 Ordering.Sort([&ArrayIn](const int32 A, const int32 B)
245 {
246 return ArrayIn[A] < ArrayIn[B];
247 });
248
249 int32 Last = Algo::Unique(Ranges, [&ArrayIn, &Ordering](int32 i, int32 j) { return ArrayIn[Ordering[i]] == ArrayIn[Ordering[j]]; });
250
251 int32 NumNodes = Last - 1;
252 Ranges[NumNodes] = ArrayIn.Num();
253 Ranges.SetNum(NumNodes + 1);
254
255 IncidentElements.SetNum(Ranges.Num() - 1);
256
257 for (int32 p = 0; p < IncidentElements.Num(); ++p)
258 {
259 IncidentElements[p].SetNum(Ranges[p + 1] - Ranges[p]);
260 for (int32 e = Ranges[p]; e < Ranges[p + 1]; e++)
261 {
262 IncidentElements[p][e - Ranges[p]] = Ordering[e];
263 }
264 }
265 }
266
267 void ComputeGridPositions(const TArray<T>& GridData, const T Dt, TArray<TVector<T, 3>>& GridPositions)
268 {
269 GridPositions.SetNum(Grid.Size());
270 for (int32 i = 0; i < Grid.Size(); i++)
271 {
272 TVector<T,3> XOld = Grid.Node(i);
273 T Mass = GridData[(NTransfer + 1) * i];
274 if (Mass == 0) {
275 GridPositions[i] = XOld;
276 }
277 else {
278 for (int32 Alpha = 0; Alpha < int32(NTransfer); Alpha++)
279 GridPositions[i][Alpha] = Dt * GridData[(NTransfer + 1) * i + Alpha + 1] / Mass + XOld[Alpha];
280 }
281 }
282 }
283
284
285 TVec4<TVector<T, 3>> SparseG2P(const TArray<TVector<T, 3>>& GridPositions, const int32 ElementIndex)
286 {
287 TVec4<TVector<T, 3>> Result(TVector<T, 3>((T)0.));
288
289 for (int32 i = 0; i < 4; i++) {
290 for (int32 ii = 0; ii < int32(NPerEle); ii++) {
291 int32 FlatIndex = ElementGridNodes[ElementIndex][NPerEle * i + ii];
292 for (int32 Alpha = 0; Alpha < 3; Alpha++) {
293 Result[i][Alpha] += ElementGridNodeWeights[ElementIndex][NPerEle * i + ii] * GridPositions[FlatIndex][Alpha];
294 }
295 }
296 }
297
298 return Result;
299 }
300
301 void ComputeAArray(const TArray<T>& GridData, const TDynamicParticles<T, 3>& Particles)
302 {
303 AArray.Init((T)0., NumModes * 3 * Particles.Size());
304 PhysicsParallelFor(int32(Particles.Size()), [&](const int32 p)
305 //for (int32 p = 0; p < int32(Particles.Size()); p++)
306 {
307 TVector<int32, 3> BaseIndex = Indices[p];
308 for (int32 ii = 0; ii < int32(Grid.NPerDir); ii++)
309 {
310 T Nii = Grid.Nijk(Weights[p][0], ii);
311 T dNii = Grid.dNijk(Weights[p][0], ii, Grid.GetDx()[0]);
312 for (int32 jj = 0; jj < int32(Grid.NPerDir); jj++)
313 {
314 T Njj = Grid.Nijk(Weights[p][1], jj);
315 T dNjj = Grid.dNijk(Weights[p][1], jj, Grid.GetDx()[0]);
316 for (int32 kk = 0; kk < int32(Grid.NPerDir); kk++)
317 {
318 T Nkk = Grid.Nijk(Weights[p][2], kk);
319 T dNkk = Grid.dNijk(Weights[p][2], kk, Grid.GetDx()[0]);
320 TVector<T, 3> Ni = { Nii, Njj, Nkk };
321 TVector<T, 3> dNi = { dNii, dNjj, dNkk };
322 TVector<int32, 3> LocIndex = { ii, jj, kk };
323 TVector<int32, 3> GlobIndex = Grid.Loc2GlobIndex(BaseIndex, LocIndex);
324 int32 GlobIndexFlat = Grid.FlatIndex(GlobIndex);
325 if (GridData[(NTransfer + 1) * GlobIndexFlat] != T(0))
326 {
327 if (Grid.interp == TMPMGrid<T>::linear)
328 {
329 TVector<T, 3> dN((T)0.);
330 Grid.GradNi(Ni, dNi, dN);
331 for (int32 l = 0; l < 3; l++)
332 {
333 T GridQuantity = GridData[(NTransfer + 1) * GlobIndexFlat + 1 + l] / GridData[(NTransfer + 1) * GlobIndexFlat];
334 for (int32 iii = 0; iii < int32(NumModes); ++iii)
335 AArray[NumModes * 3 * p + NumModes * l + iii] += dN[iii] * GridQuantity;
336 }
337 }
338 else
339 {
340 TVector<T, 3> rip = Grid.Node(GlobIndexFlat) - Particles.GetX(p);
341 T NiProdbInv = (T(4) * Ni[0] * Ni[1] * Ni[2]) / (Grid.GetDx()[0] * Grid.GetDx()[0]);
342 for (int32 l = 0; l < 3; l++)
343 {
344 T GridQuantity = GridData[(NTransfer + 1) * GlobIndexFlat + 1 + l] / GridData[(NTransfer + 1) * GlobIndexFlat];
345 for (int32 iii = 0; iii < int32(NumModes); ++iii)
346 AArray[NumModes * 3 * p + NumModes * l + iii] += NiProdbInv * rip[iii] * GridQuantity;
347 }
348 }
349 }
350
351 }
352 }
353 }
354 }, Particles.Size() < 50);
355 }
356
357 void GridPositionsToGridData(const TArray<TVector<T, 3>>& GridPositions, const T Dt, TArray<T>& GridData)
358 {
359 for (int32 i = 0; i < GridPositions.Num(); i++)
360 {
361 T Mi = GridData[(NTransfer + 1) * i];
362 if (Mi != T(0))
363 {
364 TVector<T, 3> NodePos = Grid.Node(i);
365 for (int32 alpha = 0; alpha < 3; alpha++)
366 {
367 GridData[(NTransfer + 1) * i + alpha + 1] = Mi * (GridPositions[i][alpha] - NodePos[alpha]) / Dt;
368 }
369 }
370 //else
371 //{
372 // for (int32 alpha = 0; alpha < 3; alpha++)
373 // {
374 // }
375 //}
376 }
377
378 }
379
380 void G2P(const TArray<T>& GridData, TDynamicParticles<T, 3>& Particles)
381 {
382 PhysicsParallelFor(Particles.Size(), [&](const int32 p)
383 {
384 Particles.V(p) = TVec3<T>((T)0.);
385 for (int32 ii = 0; ii < int32(Grid.NPerDir); ii++)
386 {
387 T Nii = Grid.Nijk(Weights[p][0], ii);
388 for (int32 jj = 0; jj < int32(Grid.NPerDir); jj++)
389 {
390 T Njj = Grid.Nijk(Weights[p][1], jj);
391 for (int32 kk = 0; kk < int32(Grid.NPerDir); kk++)
392 {
393 T Nkk = Grid.Nijk(Weights[p][2], kk);
394 TVector<int32, 3> LocIndex = { ii, jj, kk };
395 TVector<int32, 3> GlobIndex = Grid.Loc2GlobIndex(Indices[p], LocIndex);
396 int32 GlobIndexFlat = Grid.FlatIndex(GlobIndex);
397 if (GridData[GlobIndexFlat * (NTransfer + 1)] > T(0))
398 {
399 for (int32 alpha = 0; alpha < 3; alpha++)
400 {
401 Particles.V(p)[alpha] += Nii * Njj * Nkk * GridData[GlobIndexFlat * (NTransfer + 1) + alpha + 1] / GridData[GlobIndexFlat * (NTransfer + 1)];
402 }
403 }
404 }
405 }
406 }
407 }, Particles.Size() < 50);
408 }
409
410
412 {
413
415 GridGradient.Init(TVector<T, 3>((T)0.), 4 * NPerEle);
416 for (int32 i = 0; i < 4; i++) {
417 for (int32 ii = 0; ii < int32(NPerEle); ii++) {
418 for (int32 alpha = 0; alpha < 3; alpha++) {
419 GridGradient[NPerEle * i + ii][alpha] += ElementGridNodeWeights[ElementIndex][NPerEle * i + ii] * InGradient[i][alpha];
420 }
421 }
422 }
423
425 GridGradientCompact.Init(TVector<T, 3>((T)0.), ElementGridNodeIncidentElements[ElementIndex].Num());
426
427 for (int32 node = 0; node < ElementGridNodeIncidentElements[ElementIndex].Num(); node++)
428 {
429 for (int32 node_indices = 0; node_indices < ElementGridNodeIncidentElements[ElementIndex][node].Num(); node_indices++)
430 {
431 for (int32 alpha = 0; alpha < 3; alpha++)
432 {
433 GridGradientCompact[node][alpha] += GridGradient[ElementGridNodeIncidentElements[ElementIndex][node][node_indices]][alpha];
434 }
435 }
436 }
437
438 return GridGradient;
439
440 }
441
442};
443
444}
#define ensure( InExpression)
Definition AssertionMacros.h:464
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 TRACE_CPUPROFILER_EVENT_SCOPE(Name)
Definition CpuProfilerTrace.h:528
@ Num
Definition MetalRHIPrivate.h:234
uint32_t uint32
Definition binka_ue_file_header.h:6
uint32 Size() const
Definition ArrayCollection.h:66
Definition DynamicParticles.h:11
Definition UniformGrid.h:315
Definition MPMTransfer.h:15
TMPMTransfer(TMPMGrid< T > &_Grid)
Definition MPMTransfer.h:43
TArray< TArray< TArray< int32 > > > ElementGridNodeIncidentElements
Definition MPMTransfer.h:35
TArray< TVector< T, 3 > > Weights
Definition MPMTransfer.h:27
TArray< TVector< int32, 3 > > Indices
Definition MPMTransfer.h:28
TArray< TArray< int32 > > ElementGridNodes
Definition MPMTransfer.h:33
TArray< TArray< T > > ElementGridNodeWeights
Definition MPMTransfer.h:34
void P2GApplyHelper(const TDynamicParticles< T, 3 > &InParticles, const int32 CellIndex, TArray< T > &GridData)
Definition MPMTransfer.h:140
TArray< TArray< int32 > > ElementGridNodesSet
Definition MPMTransfer.h:36
void G2P(const TArray< T > &GridData, TDynamicParticles< T, 3 > &Particles)
Definition MPMTransfer.h:380
void ComputeElementMetaData(const TArray< TVector< int32, 4 > > &InMesh)
Definition MPMTransfer.h:188
static void ComputeIncidentElements(const TArray< int32 > &ArrayIn, TArray< TArray< int32 > > &IncidentElements)
Definition MPMTransfer.h:231
void APICP2G(const int32 p, const int32 GlobIndex, const T mip, const TDynamicParticles< T, 3 > &Particles, TArray< T > &GridData)
Definition MPMTransfer.h:174
void InitialP2G(const TDynamicParticles< T, 3 > &InParticles, TArray< T > &GridData)
Definition MPMTransfer.h:61
uint32 NumModes
Definition MPMTransfer.h:40
TMPMTransfer(TMPMGrid< T > &_Grid, const int32 NumParticles)
Definition MPMTransfer.h:50
void ComputeGridPositions(const TArray< T > &GridData, const T Dt, TArray< TVector< T, 3 > > &GridPositions)
Definition MPMTransfer.h:267
TMPMTransfer()
Definition MPMTransfer.h:42
TArray< TArray< int32 > > CellData
Definition MPMTransfer.h:29
uint32 NPerSec
Definition MPMTransfer.h:18
TArray< TVector< T, 3 > > SparseP2G(const TVec4< TVector< T, 3 > > &InGradient, const int32 ElementIndex)
Definition MPMTransfer.h:411
TMPMGrid< T > & Grid
Definition MPMTransfer.h:25
TVec4< TVector< T, 3 > > SparseG2P(const TArray< TVector< T, 3 > > &GridPositions, const int32 ElementIndex)
Definition MPMTransfer.h:285
void GridPositionsToGridData(const TArray< TVector< T, 3 > > &GridPositions, const T Dt, TArray< T > &GridData)
Definition MPMTransfer.h:357
void ComputeAArray(const TArray< T > &GridData, const TDynamicParticles< T, 3 > &Particles)
Definition MPMTransfer.h:301
uint32 NPerEle
Definition MPMTransfer.h:19
int32 NumCells
Definition MPMTransfer.h:21
uint32 NTransfer
Definition MPMTransfer.h:20
TArray< T > AArray
Definition MPMTransfer.h:39
const TVector< T, d > & GetX(const int32 Index) const
Definition Particles.h:156
Definition Vector.h:41
int32 Num() const
Definition Vector.h:150
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
void Init(const ElementType &Element, SizeType Number)
Definition Array.h:3043
UE_NODEBUG void Sort()
Definition Array.h:3418
Definition SkeletalMeshComponent.h:307
void CHAOS_API PhysicsParallelFor(int32 InNum, TFunctionRef< void(int32)> InCallable, bool bForceSingleThreaded=false)
Definition Parallel.cpp:55
U16 Index
Definition radfft.cpp:71