iMSTK
Interactive Medical Simulation Toolkit
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Pages
imstkFemDeformableBodyModel.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 "imstkFemDeformableBodyModel.h"
8 #include "imstkConjugateGradient.h"
9 #include "imstkCorotationalFemForceModel.h"
10 #include "imstkIsotropicHyperelasticFeForceModel.h"
11 #include "imstkLinearFemForceModel.h"
12 #include "imstkLogger.h"
13 #include "imstkNewtonSolver.h"
14 #include "imstkPointSet.h"
15 #include "imstkTaskGraph.h"
16 #include "imstkTimeIntegrator.h"
17 #include "imstkTypes.h"
18 #include "imstkVecDataArray.h"
19 #include "imstkVegaMeshIO.h"
20 #include "imstkVolumetricMesh.h"
21 
22 DISABLE_WARNING_PUSH
23  DISABLE_WARNING_HIDES_CLASS_MEMBER
24 #include "imstkStVKForceModel.h"
25 
26 #include <generateMassMatrix.h>
27 #include <generateMeshGraph.h>
28 #include <configFile.h>
29 
30 DISABLE_WARNING_POP
31 #include <fstream>
32 
33 namespace imstk
34 {
35 FemDeformableBodyModel::FemDeformableBodyModel() :
36  DynamicalModel(DynamicalModelType::ElastoDynamics)
37 {
38  m_fixedNodeIds.reserve(1000);
39 
40  m_validGeometryTypes = { "TetrahedralMesh", "HexahedralMesh" };
41 
42  m_solveNode = m_taskGraph->addFunction("FEMModel_Solve", [&]() { getSolver()->solve(); });
43 }
44 
45 FemDeformableBodyModel::~FemDeformableBodyModel()
46 {
47  // Get vega to destruct first (before the shared pointer to the vega mesh is cleaned up)
48  m_internalForceModel = nullptr;
49 }
50 
51 void
52 FemDeformableBodyModel::configure(const std::string& configFileName)
53 {
54  // Configure the FEMModelConfig
55  m_FEModelConfig = std::make_shared<FemModelConfig>();
56 
57  char femMethod[256];
58  char invertibleMaterial[256];
59  char fixedDOFFilename[256];
60 
61  vega::ConfigFile vegaConfigFileOptions;
62 
63  // configure the options
64  vegaConfigFileOptions.addOptionOptional("femMethod", femMethod, "StVK");
65  vegaConfigFileOptions.addOptionOptional("invertibleMaterial", invertibleMaterial, "StVK");
66  vegaConfigFileOptions.addOptionOptional("fixedDOFFilename", fixedDOFFilename, "");
67  vegaConfigFileOptions.addOptionOptional("dampingMassCoefficient", &m_FEModelConfig->m_dampingMassCoefficient, m_FEModelConfig->m_dampingMassCoefficient);
68  vegaConfigFileOptions.addOptionOptional("dampingStiffnessCoefficient", &m_FEModelConfig->m_dampingStiffnessCoefficient, m_FEModelConfig->m_dampingStiffnessCoefficient);
69  vegaConfigFileOptions.addOptionOptional("dampingLaplacianCoefficient", &m_FEModelConfig->m_dampingLaplacianCoefficient, m_FEModelConfig->m_dampingLaplacianCoefficient);
70  vegaConfigFileOptions.addOptionOptional("deformationCompliance", &m_FEModelConfig->m_deformationCompliance, m_FEModelConfig->m_deformationCompliance);
71  vegaConfigFileOptions.addOptionOptional("compressionResistance", &m_FEModelConfig->m_compressionResistance, m_FEModelConfig->m_compressionResistance);
72  vegaConfigFileOptions.addOptionOptional("inversionThreshold", &m_FEModelConfig->m_inversionThreshold, m_FEModelConfig->m_inversionThreshold);
73  vegaConfigFileOptions.addOptionOptional("gravity", &m_FEModelConfig->m_gravity, m_FEModelConfig->m_gravity);
74 
75  // Parse the configuration file
76  CHECK(vegaConfigFileOptions.parseOptions(configFileName.data()) == 0)
77  << "ForceModelConfig::parseConfig - Unable to load the configuration file";
78 
79  // get the root directory of the boundary file name
80  std::string rootDir;
81  const size_t last_slash_idx = configFileName.rfind('/');
82  if (std::string::npos != last_slash_idx)
83  {
84  rootDir = configFileName.substr(0, last_slash_idx);
85  }
86 
87  // Set fem method
88  if (std::strcmp(femMethod, "StVK") == 0)
89  {
90  m_FEModelConfig->m_femMethod = FeMethodType::StVK;
91  }
92  else if (std::strcmp(femMethod, "CLFEM") == 0)
93  {
94  m_FEModelConfig->m_femMethod = FeMethodType::Corotational;
95  }
96  else if (std::strcmp(femMethod, "Linear") == 0)
97  {
98  m_FEModelConfig->m_femMethod = FeMethodType::Linear;
99  }
100  else if (std::strcmp(femMethod, "InvertibleFEM") == 0)
101  {
102  m_FEModelConfig->m_femMethod = FeMethodType::Invertible;
103  }
104  else
105  {
106  LOG(WARNING) << "FE method not assigned; will default to StVK";
107  m_FEModelConfig->m_femMethod = FeMethodType::StVK;
108  }
109 
110  // Set up hyperelastic material type
111  if (std::strcmp(invertibleMaterial, "StVK") == 0)
112  {
113  m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::StVK;
114  }
115  else if (std::strcmp(invertibleMaterial, "NeoHookean") == 0)
116  {
117  m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::NeoHookean;
118  }
119  else if (std::strcmp(invertibleMaterial, "MooneyRivlin") == 0)
120  {
121  m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::MooneyRivlin;
122  }
123  else
124  {
125  LOG(INFO) << "Hyperelastic material type not assigned; will default to StVK";
126  m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::StVK;
127  }
128 
129  // file names (remove from here?)
130  m_FEModelConfig->m_fixedDOFFilename = rootDir + std::string("/") + std::string(fixedDOFFilename);
131 }
132 
133 void
134 FemDeformableBodyModel::configure(std::shared_ptr<FemModelConfig> config)
135 {
136  m_FEModelConfig = config;
137 }
138 
139 bool
140 FemDeformableBodyModel::initialize()
141 {
142  // prerequisite of for successfully initializing
143  CHECK(m_geometry != nullptr && m_FEModelConfig != nullptr) << "DeformableBodyModel::initialize: Physics mesh or force model configuration not set yet!";
144  std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(m_geometry);
145  // If there isn't already a displacements array for the geometry
146  if (!pointSet->hasVertexAttribute("displacements"))
147  {
148  pointSet->setVertexAttribute("displacements", std::make_shared<VecDataArray<double, 3>>(pointSet->getNumVertices()));
149  }
150 
151  // Setup default solver if model doesn't yet have one
152  if (m_solver == nullptr)
153  {
154  // Create a nonlinear system
155  // auto nlSystem = std::make_shared<NonLinearSystem<SparseMatrixd>>(getFunction(), getFunctionGradient());
156  auto nlSystem = std::make_shared<NonLinearSystem<SparseMatrixd>>(getFunction(), getFunctionGradient(), getFunctionAndGradient());
157 
158  nlSystem->setUnknownVector(getUnknownVec());
159  nlSystem->setUpdateFunction(getUpdateFunction());
160  nlSystem->setUpdatePreviousStatesFunction(getUpdatePrevStateFunction());
161 
162  // Create a linear solver
163  auto linSolver = std::make_shared<ConjugateGradient>();
164 
166  && isFixedBCImplemented())
167  {
168  LOG(WARNING) << "The GS solver may not be viable!";
169  }
170 
171  // Create a non-linear solver and add to the scene
172  auto nlSolver = std::make_shared<NewtonSolver<SparseMatrixd>>();
173  nlSolver->setToSemiImplicit();
174  nlSolver->setLinearSolver(linSolver);
175  nlSolver->setSystem(nlSystem);
176  setSolver(nlSolver);
177  }
178 
179  auto physicsMesh = std::dynamic_pointer_cast<AbstractCellMesh>(this->getModelGeometry());
180  m_vegaPhysicsMesh = VegaMeshIO::convertVolumetricMeshToVegaMesh(physicsMesh);
181  //m_vegaPhysicsMesh = physicsMesh->getAttachedVegaMesh();
182  if (!this->initializeForceModel()
183  || !this->initializeMassMatrix()
184  || !this->initializeDampingMatrix()
185  || !this->initializeTangentStiffness()
186  || !this->loadBoundaryConditions()
187  || !this->initializeGravityForce()
188  || !this->initializeExplicitExternalForces())
189  {
190  return false;
191  }
192 
193  this->loadInitialStates();
194 
195  m_Feff.resize(m_numDof);
196  m_Finternal.resize(m_numDof);
197  m_Finternal.setConstant(0.0);
198  m_Fcontact.resize(m_numDof);
199  m_Fcontact.setConstant(0.0);
200  m_qSol.resize(m_numDof);
201  m_qSol.setConstant(0.0);
202 
203  return true;
204 }
205 
206 void
207 FemDeformableBodyModel::loadInitialStates()
208 {
209  if (m_numDof == 0)
210  {
211  LOG(WARNING) << "Number of degree of freedom is zero!";
212  }
213 
214  // For now the initial states are set to zero
215  m_initialState = std::make_shared<kinematicState>(m_numDof);
216  m_previousState = std::make_shared<kinematicState>(m_numDof);
217  m_currentState = std::make_shared<kinematicState>(m_numDof);
218 }
219 
220 bool
221 FemDeformableBodyModel::loadBoundaryConditions()
222 {
223  auto fileName = m_FEModelConfig->m_fixedDOFFilename;
224 
225  if (fileName.empty())
226  {
227  // if the list of fixed nodes are set, use them
228  for (auto p:m_FEModelConfig->m_fixedNodeIds)
229  {
230  m_fixedNodeIds.emplace_back(p);
231  }
232  }
233  else
234  {
235  std::ifstream file(fileName.data());
236 
237  if (file.peek() == std::ifstream::traits_type::eof())
238  {
239  LOG(INFO) << "The external boundary conditions file is empty";
240  }
241 
242  if (file.is_open())
243  {
244  size_t index;
245  size_t maxAllowed = m_vegaPhysicsMesh->getNumVertices();
246  while (!file.eof())
247  {
248  file >> index;
249  if (index < maxAllowed)
250  {
251  m_fixedNodeIds.emplace_back(index);
252  }
253  else
254  {
255  LOG(WARNING) << "The boundary condition node id provided is greater than number of nodes and hence excluded!!";
256  return false;
257  }
258  }
259 
260  file.close();
261  std::sort(m_fixedNodeIds.begin(), m_fixedNodeIds.end()); // for efficiency
262  }
263  else
264  {
265  LOG(FATAL) << "Could not open boundary conditions file!";
266  return false;
267  }
268  }
269  return true;
270 }
271 
272 bool
273 FemDeformableBodyModel::initializeForceModel()
274 {
275  const double g = m_FEModelConfig->m_gravity;
276  // Since vega 4.0 doesn't add gravity correcntly in all cases, we do it ourselves; see \ref initializeGravityForce
277  // const bool isGravityPresent = (g > 0) ? true : false;
278  const bool isGravityPresent = false;
279 
280  m_numDof = (size_t)m_vegaPhysicsMesh->getNumVertices() * 3;
281 
282  switch (m_FEModelConfig->m_femMethod)
283  {
284  case FeMethodType::StVK:
285 
286  m_internalForceModel = std::make_shared<StvkForceModel>(m_vegaPhysicsMesh, isGravityPresent, g);
287  break;
288 
289  case FeMethodType::Linear:
290 
291  m_internalForceModel = std::make_shared<LinearFemForceModel>(m_vegaPhysicsMesh, isGravityPresent, g);
292  break;
293 
294  case FeMethodType::Corotational:
295 
296  m_internalForceModel = std::make_shared<CorotationalFemForceModel>(m_vegaPhysicsMesh);
297  break;
298 
299  case FeMethodType::Invertible:
300 
301  m_internalForceModel = std::make_shared<IsotropicHyperelasticFeForceModel>(
302  m_FEModelConfig->m_hyperElasticMaterialType,
303  m_vegaPhysicsMesh,
304  -MAX_D,
305  isGravityPresent,
306  g);
307  break;
308 
309  default:
310  LOG(FATAL) << "Unknown force model type";
311  return false;
312  } //switch
313 
314  return true;
315 }
316 
317 bool
318 FemDeformableBodyModel::initializeMassMatrix()
319 {
320  CHECK(m_geometry != nullptr) << "Force model geometry not set!";
321 
322  vega::SparseMatrix* vegaMatrix;
323  vega::GenerateMassMatrix::computeMassMatrix(m_vegaPhysicsMesh.get(), &vegaMatrix, true); //caveat
324 
325  m_vegaMassMatrix.reset(vegaMatrix);
326 
327  this->initializeEigenMatrixFromVegaMatrix(*vegaMatrix, m_M);
328 
330 
331  return true;
332 }
333 
334 bool
335 FemDeformableBodyModel::initializeDampingMatrix()
336 {
337  auto dampingLaplacianCoefficient = m_FEModelConfig->m_dampingLaplacianCoefficient;
338  auto dampingMassCoefficient = m_FEModelConfig->m_dampingMassCoefficient;
339  auto dampingStiffnessCoefficient = m_FEModelConfig->m_dampingStiffnessCoefficient;
340 
341  if (dampingStiffnessCoefficient == 0.0 && dampingLaplacianCoefficient == 0.0 && dampingMassCoefficient == 0.0)
342  {
343  LOG(WARNING) << "All the damping parameters are zero!";
344  return true;
345  }
346 
347  if (dampingLaplacianCoefficient < 0.0)
348  {
349  LOG(WARNING) << "Damping coefficient is negative!";
350  return false;
351  }
352 
353  //auto imstkVolMesh = std::static_pointer_cast<VolumetricMesh>(m_geometry);
354  //std::shared_ptr<vega::VolumetricMesh> vegaMesh = VegaMeshReader::getVegaVolumeMeshFromVolumeMesh(imstkVolMesh);
355 
356  auto meshGraph = std::make_shared<vega::Graph>(*vega::GenerateMeshGraph::Generate(m_vegaPhysicsMesh.get()));
357 
358  if (!meshGraph)
359  {
360  LOG(WARNING) << "Mesh graph not avaliable!";
361  return false;
362  }
363 
364  vega::SparseMatrix* matrix;
365  meshGraph->GetLaplacian(&matrix, 1);
366 
367  if (!matrix)
368  {
369  LOG(WARNING) << "Mesh Laplacian not avaliable!";
370  return false;
371  }
372 
373  matrix->ScalarMultiply(dampingLaplacianCoefficient);
374 
375  m_vegaDampingMatrix.reset(matrix);
376 
377  this->initializeEigenMatrixFromVegaMatrix(*matrix, m_C);
378 
379  m_damped = true;
380 
381  return true;
382 }
383 
384 bool
385 FemDeformableBodyModel::initializeTangentStiffness()
386 {
387  CHECK(m_internalForceModel != nullptr)
388  << "Tangent stiffness cannot be initialized without force model";
389 
390  vega::SparseMatrix* matrix = nullptr;
391  m_internalForceModel->getTangentStiffnessMatrixTopology(&matrix);
392 
393  CHECK(matrix != nullptr) << "Tangent stiffness matrix topology not avaliable!";
394  CHECK(m_vegaMassMatrix != nullptr) << "Vega mass matrix doesn't exist!";
395 
396  matrix->BuildSubMatrixIndices(*m_vegaMassMatrix.get());
397 
398  if (m_vegaDampingMatrix)
399  {
400  matrix->BuildSubMatrixIndices(*m_vegaDampingMatrix.get(), 1);
401  }
402 
403  m_vegaTangentStiffnessMatrix.reset(matrix);
404 
405  this->initializeEigenMatrixFromVegaMatrix(*matrix, m_K);
406 
407  if (m_damped)
408  {
409  const auto& dampingStiffnessCoefficient = m_FEModelConfig->m_dampingStiffnessCoefficient;
410  const auto& dampingMassCoefficient = m_FEModelConfig->m_dampingMassCoefficient;
411 
412  // Initialize the Raleigh damping matrix
413  m_C = dampingMassCoefficient * m_M + dampingStiffnessCoefficient * m_K;
414  }
415 
416  m_internalForceModel->setTangentStiffness(m_vegaTangentStiffnessMatrix);
417 
418  return true;
419 }
420 
421 bool
422 FemDeformableBodyModel::initializeGravityForce()
423 {
424  m_Fgravity.resize(m_numDof);
425  m_Fgravity.setZero();
426  const double gravity = m_FEModelConfig->m_gravity;
427 
428  m_vegaPhysicsMesh->computeGravity(m_Fgravity.data(), gravity);
429 
430  return true;
431 }
432 
433 void
434 FemDeformableBodyModel::computeImplicitSystemRHS(kinematicState& stateAtT,
435  kinematicState& newState,
436  const StateUpdateType updateType)
437 {
438  const auto& uPrev = stateAtT.getQ();
439  const auto& vPrev = stateAtT.getQDot();
440  auto& u = newState.getQ();
441  const auto& v = newState.getQDot();
442 
443  // Do checks if there are uninitialized matrices
444  const double dT = m_timeIntegrator->getTimestepSize();
445 
446  switch (updateType)
447  {
448  case StateUpdateType::DeltaVelocity:
449 
450  m_internalForceModel->getTangentStiffnessMatrix(u, m_K);
451  m_Feff = m_K * -(uPrev - u + v * dT);
452 
453  if (m_damped)
454  {
455  m_Feff -= m_C * v;
456  }
457 
458  m_internalForceModel->getInternalForce(u, m_Finternal);
459  m_Feff -= m_Finternal;
460  m_Feff += m_FexplicitExternal;
461  m_Feff += m_Fgravity;
462  m_Feff += m_Fcontact;
463  m_Feff *= dT;
464  m_Feff += m_M * (vPrev - v);
465 
466  break;
467  default:
468  LOG(WARNING) << "Update type not supported";
469  }
470 }
471 
472 void
473 FemDeformableBodyModel::computeSemiImplicitSystemRHS(kinematicState& stateAtT,
474  kinematicState& newState,
475  const StateUpdateType updateType)
476 {
477  //auto& uPrev = stateAtT.getQ();
478  const auto& vPrev = stateAtT.getQDot();
479  auto& u = newState.getQ();
480  //auto& v = newState.getQDot();
481 
482  // Do checks if there are uninitialized matrices
483  m_internalForceModel->getTangentStiffnessMatrix(u, m_K);
484  const double dT = m_timeIntegrator->getTimestepSize();
485 
486  switch (updateType)
487  {
488  case StateUpdateType::DeltaVelocity:
489 
490  m_Feff = m_K * (vPrev * -dT);
491 
492  if (m_damped)
493  {
494  m_Feff -= m_C * vPrev;
495  }
496 
497  m_internalForceModel->getInternalForce(u, m_Finternal);
498  m_Feff -= m_Finternal;
499  m_Feff += m_FexplicitExternal;
500  m_Feff += m_Fgravity;
501  m_Feff += m_Fcontact;
502  m_Feff *= dT;
503 
504  break;
505 
506  default:
507  LOG(FATAL) << "Update type not supported";
508  }
509 }
510 
511 void
512 FemDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& imstkNotUsed(stateAtT),
513  kinematicState& newState,
514  const StateUpdateType updateType)
515 {
516  const double dT = m_timeIntegrator->getTimestepSize();
517 
518  switch (updateType)
519  {
520  case StateUpdateType::DeltaVelocity:
521  this->updateMassMatrix();
522  m_internalForceModel->getTangentStiffnessMatrix(newState.getQ(), m_K);
523  this->updateDampingMatrix();
524 
525  m_Keff = m_M;
526  if (m_damped)
527  {
528  m_Keff += dT * m_C;
529  }
530  m_Keff += (dT * dT) * m_K;
531 
532  break;
533 
534  default:
535  LOG(FATAL) << "Update type not supported";
536  }
537 }
538 
539 void
540 FemDeformableBodyModel::computeSemiImplicitSystemRHSAndLHS(kinematicState& stateAtT,
541  kinematicState& newState,
542  const StateUpdateType updateType)
543 {
544  const auto& vPrev = stateAtT.getQDot();
545  const double dT = m_timeIntegrator->getTimestepSize();
546 
547  switch (updateType)
548  {
549  case StateUpdateType::DeltaVelocity:
550  // LHS
551  this->updateMassMatrix();
552  m_internalForceModel->getForceAndMatrix(newState.getQ(), m_Finternal, m_K);
553  this->updateDampingMatrix();
554 
555  m_Keff = m_M;
556  if (m_damped)
557  {
558  m_Keff += dT * m_C;
559  }
560  m_Keff += (dT * dT) * m_K;
561 
562  // RHS
563  m_Feff = m_K * (vPrev * -dT);
564 
565  if (m_damped)
566  {
567  m_Feff -= m_C * vPrev;
568  }
569 
570  m_Feff -= m_Finternal;
571  m_Feff += m_FexplicitExternal;
572  m_Feff += m_Fgravity;
573  m_Feff += m_Fcontact;
574  m_Feff *= dT;
575 
576  break;
577 
578  default:
579  LOG(FATAL) << "Update type not supported";
580  }
581 }
582 
583 void
584 FemDeformableBodyModel::computeImplicitSystemRHSAndLHS(kinematicState& stateAtT,
585  kinematicState& newState,
586  const StateUpdateType updateType)
587 {
588  const auto& uPrev = stateAtT.getQ();
589  const auto& vPrev = stateAtT.getQDot();
590  auto& u = newState.getQ();
591  const auto& v = newState.getQDot();
592  const double dT = m_timeIntegrator->getTimestepSize();
593 
594  switch (updateType)
595  {
596  case StateUpdateType::DeltaVelocity:
597  // LHS
598  this->updateMassMatrix();
599  m_internalForceModel->getForceAndMatrix(u, m_Finternal, m_K);
600  this->updateDampingMatrix();
601 
602  m_Keff = m_M;
603  if (m_damped)
604  {
605  m_Keff += dT * m_C;
606  }
607  m_Keff += (dT * dT) * m_K;
608 
609  // RHS
610  m_Feff = m_K * -(uPrev - u + v * dT);
611 
612  if (m_damped)
613  {
614  m_Feff -= m_C * v;
615  }
616 
617  m_Feff -= m_Finternal;
618  m_Feff += m_FexplicitExternal;
619  m_Feff += m_Fgravity;
620  m_Feff += m_Fcontact;
621  m_Feff *= dT;
622  m_Feff += m_M * (vPrev - v);
623  break;
624 
625  default:
626  LOG(FATAL) << "Update type not supported";
627  }
628 }
629 
630 bool
631 FemDeformableBodyModel::initializeExplicitExternalForces()
632 {
633  m_FexplicitExternal.resize(m_numDof);
634  m_FexplicitExternal.setZero();
635 
636  return true;
637 }
638 
639 void
640 FemDeformableBodyModel::updateDampingMatrix()
641 {
642  if (m_damped)
643  {
644  const auto& dampingStiffnessCoefficient = m_FEModelConfig->m_dampingStiffnessCoefficient;
645  const auto& dampingMassCoefficient = m_FEModelConfig->m_dampingMassCoefficient;
646 
647  if (dampingMassCoefficient > 0)
648  {
649  m_C = dampingMassCoefficient * m_M;
650 
651  if (dampingStiffnessCoefficient > 0)
652  {
653  m_C += m_K * dampingStiffnessCoefficient;
654  }
655  }
656  else if (dampingStiffnessCoefficient > 0)
657  {
658  m_C = m_K * dampingStiffnessCoefficient;
659  }
660  }
661 }
662 
663 void
664 FemDeformableBodyModel::applyBoundaryConditions(SparseMatrixd& M, const bool withCompliance) const
665 {
666  double compliance = withCompliance ? 1.0 : 0.0;
667 
668  // Set column and row to zero.
669  for (auto& index : m_fixedNodeIds)
670  {
671  auto nodeIdx = static_cast<SparseMatrixd::Index>(index) * 3;
672 
673  for (auto idx = nodeIdx; idx < nodeIdx + 3; idx++)
674  {
675  for (long long k = 0; k < M.outerSize(); ++k)
676  {
677  for (SparseMatrixd::InnerIterator i(M, k); i; ++i)
678  {
679  if (i.row() == idx || i.col() == idx)
680  {
681  i.valueRef() = 0.0;
682  }
683 
684  if (i.row() == idx && i.col() == idx)
685  {
686  i.valueRef() = compliance;
687  }
688  }
689  }
690  }
691  }
692 }
693 
694 void
695 FemDeformableBodyModel::applyBoundaryConditions(Vectord& x) const
696 {
697  for (auto& index : m_fixedNodeIds)
698  {
699  const auto _3Index = 3 * index;
700  x(_3Index) = x(_3Index + 1) = x(_3Index + 2) = 0.0;
701  }
702 }
703 
704 void
705 FemDeformableBodyModel::updateMassMatrix()
706 {
707  // Do nothing for now as topology changes are not supported yet!
708 }
709 
710 void
711 FemDeformableBodyModel::updatePhysicsGeometry()
712 {
713  auto volMesh = std::dynamic_pointer_cast<PointSet>(m_geometry);
714  auto& u = m_currentState->getQ();
715  std::shared_ptr<VecDataArray<double, 3>> displacementsPtr =
716  std::dynamic_pointer_cast<VecDataArray<double, 3>>(volMesh->getVertexAttribute("displacements"));
717  std::copy_n(u.data(), displacementsPtr->size() * 3, reinterpret_cast<double*>(displacementsPtr->getVoidPointer()));
718 
719  const VecDataArray<double, 3>& initPositions = *volMesh->getVertexPositions(Geometry::DataType::PreTransform);
720  VecDataArray<double, 3>& positions = *volMesh->getVertexPositions();
721  const VecDataArray<double, 3>& displacements = *displacementsPtr;
722  for (int i = 0; i < displacementsPtr->size(); i++)
723  {
724  positions[i] = initPositions[i] + displacements[i];
725  }
726 }
727 
728 void
729 FemDeformableBodyModel::updateBodyPreviousStates()
730 {
731  m_previousState->setU(m_currentState->getQ());
732  m_previousState->setV(m_currentState->getQDot());
733 }
734 
735 void
736 FemDeformableBodyModel::updateBodyStates(const Vectord& solution, const StateUpdateType updateType)
737 {
738  this->updateBodyPreviousStates();
739  this->updateBodyIntermediateStates(solution, updateType);
740 }
741 
742 void
743 FemDeformableBodyModel::updateBodyIntermediateStates(
744  const Vectord& solution,
745  const StateUpdateType updateType)
746 {
747  const auto& uPrev = m_previousState->getQ();
748  //auto& u = m_currentState->getQ();
749  const auto& v = m_currentState->getQDot();
750  const double dT = m_timeIntegrator->getTimestepSize();
751 
752  switch (updateType)
753  {
754  case StateUpdateType::DeltaVelocity:
755  m_currentState->setV(v + solution);
756  m_currentState->setU(uPrev + dT * v);
757 
758  break;
759 
760  case StateUpdateType::Velocity:
761  m_currentState->setV(solution);
762  m_currentState->setU(uPrev + dT * v);
763 
764  break;
765 
766  default:
767  LOG(FATAL) << "Unknown state update type";
768  }
769  m_qSol = m_currentState->getQ();
770 }
771 
772 NonLinearSystem<SparseMatrixd>::VectorFunctionType
773 FemDeformableBodyModel::getFunction()
774 {
775 #ifdef WIN32
776 #pragma warning( push )
777 #pragma warning( disable : 4100 )
778 #endif
779 
780  // Function to evaluate the nonlinear objective function given the current state
781  return [&, this](const Vectord& q, const bool semiImplicit) -> const Vectord&
782  {
783  (semiImplicit) ?
784  this->computeSemiImplicitSystemRHS(*m_previousState.get(), *m_currentState.get(), m_updateType) :
785  this->computeImplicitSystemRHS(*m_previousState.get(), *m_currentState.get(), m_updateType);
786  if (this->m_implementFixedBC)
787  {
788  applyBoundaryConditions(m_Feff);
789  }
790  return m_Feff;
791  };
792 #ifdef WIN32
793 #pragma warning( pop )
794 #endif
795 }
796 
797 NonLinearSystem<SparseMatrixd>::MatrixFunctionType
798 FemDeformableBodyModel::getFunctionGradient()
799 {
800 #ifdef WIN32
801 #pragma warning( push )
802 #pragma warning( disable : 4100 )
803 #endif
804  // Gradient of the nonlinear objective function given the current state
805  return [&, this](const Vectord& q) -> const SparseMatrixd&
806  {
807  this->computeImplicitSystemLHS(*m_previousState.get(), *m_currentState.get(), m_updateType);
808 
809  if (this->m_implementFixedBC)
810  {
811  applyBoundaryConditions(m_Keff);
812  }
813  return m_Keff;
814  };
815 #ifdef WIN32
816 #pragma warning( pop )
817 #endif
818 }
819 
820 NonLinearSystem<SparseMatrixd>::VectorMatrixFunctionType
821 FemDeformableBodyModel::getFunctionAndGradient()
822 {
823 #ifdef WIN32
824 #pragma warning( push )
825 #pragma warning( disable : 4100 )
826 #endif
827 
828  // Function to evaluate the nonlinear objective function given the current state
829  // return [&, this](const Vectord& q, const bool semiImplicit) -> NonLinearSolver<SparseMatrixd>::VecMatPair
830  return [&, this](const Vectord& q, const bool semiImplicit)
831  {
832  (semiImplicit) ?
833  this->computeSemiImplicitSystemRHSAndLHS(*m_previousState.get(), *m_currentState.get(), m_updateType) :
834  this->computeImplicitSystemRHSAndLHS(*m_previousState.get(), *m_currentState.get(), m_updateType);
835  if (this->m_implementFixedBC)
836  {
837  applyBoundaryConditions(m_Feff);
838  applyBoundaryConditions(m_Keff);
839  }
840  return std::make_pair(&m_Feff, &m_Keff);
841  };
842 #ifdef WIN32
843 #pragma warning( pop )
844 #endif
845 }
846 
847 NonLinearSystem<SparseMatrixd>::UpdateFunctionType
848 FemDeformableBodyModel::getUpdateFunction()
849 {
850  // Function to evaluate the nonlinear objective function given the current state
851  return [&, this](const Vectord& q, const bool fullyImplicit) -> void
852  {
853  (fullyImplicit) ?
854  this->updateBodyIntermediateStates(q, m_updateType) :
855  this->updateBodyStates(q, m_updateType);
856  };
857 }
858 
859 NonLinearSystem<SparseMatrixd>::UpdatePrevStateFunctionType
860 FemDeformableBodyModel::getUpdatePrevStateFunction()
861 {
862  // Function to evaluate the nonlinear objective function given the current state
863  return [&, this]() -> void
864  {
865  this->updateBodyPreviousStates();
866  };
867 }
868 
869 void
870 FemDeformableBodyModel::initializeEigenMatrixFromVegaMatrix(const vega::SparseMatrix& vegaMatrix,
871  SparseMatrixd& eigenMatrix)
872 {
873  auto rowLengths = vegaMatrix.GetRowLengths();
874  auto nonZeroValues = vegaMatrix.GetEntries();
875  auto columnIndices = vegaMatrix.GetColumnIndices();
876 
877  std::vector<Eigen::Triplet<double>> triplets;
878  triplets.reserve(vegaMatrix.GetNumEntries());
879  for (int i = 0, end = vegaMatrix.GetNumRows(); i < end; ++i)
880  {
881  for (int k = 0, k_end = rowLengths[i]; k < k_end; ++k)
882  {
883  triplets.emplace_back(i, columnIndices[i][k], nonZeroValues[i][k]);
884  }
885  }
886  eigenMatrix.resize(vegaMatrix.GetNumRows(), vegaMatrix.GetNumColumns());
887  eigenMatrix.setFromTriplets(std::begin(triplets), std::end(triplets));
888  eigenMatrix.makeCompressed();
889 }
890 
891 void
892 FemDeformableBodyModel::setFixedSizeTimeStepping()
893 {
894  m_timeStepSizeType = TimeSteppingType::Fixed;
895  m_timeIntegrator->setTimestepSizeToDefault();
896 }
897 
898 void
899 FemDeformableBodyModel::setTimeStep(const double timeStep)
900 {
901  m_timeIntegrator->setTimestepSize(timeStep);
902 }
903 
904 double
905 FemDeformableBodyModel::getTimeStep() const
906 {
907  return m_timeIntegrator->getTimestepSize();
908 };
909 
910 void
911 FemDeformableBodyModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
912 {
913  // Setup graph connectivity
914  m_taskGraph->addEdge(source, m_solveNode);
915  m_taskGraph->addEdge(m_solveNode, sink);
916 }
917 } // namespace imstk
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
Compound Geometry.
Vectord & getQ()
Get the state.
DynamicalModelType
Type of the time dependent mathematical model.
void setVertexAttribute(const std::string &arrayName, std::shared_ptr< AbstractDataArray > arr)
Set a data array holding some per vertex data.
This class stores the state of the unknown field variable in vectorized form.
Vectord & getQDot()
Get the derivative of state w.r.t time.
Base class for linear solvers.
StateUpdateType
Type of the update of the state of the body.
Provides non templated base for cell based meshes.