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
21namespace CubbyFlow
22{
23template <size_t N>
25{
26 const double ax = std::abs(x);
27
28 if (ax < 1.0)
29 {
30 return 0.5 * ax * ax * ax - ax * ax + 2.0 / 3.0;
31 }
32
33 if (ax < 2.0)
34 {
35 const double d = 2.0 - ax;
36 return d * d * d / 6.0;
37 }
38
39 return 0.0;
40}
41
42template <size_t N>
44{
45 const double ax = std::abs(x);
46
47 if (ax < 1.0)
48 {
49 return x * (1.5 * ax - 2.0);
50 }
51
52 if (ax < 2.0)
53 {
54 const double d = 2.0 - ax;
55 return -0.5 * d * d * std::copysign(1.0, x);
56 }
57
58 return 0.0;
59}
60
61template <size_t N>
66{
67 for (size_t axis = 0; axis < N; ++axis)
68 {
69 if (!std::isfinite(position[axis]) ||
70 !std::isfinite(gridSpacing[axis]) ||
71 !std::isfinite(dataOrigin[axis]) || gridSpacing[axis] <= 0.0)
72 {
73 throw std::invalid_argument("Invalid cubic B-spline input.");
74 }
75
76 (*normalized)[axis] =
78
79 const double lowestIndex = std::nextafter(
80 static_cast<double>(std::numeric_limits<ssize_t>::lowest()) + 1.0,
81 0.0);
82 if (const double highestIndex = std::nextafter(
83 static_cast<double>(std::numeric_limits<ssize_t>::max()) - 2.0,
84 0.0);
85 !std::isfinite((*normalized)[axis]) ||
86 (*normalized)[axis] < lowestIndex ||
87 (*normalized)[axis] > highestIndex)
88 {
89 throw std::invalid_argument(
90 "Cubic B-spline index is out of range.");
91 }
92
93 (*firstIndex)[axis] =
94 static_cast<ssize_t>(std::floor((*normalized)[axis])) - 1;
95 }
96}
97
98template <size_t N>
99CubicBSplineKernel<N>::Entry CubicBSplineKernel<N>::GetStencilEntry(
102{
103 Entry entry;
104 std::array<double, N> axisWeights;
105
106 entry.weight = 1.0;
107
108 for (size_t axis = 0; axis < N; ++axis)
109 {
110 entry.index[axis] =
111 firstIndex[axis] + static_cast<ssize_t>(offset[axis]);
113 Weight(normalized[axis] - static_cast<double>(entry.index[axis]));
114 entry.weight *= axisWeights[axis];
115 }
116
117 for (size_t axis = 0; axis < N; ++axis)
118 {
119 entry.gradient[axis] =
120 Gradient(normalized[axis] -
121 static_cast<double>(entry.index[axis])) /
123
124 for (size_t other = 0; other < N; ++other)
125 {
126 if (other != axis)
127 {
128 entry.gradient[axis] *= axisWeights[other];
129 }
130 }
131 }
132
133 return entry;
134}
135
136template <size_t N>
159
160template <size_t N>
170
171template <size_t N>
173{
174 Base::Resize(newNumberOfParticles);
175
176 m_particleMasses.Resize(newNumberOfParticles, Base::Mass());
177 m_initialVolumes.Resize(newNumberOfParticles, 0.0);
178 m_deformationStates.Resize(newNumberOfParticles, DeformationState{});
179}
180
181template <size_t N>
182void MPMSystemData<N>::Deserialize(const std::vector<uint8_t>& buffer)
183{
184 Base::Deserialize(buffer);
185 ResetMPMState();
186}
187
188template <size_t N>
190{
191 Base::Set(other);
192 ResetMPMState();
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>
234{
235 return m_deformationStates.View();
236}
237
238template <size_t N>
241{
242 return m_deformationStates.View();
243}
244
245template <size_t N>
247{
248 return m_gridMass;
249}
250
251template <size_t N>
253{
254 return m_gridMass;
255}
256
257template <size_t N>
259{
260 return m_gridVelocities;
261}
262
263template <size_t N>
265{
266 return m_gridVelocities;
267}
268
269template <size_t N>
272{
273 return m_gridVelocitiesBeforeUpdate;
274}
275
276template <size_t N>
278{
279 return m_gridVelocitiesBeforeUpdate;
280}
281
282template <size_t N>
284{
285 return m_flipBlendingFactor;
286}
287
288template <size_t N>
290{
291 if (!std::isfinite(factor) || factor < 0.0 || factor > 1.0)
292 {
293 throw std::invalid_argument("FLIP blending factor must be in [0, 1].");
294 }
295
296 m_flipBlendingFactor = factor;
297}
298
299template <size_t N>
301{
302 ValidateGridState();
303
304 const auto positions = this->Positions();
305 const auto velocities = this->Velocities();
306
307 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
308 {
309 if (!std::isfinite(m_particleMasses[i]) || m_particleMasses[i] <= 0.0 ||
310 !IsFinite(positions[i]) || !IsFinite(velocities[i]))
311 {
312 throw std::invalid_argument("Invalid MPM particle state.");
313 }
314 }
315
316 m_gridMass.Fill(0.0, ExecutionPolicy::Serial);
317 m_gridVelocities.Fill(Vector<double, N>{}, ExecutionPolicy::Serial);
318
319 const auto dataSize = m_gridMass.DataSize();
320 const auto gridSpacing = m_gridMass.GridSpacing();
321 const auto dataOrigin = m_gridMass.DataOrigin();
322
323 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
324 {
327
328 for (const auto& entry : stencil)
329 {
330 if (entry.weight == 0.0)
331 {
332 continue;
333 }
334
335 const auto index = ClampIndex(entry.index, dataSize);
336 const double mass = entry.weight * m_particleMasses[i];
337
338 m_gridMass(index) += mass;
339 m_gridVelocities(index) += mass * velocities[i];
340 }
341 }
342
343 m_gridMass.ForEachDataPointIndex([this](const Vector<size_t, N>& index) {
344 const double mass = m_gridMass(index);
345 if (mass > 0.0)
346 {
347 m_gridVelocities(index) /= mass;
348 }
349 });
350
351 m_gridVelocitiesBeforeUpdate.Set(m_gridVelocities);
352}
353
354template <size_t N>
356{
357 ValidateGridState();
358
359 const auto positions = this->Positions();
360 auto velocities = this->Velocities();
361
362 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
363 {
364 if (!IsFinite(positions[i]) || !IsFinite(velocities[i]))
365 {
366 throw std::invalid_argument("Invalid MPM particle state.");
367 }
368 }
369
370 m_gridVelocities.ForEachDataPointIndex(
371 [this](const Vector<size_t, N>& index) {
372 if (!IsFinite(m_gridVelocities(index)) ||
373 !IsFinite(m_gridVelocitiesBeforeUpdate(index)))
374 {
375 throw std::invalid_argument("Invalid MPM grid velocity.");
376 }
377 });
378
379 const auto dataSize = m_gridVelocities.DataSize();
380 const auto gridSpacing = m_gridVelocities.GridSpacing();
381 const auto dataOrigin = m_gridVelocities.DataOrigin();
382
383 for (size_t i = 0; i < this->NumberOfParticles(); ++i)
384 {
389
390 for (const auto& entry : stencil)
391 {
392 if (entry.weight == 0.0)
393 {
394 continue;
395 }
396
397 const auto index = ClampIndex(entry.index, dataSize);
398 picVelocity += entry.weight * m_gridVelocities(index);
399 flipDelta += entry.weight * (m_gridVelocities(index) -
400 m_gridVelocitiesBeforeUpdate(index));
401 }
402
405 (1.0 - m_flipBlendingFactor) * picVelocity +
406 m_flipBlendingFactor * flipVelocity;
407
408 velocities[i] = result;
409 }
410}
411
412template <size_t N>
414 const Vector<ssize_t, N>& index, const Vector<size_t, N>& dataSize)
415{
417
418 for (size_t axis = 0; axis < N; ++axis)
419 {
420 result[axis] = index[axis] < 0
421 ? 0
422 : std::min(static_cast<size_t>(index[axis]),
423 dataSize[axis] - 1);
424 }
425
426 return result;
427}
428
429template <size_t N>
430bool MPMSystemData<N>::IsFinite(const Vector<double, N>& value)
431{
432 for (size_t axis = 0; axis < N; ++axis)
433 {
434 if (!std::isfinite(value[axis]))
435 {
436 return false;
437 }
438 }
439
440 return true;
441}
442
443template <size_t N>
444void MPMSystemData<N>::ValidateGridParameters(
447{
448 for (size_t axis = 0; axis < N; ++axis)
449 {
450 if (resolution[axis] == 0 ||
451 resolution[axis] == std::numeric_limits<size_t>::max() ||
452 !std::isfinite(gridSpacing[axis]) || gridSpacing[axis] <= 0.0 ||
453 !std::isfinite(gridOrigin[axis]))
454 {
455 throw std::invalid_argument("Invalid MPM grid parameters.");
456 }
457 }
458}
459
460template <size_t N>
461void MPMSystemData<N>::ValidateGridState() const
462{
463 ValidateGridParameters(m_gridMass.Resolution(), m_gridMass.GridSpacing(),
464 m_gridMass.Origin());
465 ValidateGridParameters(m_gridVelocities.Resolution(),
466 m_gridVelocities.GridSpacing(),
467 m_gridVelocities.Origin());
468 ValidateGridParameters(m_gridVelocitiesBeforeUpdate.Resolution(),
469 m_gridVelocitiesBeforeUpdate.GridSpacing(),
470 m_gridVelocitiesBeforeUpdate.Origin());
471
472 if (m_gridMass.Resolution() != m_gridVelocities.Resolution() ||
473 m_gridMass.Resolution() != m_gridVelocitiesBeforeUpdate.Resolution() ||
474 m_gridMass.GridSpacing() != m_gridVelocities.GridSpacing() ||
475 m_gridMass.GridSpacing() !=
476 m_gridVelocitiesBeforeUpdate.GridSpacing() ||
477 m_gridMass.Origin() != m_gridVelocities.Origin() ||
478 m_gridMass.Origin() != m_gridVelocitiesBeforeUpdate.Origin())
479 {
480 throw std::invalid_argument("MPM grids must have matching geometry.");
481 }
482}
483
484template <size_t N>
485void MPMSystemData<N>::ResetMPMState()
486{
487 m_particleMasses.Fill(Base::Mass());
488 m_initialVolumes.Fill(0.0);
489 m_deformationStates.Fill(DeformationState{});
490 m_gridMass.Fill(0.0, ExecutionPolicy::Serial);
491 m_gridVelocities.Fill(Vector<double, N>{}, ExecutionPolicy::Serial);
492 m_gridVelocitiesBeforeUpdate.Fill(Vector<double, N>{},
494}
495} // namespace CubbyFlow
496
497#endif
Tensor-product cubic B-spline interpolation kernel.
Definition MPMSystemData.hpp:28
static double Weight(double x)
Definition MPMSystemData-Impl.hpp:24
static Stencil GetStencil(const Vector< double, N > &position, const Vector< double, N > &gridSpacing, const Vector< double, N > &dataOrigin)
Definition MPMSystemData-Impl.hpp:137
static double Gradient(double x)
Definition MPMSystemData-Impl.hpp:43
std::array< Entry, STENCIL_SIZE > Stencil
Definition MPMSystemData.hpp:41
N-D material point method particle and grid state.
Definition MPMSystemData.hpp:72
ConstArrayView1< DeformationState > DeformationStates() const
Returns per-particle deformation states.
Definition MPMSystemData-Impl.hpp:233
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
void SetFLIPBlendingFactor(double factor)
Sets the FLIP fraction used for grid-to-particle transfer.
Definition MPMSystemData-Impl.hpp:289
void Set(const ParticleSystemData< N > &other) override
Copies inherited particle state and resets MPM-specific state.
Definition MPMSystemData-Impl.hpp:189
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 MPM state with a vertex-centered background grid.
Definition MPMSystemData-Impl.hpp:161
const VertexCenteredVectorGrid< N > & GridVelocities() const
Returns current grid velocities.
Definition MPMSystemData-Impl.hpp:258
void TransferFromGridToParticles()
Definition MPMSystemData-Impl.hpp:355
void TransferFromParticlesToGrid()
Definition MPMSystemData-Impl.hpp:300
void Deserialize(const std::vector< uint8_t > &buffer) override
Deserializes inherited particle state and resets MPM-specific state.
Definition MPMSystemData-Impl.hpp:182
const VertexCenteredScalarGrid< N > & GridMass() const
Returns grid mass.
Definition MPMSystemData-Impl.hpp:246
ConstArrayView1< double > InitialVolumes() const
Returns per-particle initial volumes.
Definition MPMSystemData-Impl.hpp:220
ConstArrayView1< double > ParticleMasses() const
Returns per-particle masses.
Definition MPMSystemData-Impl.hpp:208
const VertexCenteredVectorGrid< N > & GridVelocitiesBeforeUpdate() const
Returns grid velocities before the grid update.
Definition MPMSystemData-Impl.hpp:271
void Resize(size_t newNumberOfParticles) override
Resizes particle state, initializing new MPM attributes.
Definition MPMSystemData-Impl.hpp:172
double FLIPBlendingFactor() const
Returns the FLIP fraction used for grid-to-particle transfer.
Definition MPMSystemData-Impl.hpp:283
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