iMSTK
Interactive Medical Simulation Toolkit
imstkTearable.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 "imstkCellMesh.h"
8 #include "imstkParallelUtils.h"
9 #include "imstkPbdConstraint.h"
10 #include "imstkPbdConstraintContainer.h"
11 #include "imstkPbdModel.h"
12 #include "imstkPbdObject.h"
13 #include "imstkPbdObjectCellRemoval.h"
14 #include "imstkPbdSolver.h"
15 #include "imstkTaskGraph.h"
16 #include "imstkTaskNode.h"
17 #include "imstkTearable.h"
18 
19 namespace imstk
20 {
21 Tearable::Tearable(const std::string& name) : SceneBehaviour(true, name)
22 {
23  m_tearableHandleNode = std::make_shared<TaskNode>([this]()
24  {
25  handleTearable();
26  }, "TearableHandle");
27 }
28 
29 void
31 {
32  m_tearableObject = std::dynamic_pointer_cast<PbdObject>(getEntity().lock());
33 
34  CHECK(m_tearableObject != nullptr) << "Tearable requires a input PBD object,"
35  "please add it on creation";
36 
37  // Create cell remover for removing torn cells
38  m_cellRemover = std::make_shared<PbdObjectCellRemoval>(m_tearableObject);
39 
40  // Add task nodes
41  m_taskGraph->addNode(m_tearableHandleNode);
42  m_taskGraph->addNode(m_tearableObject->getPbdModel()->getUpdateVelocityNode());
43  m_taskGraph->addNode(m_tearableObject->getPbdModel()->getTaskGraph()->getSink());
44 }
45 
46 void
48 {
49  // Check that the cellConstraintMap exists, if not make it
50  if (m_tearableObject->getPbdBody()->cellConstraintMap.empty())
51  {
52  m_tearableObject->computeCellConstraintMap();
53  }
54 
55  // Get body id
56  auto pbdBody = m_tearableObject->getPbdBody();
57  int bodyId = m_tearableObject->getPbdBody()->bodyHandle;
58 
59  // Mesh data
60  auto cellMesh = std::dynamic_pointer_cast<AbstractCellMesh>(m_tearableObject->getPhysicsGeometry());
61  auto cellVerts = std::dynamic_pointer_cast<DataArray<int>>(cellMesh->getAbstractCells()); // underlying 1D array
62  const int vertsPerCell = cellMesh->getAbstractCells()->getNumberOfComponents();
63 
64  // Check the strain state of the cell and remove if strain is greater than max strain
66  ParallelUtils::parallelFor(cellMesh->getNumCells(),
67  [&](const int cellId)
68  {
69  std::vector<std::shared_ptr<PbdConstraint>> constraints = m_tearableObject->getCellConstraints(cellId);
70 
71  bool remove = false;
72  for (int constraintId = 0; constraintId < constraints.size(); constraintId++)
73  {
74  // check that constraint only involves this body
75  const std::vector<PbdParticleId>& cVertexIds = constraints[constraintId]->getParticles();
76 
77  // Check that constraint involves this body and get associated vertices
78  bool isBody = true;
79  for (int cVertId = 0; cVertId < cVertexIds.size(); cVertId++)
80  {
81  if (cVertexIds[cVertId].first != bodyId)
82  {
83  isBody = false;
84  }
85  }
86 
87  double strain = 0.0;
88  double constraintC = constraints[constraintId]->getConstraintC();
89  double constraintRef = constraints[constraintId]->getRestValue();
90 
91  // Some constraints have a reference state of 0, dividing by zero is bad(TM) so
92  // use constraint value without normalizing to a strain like measure (length/length)
93  if (fabs(constraintRef) <= 1E-7)
94  {
95  strain = constraintC;
96  }
97  else
98  {
99  strain = constraintC / constraintRef;
100  }
101 
102  if (strain > m_maxStrain)
103  {
104  remove = true;
105  break;
106  }
107  }
108  if (remove == true)
109  {
110  lock.lock();
111  m_cellRemover->removeCellOnApply(cellId);
112  pbdBody->cellConstraintMap.erase(cellId);
113  lock.unlock();
114  }
115  }, cellMesh->getNumCells() > 50);
116 
117  m_cellRemover->apply();
118 }
119 
120 void
121 Tearable::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
122 {
123  // Add the cell removal check after the constraints have all been solved
124  m_taskGraph->addEdge(source, m_tearableObject->getPbdModel()->getUpdateVelocityNode());
125  m_taskGraph->addEdge(m_tearableObject->getPbdModel()->getUpdateVelocityNode(), m_tearableHandleNode);
126  m_taskGraph->addEdge(m_tearableHandleNode, m_tearableObject->getPbdModel()->getTaskGraph()->getSink());
127  m_taskGraph->addEdge(m_tearableObject->getPbdModel()->getTaskGraph()->getSink(), sink);
128 }
129 } // namespace imstk
The SpinLock class.
Definition: imstkSpinLock.h:20
void unlock()
End a thread-safe region.
Definition: imstkSpinLock.h:53
virtual int getNumberOfComponents() const override
Returns the number of components.
void init() override
Initialize the component, called at a later time after all component construction is complete...
Compound Geometry.
std::weak_ptr< Entity > getEntity() const
Get parent entity.
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
Base class for scene objects that move and/or deform under position based dynamics formulation...
Simple dynamic array implementation that also supports event posting and viewing/facade.
Provides non templated base for cell based meshes.