Loading...
Searching...
No Matches
MPMSystemData-Impl.hpp
Go to the documentation of this file.
1// This code is based on Jet framework.
2// Copyright (c) 2018 Doyub Kim
3// CubbyFlow is voxel-based fluid simulation engine for computer games.
4// Copyright (c) 2020 CubbyFlow Team
5// Core Part: Chris Ohk, Junwoo Hwang, Jihong Sin, Seungwoo Yoo
6// AI Part: Dongheon Cho, Minseo Kim
7// We are making my contributions/submissions to this project solely in our
8// personal capacity and are not conveying any rights to any intellectual
9// property of any third parties.
10
11#ifndef CUBBYFLOW_MPM_SYSTEM_DATA_IMPL_HPP
12#define CUBBYFLOW_MPM_SYSTEM_DATA_IMPL_HPP
13
15
16#include <algorithm>
17#include <cmath>
18#include <limits>
19#include <stdexcept>
20#include <utility>
21
22namespace CubbyFlow
23{
24template <size_t N>
26{
27 const double ax = std::abs(x);
28
29 if (ax < 1.0)
30 {
31 return 0.5 * ax * ax * ax - ax * ax + 2.0 / 3.0;
32 }
33
34 if (ax < 2.0)
35 {
36 const double d = 2.0 - ax;
37 return d * d * d / 6.0;
38 }
39
40 return 0.0;
41}
42
43template <size_t N>
45{
46 const double ax = std::abs(x);
47
48 if (ax < 1.0)
49 {
50 return x * (1.5 * ax - 2.0);
51 }
52
53 if (ax < 2.0)
54 {
55 const double d = 2.0 - ax;
56 return -0.5 * d * d * std::copysign(1.0, x);
57 }
58
59 return 0.0;
60}
61
62template <size_t N>
67{
68 for (size_t axis = 0; axis < N; ++axis)
69 {
70 if (!std::isfinite(position[axis]) ||
71 !std::isfinite(gridSpacing[axis]) ||
72 !std::isfinite(dataOrigin[axis]) || gridSpacing[axis] <= 0.0)
73 {
74 throw std::invalid_argument("Invalid cubic B-spline input.");
75 }
76
77 (*normalized)[axis] =
79
80 const double lowestIndex = std::nextafter(
81 static_cast<double>(std::numeric_limits<ssize_t>::lowest()) + 1.0,
82 0.0);
83 if (const double highestIndex = std::nextafter(
84 static_cast<double>(std::numeric_limits<ssize_t>::max()) - 2.0,
85 0.0);
86 !std::isfinite((*normalized)[axis]) ||
87 (*normalized)[axis] < lowestIndex ||
88 (*normalized)[axis] > highestIndex)
89 {
90 throw std::invalid_argument(
91 "Cubic B-spline index is out of range.");
92 }
93
94 (*firstIndex)[axis] =
95 static_cast<ssize_t>(std::floor((*normalized)[axis])) - 1;
96 }
97}
98
99template <size_t N>
100CubicBSplineKernel<N>::Entry CubicBSplineKernel<N>::GetStencilEntry(
103{
104 Entry entry;
105 std::array<double, N> axisWeights;
106
107 entry.weight = 1.0;
108
109 for (size_t axis = 0; axis < N; ++axis)
110 {
111 entry.index[axis] =
112 firstIndex[axis] + static_cast<ssize_t>(offset[axis]);
114 Weight(normalized[axis] - static_cast<double>(entry.index[axis]));
115 entry.weight *= axisWeights[axis];
116 }
117
118 for (size_t axis = 0; axis < N; ++axis)
119 {
120 entry.gradient[axis] =
121 Gradient(normalized[axis] -
122 static_cast<double>(entry.index[axis])) /
124
125 for (size_t other = 0; other < N; ++other)
126 {
127 if (other != axis)
128 {
129 entry.gradient[axis] *= axisWeights[other];
130 }
131 }
132 }
133
134 return entry;
135}
136
137template <size_t N>
141{
144 GetStencilCoordinates(position, gridSpacing, dataOrigin, &normalized,
146
147 std::array<Entry, STENCIL_SIZE> result;
148 size_t flatIndex = 0;
149
152 &gridSpacing](auto... rawIndices) {
154 result[flatIndex++] = GetStencilEntry(
156 });
157
158 return result;
159}
160
161template <size_t N>
171
172template <size_t N>
174{
175 Base::Resize(newNumberOfParticles);
176
177 m_particleMasses.Resize(newNumberOfParticles, Base::Mass());
178 m_initialVolumes.Resize(newNumberOfParticles, 0.0);
179}
180
181template <size_t N>
182void MPMTransferSystemData<N>::Deserialize(const std::vector<uint8_t>& buffer)
183{
184 Base::Deserialize(buffer);
185 ResetTransferState();
186}
187
188template <size_t N>
190{
191 Base::Set(other);
192 ResetTransferState();
193}
194
195template <size_t N>
199{
200 ValidateGridParameters(resolution, gridSpacing, gridOrigin);
201
202 m_gridMass.Resize(resolution, gridSpacing, gridOrigin);
203 m_gridVelocities.Resize(resolution, gridSpacing, gridOrigin);
204 m_gridVelocitiesBeforeUpdate.Resize(resolution, gridSpacing, gridOrigin);
205}
206
207template <size_t N>
209{
210 return m_particleMasses.View();
211}
212
213template <size_t N>
215{
216 return m_particleMasses.View();
217}
218
219template <size_t N>
221{
222 return m_initialVolumes.View();
223}
224
225template <size_t N>
227{
228 return m_initialVolumes.View();
229}
230
231template <size_t N>
233{
234 return m_gridMass;
235}
236
237template <size_t N>
242
243template <size_t N>
245 const
246{
247 return m_gridVelocities;
248}
249
250template <size_t N>
255
256template <size_t N>
259{
260 return m_gridVelocitiesBeforeUpdate;
261}
262
263template <size_t N>
266{
267 return m_gridVelocitiesBeforeUpdate;
268}
269
270template <size_t N>
272{
273 return m_flipBlendingFactor;
274}
275
276template <size_t N>
278{
279 if (!std::isfinite(factor) || factor < 0.0 || factor > 1.0)
280 {
281 throw std::invalid_argument("FLIP blending factor must be in [0, 1].");
282 }
283
284 m_flipBlendingFactor = factor;
285}
286
287template <size_t N>
289{
290 ValidateGridState();
291
292 const auto positions = this->Positions();
293 const auto velocities = this->Velocities();
294
295 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
296 {
297 if (!std::isfinite(m_particleMasses[i]) || m_particleMasses[i] <= 0.0 ||
298 !IsFinite(positions[i]) || !IsFinite(velocities[i]))
299 {
300 throw std::invalid_argument("Invalid MPM particle state.");
301 }
302 }
303
304 VertexCenteredScalarGrid<N> nextGridMass{ m_gridMass.Resolution(),
305 m_gridMass.GridSpacing(),
306 m_gridMass.Origin() };
308 m_gridVelocities.Resolution(), m_gridVelocities.GridSpacing(),
309 m_gridVelocities.Origin()
310 };
311
312 const auto dataSize = nextGridMass.DataSize();
313 const auto gridSpacing = nextGridMass.GridSpacing();
314 const auto dataOrigin = nextGridMass.DataOrigin();
315
316 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
317 {
320
321 for (const auto& entry : stencil)
322 {
323 if (entry.weight == 0.0)
324 {
325 continue;
326 }
327
328 const auto index = ClampIndex(entry.index, dataSize);
329 const double mass = entry.weight * m_particleMasses[i];
330
331 nextGridMass(index) += mass;
332 nextGridVelocities(index) += mass * velocities[i];
333 }
334 }
335
336 nextGridMass.ForEachDataPointIndex([&nextGridMass, &nextGridVelocities](
337 const Vector<size_t, N>& index) {
338 const double mass = nextGridMass(index);
339
340 if (!std::isfinite(mass) ||
342 {
343 throw std::invalid_argument("Invalid MPM grid accumulation.");
344 }
345
346 if (mass > 0.0)
347 {
348 nextGridVelocities(index) /= mass;
349
351 {
352 throw std::invalid_argument(
353 "Invalid MPM grid velocity update.");
354 }
355 }
356 });
357
360
361 m_gridMass = std::move(nextGridMass);
362 m_gridVelocities = std::move(nextGridVelocities);
363 m_gridVelocitiesBeforeUpdate = std::move(nextGridVelocitiesBeforeUpdate);
364}
365
366template <size_t N>
368{
369 ValidateGridToParticleState();
370 TransferFromGridToParticlesUnchecked();
371}
372
373template <size_t N>
375{
376 ValidateGridState();
377
378 const auto positions = this->Positions();
379 const auto velocities = this->Velocities();
380
381 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
382 {
383 if (!IsFinite(positions[i]) || !IsFinite(velocities[i]))
384 {
385 throw std::invalid_argument("Invalid MPM particle state.");
386 }
387 }
388
389 m_gridVelocities.ForEachDataPointIndex(
390 [this](const Vector<size_t, N>& index) {
391 if (!IsFinite(m_gridVelocities(index)) ||
392 !IsFinite(m_gridVelocitiesBeforeUpdate(index)))
393 {
394 throw std::invalid_argument("Invalid MPM grid velocity.");
395 }
396 });
397}
398
399template <size_t N>
401{
402 const auto positions = this->Positions();
403 auto velocities = this->Velocities();
404 Array1<Vector<double, N>> nextVelocities(this->NumberOfParticles());
405
406 const auto dataSize = m_gridVelocities.DataSize();
407 const auto gridSpacing = m_gridVelocities.GridSpacing();
408 const auto dataOrigin = m_gridVelocities.DataOrigin();
409
410 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
411 {
416
417 for (const auto& entry : stencil)
418 {
419 if (entry.weight == 0.0)
420 {
421 continue;
422 }
423
424 const auto index = ClampIndex(entry.index, dataSize);
425 picVelocity += entry.weight * m_gridVelocities(index);
426 flipDelta += entry.weight * (m_gridVelocities(index) -
427 m_gridVelocitiesBeforeUpdate(index));
428 }
429
432 (1.0 - m_flipBlendingFactor) * picVelocity +
433 m_flipBlendingFactor * flipVelocity;
434
435 if (!IsFinite(result))
436 {
437 throw std::invalid_argument(
438 "Invalid MPM particle velocity update.");
439 }
440
442 }
443
444 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
445 {
447 }
448}
449
450template <size_t N>
452 size_t particleIndex) const
453{
454 const auto positions = this->Positions();
455 const auto dataSize = m_gridVelocities.DataSize();
457 positions[particleIndex], m_gridVelocities.GridSpacing(),
458 m_gridVelocities.DataOrigin());
460
461 for (const auto& entry : stencil)
462 {
463 if (entry.weight == 0.0)
464 {
465 continue;
466 }
467
468 const Vector<double, N> velocity =
469 m_gridVelocities(ClampIndex(entry.index, dataSize));
470
471 for (size_t row = 0; row < N; ++row)
472 {
473 for (size_t column = 0; column < N; ++column)
474 {
475 result(row, column) += velocity[row] * entry.gradient[column];
476 }
477 }
478 }
479
480 return result;
481}
482
483template <size_t N>
485 const Vector<ssize_t, N>& index, const Vector<size_t, N>& dataSize)
486{
488
489 for (size_t axis = 0; axis < N; ++axis)
490 {
491 result[axis] = index[axis] < 0
492 ? 0
493 : std::min(static_cast<size_t>(index[axis]),
494 dataSize[axis] - 1);
495 }
496
497 return result;
498}
499
500template <size_t N>
502{
503 for (size_t axis = 0; axis < N; ++axis)
504 {
505 if (!std::isfinite(value[axis]))
506 {
507 return false;
508 }
509 }
510
511 return true;
512}
513
514template <size_t N>
518{
519 for (size_t axis = 0; axis < N; ++axis)
520 {
521 if (resolution[axis] == 0 ||
522 resolution[axis] == std::numeric_limits<size_t>::max() ||
523 !std::isfinite(gridSpacing[axis]) || gridSpacing[axis] <= 0.0 ||
524 !std::isfinite(gridOrigin[axis]))
525 {
526 throw std::invalid_argument("Invalid MPM grid parameters.");
527 }
528 }
529}
530
531template <size_t N>
533{
534 ValidateGridParameters(m_gridMass.Resolution(), m_gridMass.GridSpacing(),
535 m_gridMass.Origin());
536 ValidateGridParameters(m_gridVelocities.Resolution(),
537 m_gridVelocities.GridSpacing(),
538 m_gridVelocities.Origin());
539 ValidateGridParameters(m_gridVelocitiesBeforeUpdate.Resolution(),
540 m_gridVelocitiesBeforeUpdate.GridSpacing(),
541 m_gridVelocitiesBeforeUpdate.Origin());
542
543 if (m_gridMass.Resolution() != m_gridVelocities.Resolution() ||
544 m_gridMass.Resolution() != m_gridVelocitiesBeforeUpdate.Resolution() ||
545 m_gridMass.GridSpacing() != m_gridVelocities.GridSpacing() ||
546 m_gridMass.GridSpacing() !=
547 m_gridVelocitiesBeforeUpdate.GridSpacing() ||
548 m_gridMass.Origin() != m_gridVelocities.Origin() ||
549 m_gridMass.Origin() != m_gridVelocitiesBeforeUpdate.Origin())
550 {
551 throw std::invalid_argument("MPM grids must have matching geometry.");
552 }
553}
554
555template <size_t N>
557{
558 m_particleMasses.Fill(Base::Mass());
559 m_initialVolumes.Fill(0.0);
560 m_gridMass.Fill(0.0, ExecutionPolicy::Serial);
561 m_gridVelocities.Fill(Vector<double, N>{}, ExecutionPolicy::Serial);
562 m_gridVelocitiesBeforeUpdate.Fill(Vector<double, N>{},
564}
565
566template <size_t N>
576
577template <size_t N>
579{
580 TransferBase::Resize(newNumberOfParticles);
581 m_deformationStates.Resize(newNumberOfParticles, DeformationState{});
582}
583
584template <size_t N>
585void MPMSystemData<N>::Deserialize(const std::vector<uint8_t>& buffer)
586{
587 TransferBase::Deserialize(buffer);
588 m_deformationStates.Fill(DeformationState{});
589}
590
591template <size_t N>
593{
594 TransferBase::Set(other);
595 m_deformationStates.Fill(DeformationState{});
596}
597
598template <size_t N>
601{
602 return m_deformationStates.View();
603}
604
605template <size_t N>
608{
609 return m_deformationStates.View();
610}
611} // namespace CubbyFlow
612
613#endif
Tensor-product cubic B-spline interpolation kernel.
Definition MPMSystemData.hpp:28
static double Weight(double x)
Definition MPMSystemData-Impl.hpp:25
static Stencil GetStencil(const Vector< double, N > &position, const Vector< double, N > &gridSpacing, const Vector< double, N > &dataOrigin)
Definition MPMSystemData-Impl.hpp:138
static double Gradient(double x)
Definition MPMSystemData-Impl.hpp:44
std::array< Entry, STENCIL_SIZE > Stencil
Definition MPMSystemData.hpp:41
ConstArrayView1< DeformationState > DeformationStates() const
Returns per-particle deformation states.
Definition MPMSystemData-Impl.hpp:600
void Set(const ParticleSystemData< N > &other) override
Copies inherited particle state and resets deformation state.
Definition MPMSystemData-Impl.hpp:592
MPMSystemData(const Vector< size_t, N > &resolution=Vector< size_t, N >::MakeConstant(1), const Vector< double, N > &gridSpacing=Vector< double, N >::MakeConstant(1.0), const Vector< double, N > &gridOrigin=Vector< double, N >{}, size_t numberOfParticles=0)
Constructs snow MPM state with a vertex-centered background grid.
Definition MPMSystemData-Impl.hpp:567
void Deserialize(const std::vector< uint8_t > &buffer) override
Deserializes inherited particle state and resets deformation state.
Definition MPMSystemData-Impl.hpp:585
void Resize(size_t newNumberOfParticles) override
Resizes particle state, initializing new deformation states.
Definition MPMSystemData-Impl.hpp:578
Shared N-D material point method particle-grid transfer state.
Definition MPMSystemData.hpp:72
const VertexCenteredVectorGrid< N > & GridVelocitiesBeforeUpdate() const
Returns grid velocities before the grid update.
Definition MPMSystemData-Impl.hpp:258
ConstArrayView1< double > ParticleMasses() const
Returns per-particle masses.
Definition MPMSystemData-Impl.hpp:208
void ValidateGridState() const
Definition MPMSystemData-Impl.hpp:532
const VertexCenteredVectorGrid< N > & GridVelocities() const
Returns current grid velocities.
Definition MPMSystemData-Impl.hpp:244
ConstArrayView1< double > InitialVolumes() const
Returns per-particle initial volumes.
Definition MPMSystemData-Impl.hpp:220
void Resize(size_t newNumberOfParticles) override
Resizes particle state, initializing new transfer attributes.
Definition MPMSystemData-Impl.hpp:173
void TransferFromGridToParticlesUnchecked()
Definition MPMSystemData-Impl.hpp:400
void SetFLIPBlendingFactor(double factor)
Sets the FLIP fraction used for grid-to-particle transfer.
Definition MPMSystemData-Impl.hpp:277
const VertexCenteredScalarGrid< N > & GridMass() const
Returns grid mass.
Definition MPMSystemData-Impl.hpp:232
static void ValidateGridParameters(const Vector< size_t, N > &resolution, const Vector< double, N > &gridSpacing, const Vector< double, N > &gridOrigin)
Definition MPMSystemData-Impl.hpp:515
void TransferFromParticlesToGrid()
Definition MPMSystemData-Impl.hpp:288
Matrix< double, N, N > ComputeVelocityGradient(size_t particleIndex) const
Definition MPMSystemData-Impl.hpp:451
double FLIPBlendingFactor() const
Returns the FLIP fraction used for grid-to-particle transfer.
Definition MPMSystemData-Impl.hpp:271
void TransferFromGridToParticles()
Definition MPMSystemData-Impl.hpp:367
void ValidateGridToParticleState() const
Definition MPMSystemData-Impl.hpp:374
void Set(const ParticleSystemData< N > &other) override
Copies inherited particle state and resets transfer state.
Definition MPMSystemData-Impl.hpp:189
void Deserialize(const std::vector< uint8_t > &buffer) override
Deserializes inherited particle state and resets transfer state.
Definition MPMSystemData-Impl.hpp:182
static Vector< size_t, N > ClampIndex(const Vector< ssize_t, N > &index, const Vector< size_t, N > &dataSize)
Definition MPMSystemData-Impl.hpp:484
void ResizeGrid(const Vector< size_t, N > &resolution, const Vector< double, N > &gridSpacing, const Vector< double, N > &gridOrigin)
Resizes the background grid without changing particle state.
Definition MPMSystemData-Impl.hpp:196
MPMTransferSystemData(const Vector< size_t, N > &resolution=Vector< size_t, N >::MakeConstant(1), const Vector< double, N > &gridSpacing=Vector< double, N >::MakeConstant(1.0), const Vector< double, N > &gridOrigin=Vector< double, N >{}, size_t numberOfParticles=0)
Constructs transfer state with a vertex-centered background grid.
Definition MPMSystemData-Impl.hpp:162
static bool IsFinite(const Vector< double, N > &value)
Definition MPMSystemData-Impl.hpp:501
Definition Matrix.hpp:30
Definition pybind11Utils.hpp:22
void ForEachIndex(const Vector< IndexType, N > &begin, const Vector< IndexType, N > &end, const Func &func)
Definition IterationUtils-Impl.hpp:51
Matrix< T, Rows, 1 > Vector
Definition Matrix.hpp:648