11#ifndef CUBBYFLOW_SNOW_MPM_SOLVER_IMPL_HPP
12#define CUBBYFLOW_SNOW_MPM_SOLVER_IMPL_HPP
105 if (!std::isfinite(radius) || radius < 0.0 || !std::isfinite(
mass) ||
108 throw std::invalid_argument{
"Invalid snow MPM particle parameters." };
111 m_mpmSystemData->SetRadius(radius);
112 m_mpmSystemData->SetMass(
mass);
113 this->SetParticleSystemData(m_mpmSystemData);
114 this->SetIsUsingFixedSubTimeSteps(
false);
120 return m_mpmSystemData;
126 return m_timeStepLimitScale;
134 throw std::invalid_argument{
135 "Time-step limit scale must be in (0, 1]."
145 return m_isUsingSemiImplicit;
151 m_isUsingSemiImplicit =
isUsing;
157 return m_maxNumberOfIterations;
176 if (!std::isfinite(tolerance) || tolerance <= 0.0)
178 throw std::invalid_argument{
179 "Semi-implicit tolerance must be positive and finite."
183 m_tolerance = tolerance;
189 return m_lastNumberOfIterations;
195 return m_lastResidual;
201 return m_closedDomainBoundaryFlag;
207 m_closedDomainBoundaryFlag =
flag;
219 Base::OnInitialize();
220 m_mpmSystemData->TransferFromParticlesToGrid();
221 InitializeReferenceVolumes();
222 m_maxVelocityGradient = ComputeMaxVelocityGradient();
227 double timeIntervalInSeconds)
const
229 if (!std::isfinite(timeIntervalInSeconds) || timeIntervalInSeconds <= 0.0)
234 const auto velocities = m_mpmSystemData->Velocities();
235 const auto masses = m_mpmSystemData->ParticleMasses();
236 const auto volumes = m_mpmSystemData->InitialVolumes();
237 const auto states = m_mpmSystemData->DeformationStates();
238 const auto spacing = m_mpmSystemData->GridMass().GridSpacing();
259 throw std::invalid_argument{
"Invalid snow reference volume." };
263 std::max(
maxWaveSpeed, m_constitutiveModel.ComputeWaveSpeed(
276 if (m_maxVelocityGradient > 0.0)
287 const double count = std::ceil(timeIntervalInSeconds /
290 static_cast<double>(std::numeric_limits<unsigned int>::max());
292 return static_cast<unsigned int>(std::clamp(
count, 1.0,
maxCount));
304 m_mpmSystemData->TransferFromParticlesToGrid();
305 InitializeReferenceVolumes();
311 BuildActiveNodes(&activeNodes, &nodeToActive);
315 ConstrainGridVelocities(activeNodes, nodeToActive, &constrained);
317 if (m_isUsingSemiImplicit)
321 ConstrainGridVelocities(activeNodes, nodeToActive,
nullptr);
325 m_lastNumberOfIterations = 0;
326 m_lastResidual = 0.0;
330 m_mpmSystemData->TransferFromGridToParticles();
337 ConstrainParticlesToDomain();
348 result[
axis] =
static_cast<size_t>(std::clamp<ssize_t>(
356void SnowMPMSolver<N>::InitializeReferenceVolumes()
358 const auto positions = m_mpmSystemData->Positions();
359 const auto masses = m_mpmSystemData->ParticleMasses();
360 auto volumes = m_mpmSystemData->InitialVolumes();
361 const auto&
gridMass = m_mpmSystemData->GridMass();
374 throw std::invalid_argument{
"Invalid snow MPM cell volume." };
383 throw std::invalid_argument{
"Invalid snow reference volume." };
400 throw std::invalid_argument{
"Invalid snow reference density." };
410 const auto positions = m_mpmSystemData->Positions();
411 const auto velocities = m_mpmSystemData->Velocities();
412 const auto masses = m_mpmSystemData->ParticleMasses();
413 const auto volumes = m_mpmSystemData->InitialVolumes();
414 const auto states = m_mpmSystemData->DeformationStates();
415 const auto&
gridMass = m_mpmSystemData->GridMass();
426 masses[i] * this->GetGravity() -
429 m_constitutiveModel.ComputeKirchhoffStress(
states[i]);
435 if (
entry.weight == 0.0)
458 const auto&
gridMass = m_mpmSystemData->GridMass();
461 activeNodes->Clear();
466 nodeToActive](
const SizeType& index) {
469 (*nodeToActive)[
dataView.Index(index)] =
470 static_cast<ssize_t>(activeNodes->Length());
471 activeNodes->Append(index);
477void SnowMPMSolver<N>::ConstrainGridVelocities(
481 const auto&
gridMass = m_mpmSystemData->GridMass();
485 if (constrained !=
nullptr)
487 constrained->Resize(activeNodes.Length() *
N,
uint8_t{ 0 });
492 [
this, constrained, &
gridMass, &nodeToActive,
506 ConstrainGridVelocityAtNode(index,
static_cast<size_t>(
active),
512void SnowMPMSolver<N>::ConstrainGridVelocityAtNode(
const SizeType& index,
519 ApplyGridColliderConstraint(index,
active, constrained, &velocity);
520 ApplyGridDomainConstraint(index,
active, constrained, &velocity);
526void SnowMPMSolver<N>::ApplyGridColliderConstraint(
const SizeType& index,
529 VectorType* velocity)
const
531 const auto collider = this->GetCollider();
538 const VectorType
incoming = *velocity;
540 m_mpmSystemData->GridVelocities().DataPosition()(index);
544 if (constrained !=
nullptr && *velocity !=
incoming)
554void SnowMPMSolver<N>::ApplyGridDomainConstraint(
const SizeType& index,
557 VectorType* velocity)
const
563 const auto dataSize = m_mpmSystemData->GridVelocities().DataSize();
569 index[
axis] == 0 && (*velocity)[
axis] < 0.0;
576 (*velocity)[
axis] = 0.0;
578 if (constrained !=
nullptr)
588SnowMPMSolver<N>::ComputeParticleDeformationDifferential(
592 const auto&
gridMass = m_mpmSystemData->GridMass();
599 if (
entry.weight == 0.0)
635void SnowMPMSolver<N>::AccumulateParticleHessian(
640 const auto&
gridMass = m_mpmSystemData->GridMass();
646 if (
entry.weight == 0.0)
664 (*output)[
static_cast<size_t>(
active) *
N +
axis] +=
671void SnowMPMSolver<N>::ApplyElasticHessian(
const Array1<SizeType>& activeNodes,
676 const auto positions = m_mpmSystemData->Positions();
677 const auto volumes = m_mpmSystemData->InitialVolumes();
678 const auto states = m_mpmSystemData->DeformationStates();
679 const auto&
gridMass = m_mpmSystemData->GridMass();
683 output->Resize(activeNodes.Length() *
N, 0.0);
690 const MatrixType
differential = ComputeParticleDeformationDifferential(
693 m_constitutiveModel.ComputeFirstPiolaStressDifferential(
703VectorND SnowMPMSolver<N>::GatherActiveGridVelocities(
723VectorND SnowMPMSolver<N>::BuildSemiImplicitRightHandSide(
736 if (constrained[i] == 0)
746VectorND SnowMPMSolver<N>::SolveGridVelocityCorrection(
751 const LinearSystem system{
this, &activeNodes, &nodeToActive, &constrained,
770VectorND SnowMPMSolver<N>::ComputeGridVelocityUpdate(
775 const VectorND vStar = GatherActiveGridVelocities(activeNodes);
776 const VectorND rhs = BuildSemiImplicitRightHandSide(
777 dtSquared, activeNodes, nodeToActive, constrained,
vStar);
782 m_lastResidual = std::numeric_limits<double>::infinity();
783 throw std::runtime_error{
784 "Semi-implicit snow solve failed to converge."
793 SolveGridVelocityCorrection(dtSquared, activeNodes, nodeToActive,
797 if (
const bool isFinite = std::ranges::all_of(
798 result, [](
double value) {
return std::isfinite(value); });
799 !
isFinite || !std::isfinite(m_lastResidual) ||
800 m_lastResidual > m_tolerance)
802 throw std::runtime_error{
803 "Semi-implicit snow solve failed to converge."
811void SnowMPMSolver<N>::StoreActiveGridVelocities(
837 m_mpmSystemData->GridVelocitiesBeforeUpdate();
839 m_lastNumberOfIterations = 0;
840 m_lastResidual = 0.0;
844 if (!activeNodes.IsEmpty())
862 const auto positions = m_mpmSystemData->Positions();
872 if (
entry.weight != 0.0)
874 const VectorType velocity =
891double SnowMPMSolver<N>::ComputeMaxVelocityGradient()
const
895 for (
size_t i = 0; i < m_mpmSystemData->NumberOfParticles(); ++i)
906 auto states = m_mpmSystemData->DeformationStates();
907 m_maxVelocityGradient = 0.0;
912 m_maxVelocityGradient =
914 states[i] = m_constitutiveModel.Update(
921void SnowMPMSolver<N>::ConstrainParticlesToDomain()
927 const auto domain = m_mpmSystemData->GridMass().GetBoundingBox();
928 auto positions = m_mpmSystemData->Positions();
929 auto velocities = m_mpmSystemData->Velocities();
934 for (size_t axis = 0; axis < N; ++axis)
936 if ((m_closedDomainBoundaryFlag & lowerFlags[axis]) != 0 &&
937 positions[i][axis] <= domain.lowerCorner[axis])
939 positions[i][axis] = domain.lowerCorner[axis];
940 velocities[i][axis] = std::max(velocities[i][axis], 0.0);
942 if ((m_closedDomainBoundaryFlag & upperFlags[axis]) != 0 &&
943 positions[i][axis] >= domain.upperCorner[axis])
945 positions[i][axis] = domain.upperCorner[axis];
946 velocities[i][axis] = std::min(velocities[i][axis], 0.0);
993 return SnowMPMSolver{ m_resolution, m_gridSpacing, m_gridOrigin, m_radius,
1000 return std::make_shared<SnowMPMSolver>(m_resolution, m_gridSpacing,
1001 m_gridOrigin, m_radius, m_mass);
static Stencil GetStencil(const Vector< double, N > &position, const Vector< double, N > &gridSpacing, const Vector< double, N > &dataOrigin)
Definition MPMSystemData-Impl.hpp:137
N-D material point method particle and grid state.
Definition MPMSystemData.hpp:72
Definition Matrix.hpp:526
ValueType Length() const
Definition MatrixExpression-Impl.hpp:278
MatrixTranspose< T, Rows, Cols, const Derived & > Transposed() const
Definition MatrixExpression-Impl.hpp:365
ValueType AbsMax() const
Definition MatrixExpression-Impl.hpp:162
void Fill(const T &val)
Definition Matrix-Impl.hpp:226
constexpr size_t GetRows() const
Definition Matrix-Impl.hpp:260
Front-end to create SnowMPMSolver objects step by step.
Definition SnowMPMSolver.hpp:216
N-D material point method solver for snow.
Definition SnowMPMSolver.hpp:43
unsigned int GetNumberOfSubTimeSteps(double timeIntervalInSeconds) const override
Returns the number of adaptive sub-time-steps.
Definition SnowMPMSolver-Impl.hpp:226
SnowMPMSolver(const SizeType &resolution=SizeType::MakeConstant(32), const VectorType &gridSpacing=VectorType::MakeConstant(1.0), const VectorType &gridOrigin=VectorType{}, double radius=1e-3, double mass=1e-3)
Constructs an empty snow MPM solver.
Definition SnowMPMSolver-Impl.hpp:97
double GetTolerance() const
Returns the relative conjugate-residual tolerance.
Definition SnowMPMSolver-Impl.hpp:168
double GetTimeStepLimitScale() const
Returns the scale applied to adaptive time-step limits.
Definition SnowMPMSolver-Impl.hpp:124
void AccumulateForces(double timeStepInSeconds) override
Snow forces are integrated on the background grid.
Definition SnowMPMSolver-Impl.hpp:296
void OnEndAdvanceTimeStep(double timeStepInSeconds) override
Projects particles back into selected closed domain boundaries.
Definition SnowMPMSolver-Impl.hpp:334
unsigned int GetMaxNumberOfIterations() const
Returns the maximum conjugate-residual iteration count.
Definition SnowMPMSolver-Impl.hpp:155
Matrix< double, N, N > MatrixType
Definition SnowMPMSolver.hpp:49
void OnInitialize() override
Initializes particle-grid state before the first adaptive step query.
Definition SnowMPMSolver-Impl.hpp:217
bool GetIsUsingSemiImplicit() const
Returns whether the elastic grid update is semi-implicit.
Definition SnowMPMSolver-Impl.hpp:143
void SetClosedDomainBoundaryFlag(int flag)
Sets the closed domain boundary flag.
Definition SnowMPMSolver-Impl.hpp:205
void SetIsUsingSemiImplicit(bool isUsing)
Enables or disables the semi-implicit elastic grid update.
Definition SnowMPMSolver-Impl.hpp:149
void SetMaxNumberOfIterations(unsigned int maxNumberOfIterations)
Definition SnowMPMSolver-Impl.hpp:161
double GetLastResidual() const
Returns the relative residual from the last semi-implicit solve.
Definition SnowMPMSolver-Impl.hpp:193
std::conditional_t< N==2, ParticleSystemSolver2, ParticleSystemSolver3 > Base
Definition SnowMPMSolver.hpp:48
int GetClosedDomainBoundaryFlag() const
Returns the closed domain boundary flag.
Definition SnowMPMSolver-Impl.hpp:199
void OnBeginAdvanceTimeStep(double timeStepInSeconds) override
Advances particle-grid snow state before base particle integration.
Definition SnowMPMSolver-Impl.hpp:302
unsigned int GetLastNumberOfIterations() const
Returns the iteration count from the last semi-implicit solve.
Definition SnowMPMSolver-Impl.hpp:187
void SetTimeStepLimitScale(double newScale)
Sets the adaptive time-step scale in (0, 1].
Definition SnowMPMSolver-Impl.hpp:130
std::shared_ptr< MPMSystemData< N > > GetMPMSystemData() const
Returns the owned MPM particle and grid state.
Definition SnowMPMSolver-Impl.hpp:118
static Builder GetBuilder()
Returns a builder for SnowMPMSolver.
Definition SnowMPMSolver-Impl.hpp:211
void SetTolerance(double tolerance)
Sets the positive finite tolerance relative to the initial residual.
Definition SnowMPMSolver-Impl.hpp:174
Definition pybind11Utils.hpp:22
constexpr size_t ZERO_SIZE
Zero size_t.
Definition Constants.hpp:20
constexpr int DIRECTION_UP
Up direction.
Definition Constants.hpp:323
constexpr int DIRECTION_RIGHT
Right direction.
Definition Constants.hpp:317
VectorN< double > VectorND
Definition Matrix.hpp:742
constexpr int DIRECTION_LEFT
Left direction.
Definition Constants.hpp:314
void ParallelFor(IndexType beginIndex, IndexType endIndex, const Function &function, ExecutionPolicy policy)
Makes a for-loop from beginIndex to endIndex in parallel.
Definition Parallel-Impl.hpp:203
constexpr int DIRECTION_BACK
Back direction.
Definition Constants.hpp:326
Matrix< T, Rows, 1 > Vector
Definition Matrix.hpp:648
constexpr int DIRECTION_FRONT
Front direction.
Definition Constants.hpp:329
constexpr int DIRECTION_DOWN
Down direction.
Definition Constants.hpp:320
Generic BLAS operator wrapper class.
Definition BLAS.hpp:29
Definition SnowMPMSolver-Impl.hpp:38
static void MVM(const System &system, const VectorND &vector, VectorND *result)
Definition SnowMPMSolver-Impl.hpp:42
static void Residual(const System &system, const VectorND &x, const VectorND &b, VectorND *result)
Definition SnowMPMSolver-Impl.hpp:48
Definition SnowMPMSolver-Impl.hpp:26
const SnowMPMSolver * solver
Definition SnowMPMSolver-Impl.hpp:27
double dtSquared
Definition SnowMPMSolver-Impl.hpp:31
const Array1< uint8_t > * constrained
Definition SnowMPMSolver-Impl.hpp:30
const Array1< ssize_t > * nodeToActive
Definition SnowMPMSolver-Impl.hpp:29
const Array1< SizeType > * activeNodes
Definition SnowMPMSolver-Impl.hpp:28
void Multiply(const VectorND &input, VectorND *output) const
Definition SnowMPMSolver-Impl.hpp:57