iMSTK
Interactive Medical Simulation Toolkit
imstkPenaltyCH.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 "imstkPenaltyCH.h"
8 #include "imstkCollisionData.h"
9 #include "imstkFeDeformableObject.h"
10 #include "imstkFemDeformableBodyModel.h"
11 #include "imstkParallelUtils.h"
12 #include "imstkRbdConstraint.h"
13 #include "imstkRigidObject2.h"
14 
15 namespace imstk
16 {
17 void
18 PenaltyCH::setInputFeObject(std::shared_ptr<FeDeformableObject> feObj)
19 {
20  setInputObjectA(feObj);
21 }
22 
23 void
24 PenaltyCH::setInputRbdObject(std::shared_ptr<RigidObject2> rbdObj)
25 {
26  setInputObjectB(rbdObj);
27 }
28 
29 std::shared_ptr<FeDeformableObject>
30 PenaltyCH::getInputFeObject()
31 {
32  return std::dynamic_pointer_cast<FeDeformableObject>(getInputObjectA());
33 }
34 
35 std::shared_ptr<RigidObject2>
36 PenaltyCH::getInputRbdObject()
37 {
38  return std::dynamic_pointer_cast<RigidObject2>(getInputObjectB());
39 }
40 
41 void
43  const std::vector<CollisionElement>& elementsA,
44  const std::vector<CollisionElement>& elementsB)
45 {
46  auto deformableObj = std::dynamic_pointer_cast<FeDeformableObject>(getInputObjectA());
47  auto rbdObj = std::dynamic_pointer_cast<RigidObject2>(getInputObjectB());
48 
49  if (deformableObj != nullptr)
50  {
51  this->computeContactForcesDiscreteDeformable(elementsA, deformableObj);
52  }
53  if (rbdObj != nullptr)
54  {
55  this->computeContactForcesAnalyticRigid(elementsB, rbdObj);
56  }
57  else
58  {
59  LOG(FATAL) << "no penalty collision handling available for " << getInputObjectA()->getName()
60  << " (rigid mesh not yet supported).";
61  }
62 }
63 
64 void
66  const std::vector<CollisionElement>& elements,
67  std::shared_ptr<RigidObject2> analyticObj)
68 {
69  if (elements.empty())
70  {
71  return;
72  }
73 
74  // Sum forces (only supports PointDirection contacts)
75  Vec3d force = Vec3d::Zero();
76  for (size_t i = 0; i < elements.size(); i++)
77  {
78  const CollisionElement& elem = elements[i];
79  if (elem.m_type == CollisionElementType::PointDirection)
80  {
81  const Vec3d dir = elem.m_element.m_PointDirectionElement.dir;
82  const double penetrationDepth = elem.m_element.m_PointDirectionElement.penetrationDepth;
83  force += dir * ((penetrationDepth + 1.0) * (penetrationDepth + 1.0) - 1.0) * 10.0;
84  }
85  }
86 
87  // Apply as external force
88  *analyticObj->getRigidBody()->m_force = force;
89 }
90 
91 void
93  const std::vector<CollisionElement>& elements,
94  std::shared_ptr<FeDeformableObject> deformableObj)
95 {
96  if (elements.empty())
97  {
98  return;
99  }
100 
101  // Get current force vector
102  std::shared_ptr<FemDeformableBodyModel> model = deformableObj->getFEMModel();
103  Vectord& force = model->getContactForce();
104  const Vectord& velVector = model->getCurrentState()->getQDot();
105 
106  // If collision data, append forces
108  ParallelUtils::parallelFor(elements.size(),
109  [&](const size_t i)
110  {
111  const CollisionElement& elem = elements[i];
112  if (elem.m_type == CollisionElementType::PointIndexDirection)
113  {
114  const Vec3d dir = elem.m_element.m_PointDirectionElement.dir;
115  const double penetrationDepth = elem.m_element.m_PointDirectionElement.penetrationDepth;
116  const int ptIndex = elem.m_element.m_PointIndexDirectionElement.ptIndex;
117 
118  const Vec3d penetrationVector = dir * penetrationDepth;
119  const Eigen::Index nodeDofID = static_cast<Eigen::Index>(3 * ptIndex);
120 
121  Vec3d velocityProjection = Vec3d(velVector(nodeDofID),
122  velVector(nodeDofID + 1),
123  velVector(nodeDofID + 2));
124  velocityProjection = velocityProjection.dot(dir) * penetrationVector;
125 
126  const Vec3d nodalForce = -m_stiffness * penetrationVector - m_damping * velocityProjection;
127 
128  lock.lock();
129  force(nodeDofID) += nodalForce.x();
130  force(nodeDofID + 1) += nodalForce.y();
131  force(nodeDofID + 2) += nodalForce.z();
132  lock.unlock();
133  }
134  });
135 }
136 } // end namespace imstk
The SpinLock class.
Definition: imstkSpinLock.h:20
void unlock()
End a thread-safe region.
Definition: imstkSpinLock.h:53
void setInputObjectA(std::shared_ptr< CollidingObject > objectA)
Set the input objects.
double m_stiffness
Stiffness of contact.
Compound Geometry.
void computeContactForcesDiscreteDeformable(const std::vector< CollisionElement > &elements, std::shared_ptr< FeDeformableObject > deformableObj)
Given the collision data, applies nodal forces in the FEM model.
Union of collision elements. We use a union to avoid polymorphism. There may be many elements and acc...
void lock()
Start a thread-safe region, where only one thread can execute at a time until a call to the unlock fu...
Definition: imstkSpinLock.h:45
void handle(const std::vector< CollisionElement > &elementsA, const std::vector< CollisionElement > &elementsB) override
Handle the input collision data. Elements will be flipped (if needed) such that elementsA corresponds...
void computeContactForcesAnalyticRigid(const std::vector< CollisionElement > &elements, std::shared_ptr< RigidObject2 > analyticObj)
Given the collision data, applies contact as external force to the rigid body (onyl supports PointDir...
Scene objects that can deform.
std::shared_ptr< CollidingObject > getInputObjectA() const
Get the input objects.
Scene objects that are governed by rigid body dynamics under the RigidBodyModel2. ...
double m_damping
Damping of the contact.