iMSTK
Interactive Medical Simulation Toolkit
imstkSphCollisionHandling.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkSphCollisionHandling.h"
8 #include "imstkCollisionData.h"
9 #include "imstkCollisionDetectionAlgorithm.h"
10 #include "imstkParallelFor.h"
11 #include "imstkSphModel.h"
12 #include "imstkSphObject.h"
13 
14 namespace imstk
15 {
16 void
17 SphCollisionHandling::setInputSphObject(std::shared_ptr<SphObject> sphObj)
18 {
19  setInputObjectA(sphObj);
20 }
21 
22 void
24  const std::vector<CollisionElement>& elementsA,
25  const std::vector<CollisionElement>& imstkNotUsed(elementsB))
26 {
27  std::shared_ptr<SphObject> obj = std::dynamic_pointer_cast<SphObject>(getInputObjectA());
28  std::shared_ptr<SphModel> sphModel = obj->getSphModel();
29 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
30  LOG_IF(FATAL, (!sphModel)) << "SPH model was not initialized";
31 #endif
32 
33  m_boundaryFriction = sphModel->getParameters()->m_frictionBoundary;
34 #if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
35  LOG_IF(FATAL, (m_boundaryFriction<0.0 || m_boundaryFriction>1.0))
36  << "Invalid boundary friction coefficient (value must be in [0, 1])";
37 #endif
38 
39  std::shared_ptr<SphState> state = sphModel->getCurrentState();
40  std::shared_ptr<VecDataArray<double, 3>> positionsPtr = state->getPositions();
41  std::shared_ptr<VecDataArray<double, 3>> velocitiesPtr = state->getVelocities();
42  VecDataArray<double, 3>& positions = *positionsPtr;
43  VecDataArray<double, 3>& velocities = *velocitiesPtr;
44 
45  // Solve analytical collision
46  for (int i = 0; i < m_iterations; i++)
47  {
48  // Coming into this CH, CD has already been computed
49  if (i != 0 && m_colDetect != nullptr)
50  {
51  // Update the collision geometry
52  obj->updateGeometries();
53  // Compute collision again
54  m_colDetect->update();
55  }
56 
57  ParallelUtils::parallelFor(elementsA.size(), [&](const size_t j)
58  {
59  const CollisionElement& colElem = elementsA[j];
60  if (colElem.m_type == CollisionElementType::PointIndexDirection)
61  {
62  const int particleIndex = colElem.m_element.m_PointIndexDirectionElement.ptIndex;
63  const Vec3d& n = -colElem.m_element.m_PointIndexDirectionElement.dir;
64  const double depth = colElem.m_element.m_PointIndexDirectionElement.penetrationDepth;
65  solve(positions[particleIndex], velocities[particleIndex], n * depth);
66  }
67  });
68  }
69 }
70 
71 void
72 SphCollisionHandling::solve(Vec3d& pos, Vec3d& velocity, const Vec3d& penetrationVector)
73 {
74  // Correct particle position
75  pos -= penetrationVector;
76 
77  const auto nLengthSqr = penetrationVector.squaredNorm();
78  if (nLengthSqr < 1.0e-20) // Normalize n
79  {
80  return; // Too little penetration: ignore
81  }
82  const Vec3d n = penetrationVector / std::sqrt(nLengthSqr);
83 
84  // Correct particle velocity: slip boundary condition with friction
85  const Vec3d oldVel = velocity;
86  const double vn = oldVel.dot(n);
87 
88  // If particle is escaping the boundary, ignore it
89  if (vn > 0)
90  {
91  Vec3d correctedVel = oldVel - vn * n; // From now, vel is parallel with the solid surface
92 
93  if (m_boundaryFriction > 1.0e-20)
94  {
95  const double velLength = correctedVel.norm();
96  const double frictionLength = vn * m_boundaryFriction; // This is always positive
97  if (frictionLength < velLength && velLength > 1.0e-10)
98  {
99  correctedVel -= (correctedVel / velLength) * frictionLength; // Subtract a friction from velocity, which is proportional to the amount of penetration
100  }
101  else
102  {
103  correctedVel = Vec3d::Zero();
104  }
105  }
106 
107  velocity = correctedVel;
108  }
109 }
110 } // end namespace imstk
void setInputObjectA(std::shared_ptr< CollidingObject > objectA)
Set the input objects.
void solve(Vec3d &pos, Vec3d &velocity, const Vec3d &penetrationVector)
Solves positiona and corrects velocity of individual particle.
Compound Geometry.
Base class for scene objects that move and/or deform under smooth particle hydrodynamics.
Union of collision elements. We use a union to avoid polymorphism. There may be many elements and acc...
std::shared_ptr< CollidingObject > getInputObjectA() const
Get the input objects.
std::shared_ptr< SphModel > getSphModel()
Get the model governing the Sph fluid dynamics of this object.
void handle(const std::vector< CollisionElement > &elementsA, const std::vector< CollisionElement > &elementsB) override
Resolve SPH particle positions.