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" 23 DISABLE_WARNING_HIDES_CLASS_MEMBER
24 #include "imstkStVKForceModel.h" 26 #include <generateMassMatrix.h> 27 #include <generateMeshGraph.h> 28 #include <configFile.h> 35 FemDeformableBodyModel::FemDeformableBodyModel() :
38 m_fixedNodeIds.reserve(1000);
40 m_validGeometryTypes = {
"TetrahedralMesh",
"HexahedralMesh" };
42 m_solveNode = m_taskGraph->addFunction(
"FEMModel_Solve", [&]() { getSolver()->solve(); });
45 FemDeformableBodyModel::~FemDeformableBodyModel()
48 m_internalForceModel =
nullptr;
52 FemDeformableBodyModel::configure(
const std::string& configFileName)
55 m_FEModelConfig = std::make_shared<FemModelConfig>();
58 char invertibleMaterial[256];
59 char fixedDOFFilename[256];
61 vega::ConfigFile vegaConfigFileOptions;
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);
76 CHECK(vegaConfigFileOptions.parseOptions(configFileName.data()) == 0)
77 <<
"ForceModelConfig::parseConfig - Unable to load the configuration file";
81 const size_t last_slash_idx = configFileName.rfind(
'/');
82 if (std::string::npos != last_slash_idx)
84 rootDir = configFileName.substr(0, last_slash_idx);
88 if (std::strcmp(femMethod,
"StVK") == 0)
90 m_FEModelConfig->m_femMethod = FeMethodType::StVK;
92 else if (std::strcmp(femMethod,
"CLFEM") == 0)
94 m_FEModelConfig->m_femMethod = FeMethodType::Corotational;
96 else if (std::strcmp(femMethod,
"Linear") == 0)
98 m_FEModelConfig->m_femMethod = FeMethodType::Linear;
100 else if (std::strcmp(femMethod,
"InvertibleFEM") == 0)
102 m_FEModelConfig->m_femMethod = FeMethodType::Invertible;
106 LOG(WARNING) <<
"FE method not assigned; will default to StVK";
107 m_FEModelConfig->m_femMethod = FeMethodType::StVK;
111 if (std::strcmp(invertibleMaterial,
"StVK") == 0)
113 m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::StVK;
115 else if (std::strcmp(invertibleMaterial,
"NeoHookean") == 0)
117 m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::NeoHookean;
119 else if (std::strcmp(invertibleMaterial,
"MooneyRivlin") == 0)
121 m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::MooneyRivlin;
125 LOG(INFO) <<
"Hyperelastic material type not assigned; will default to StVK";
126 m_FEModelConfig->m_hyperElasticMaterialType = HyperElasticMaterialType::StVK;
130 m_FEModelConfig->m_fixedDOFFilename = rootDir + std::string(
"/") + std::string(fixedDOFFilename);
134 FemDeformableBodyModel::configure(std::shared_ptr<FemModelConfig> config)
136 m_FEModelConfig = config;
140 FemDeformableBodyModel::initialize()
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);
146 if (!pointSet->hasVertexAttribute(
"displacements"))
152 if (m_solver ==
nullptr)
156 auto nlSystem = std::make_shared<NonLinearSystem<SparseMatrixd>>(getFunction(), getFunctionGradient(), getFunctionAndGradient());
158 nlSystem->setUnknownVector(getUnknownVec());
159 nlSystem->setUpdateFunction(getUpdateFunction());
160 nlSystem->setUpdatePreviousStatesFunction(getUpdatePrevStateFunction());
163 auto linSolver = std::make_shared<ConjugateGradient>();
166 && isFixedBCImplemented())
168 LOG(WARNING) <<
"The GS solver may not be viable!";
172 auto nlSolver = std::make_shared<NewtonSolver<SparseMatrixd>>();
173 nlSolver->setToSemiImplicit();
174 nlSolver->setLinearSolver(linSolver);
175 nlSolver->setSystem(nlSystem);
179 auto physicsMesh = std::dynamic_pointer_cast<
AbstractCellMesh>(this->getModelGeometry());
180 m_vegaPhysicsMesh = VegaMeshIO::convertVolumetricMeshToVegaMesh(physicsMesh);
182 if (!this->initializeForceModel()
183 || !this->initializeMassMatrix()
184 || !this->initializeDampingMatrix()
185 || !this->initializeTangentStiffness()
186 || !this->loadBoundaryConditions()
187 || !this->initializeGravityForce()
188 || !this->initializeExplicitExternalForces())
193 this->loadInitialStates();
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);
207 FemDeformableBodyModel::loadInitialStates()
211 LOG(WARNING) <<
"Number of degree of freedom is 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);
221 FemDeformableBodyModel::loadBoundaryConditions()
223 auto fileName = m_FEModelConfig->m_fixedDOFFilename;
225 if (fileName.empty())
228 for (
auto p:m_FEModelConfig->m_fixedNodeIds)
230 m_fixedNodeIds.emplace_back(p);
235 std::ifstream file(fileName.data());
237 if (file.peek() == std::ifstream::traits_type::eof())
239 LOG(INFO) <<
"The external boundary conditions file is empty";
245 size_t maxAllowed = m_vegaPhysicsMesh->getNumVertices();
249 if (index < maxAllowed)
251 m_fixedNodeIds.emplace_back(index);
255 LOG(WARNING) <<
"The boundary condition node id provided is greater than number of nodes and hence excluded!!";
261 std::sort(m_fixedNodeIds.begin(), m_fixedNodeIds.end());
265 LOG(FATAL) <<
"Could not open boundary conditions file!";
273 FemDeformableBodyModel::initializeForceModel()
275 const double g = m_FEModelConfig->m_gravity;
278 const bool isGravityPresent =
false;
280 m_numDof = (size_t)m_vegaPhysicsMesh->getNumVertices() * 3;
282 switch (m_FEModelConfig->m_femMethod)
284 case FeMethodType::StVK:
286 m_internalForceModel = std::make_shared<StvkForceModel>(m_vegaPhysicsMesh, isGravityPresent, g);
289 case FeMethodType::Linear:
291 m_internalForceModel = std::make_shared<LinearFemForceModel>(m_vegaPhysicsMesh, isGravityPresent, g);
294 case FeMethodType::Corotational:
296 m_internalForceModel = std::make_shared<CorotationalFemForceModel>(m_vegaPhysicsMesh);
299 case FeMethodType::Invertible:
301 m_internalForceModel = std::make_shared<IsotropicHyperelasticFeForceModel>(
302 m_FEModelConfig->m_hyperElasticMaterialType,
310 LOG(FATAL) <<
"Unknown force model type";
318 FemDeformableBodyModel::initializeMassMatrix()
320 CHECK(m_geometry !=
nullptr) <<
"Force model geometry not set!";
322 vega::SparseMatrix* vegaMatrix;
323 vega::GenerateMassMatrix::computeMassMatrix(m_vegaPhysicsMesh.get(), &vegaMatrix,
true);
325 m_vegaMassMatrix.reset(vegaMatrix);
327 this->initializeEigenMatrixFromVegaMatrix(*vegaMatrix, m_M);
335 FemDeformableBodyModel::initializeDampingMatrix()
337 auto dampingLaplacianCoefficient = m_FEModelConfig->m_dampingLaplacianCoefficient;
338 auto dampingMassCoefficient = m_FEModelConfig->m_dampingMassCoefficient;
339 auto dampingStiffnessCoefficient = m_FEModelConfig->m_dampingStiffnessCoefficient;
341 if (dampingStiffnessCoefficient == 0.0 && dampingLaplacianCoefficient == 0.0 && dampingMassCoefficient == 0.0)
343 LOG(WARNING) <<
"All the damping parameters are zero!";
347 if (dampingLaplacianCoefficient < 0.0)
349 LOG(WARNING) <<
"Damping coefficient is negative!";
356 auto meshGraph = std::make_shared<vega::Graph>(*vega::GenerateMeshGraph::Generate(m_vegaPhysicsMesh.get()));
360 LOG(WARNING) <<
"Mesh graph not avaliable!";
364 vega::SparseMatrix* matrix;
365 meshGraph->GetLaplacian(&matrix, 1);
369 LOG(WARNING) <<
"Mesh Laplacian not avaliable!";
373 matrix->ScalarMultiply(dampingLaplacianCoefficient);
375 m_vegaDampingMatrix.reset(matrix);
377 this->initializeEigenMatrixFromVegaMatrix(*matrix, m_C);
385 FemDeformableBodyModel::initializeTangentStiffness()
387 CHECK(m_internalForceModel !=
nullptr)
388 <<
"Tangent stiffness cannot be initialized without force model";
390 vega::SparseMatrix* matrix =
nullptr;
391 m_internalForceModel->getTangentStiffnessMatrixTopology(&matrix);
393 CHECK(matrix !=
nullptr) <<
"Tangent stiffness matrix topology not avaliable!";
394 CHECK(m_vegaMassMatrix !=
nullptr) <<
"Vega mass matrix doesn't exist!";
396 matrix->BuildSubMatrixIndices(*m_vegaMassMatrix.get());
398 if (m_vegaDampingMatrix)
400 matrix->BuildSubMatrixIndices(*m_vegaDampingMatrix.get(), 1);
403 m_vegaTangentStiffnessMatrix.reset(matrix);
405 this->initializeEigenMatrixFromVegaMatrix(*matrix, m_K);
409 const auto& dampingStiffnessCoefficient = m_FEModelConfig->m_dampingStiffnessCoefficient;
410 const auto& dampingMassCoefficient = m_FEModelConfig->m_dampingMassCoefficient;
413 m_C = dampingMassCoefficient * m_M + dampingStiffnessCoefficient * m_K;
416 m_internalForceModel->setTangentStiffness(m_vegaTangentStiffnessMatrix);
422 FemDeformableBodyModel::initializeGravityForce()
424 m_Fgravity.resize(m_numDof);
425 m_Fgravity.setZero();
426 const double gravity = m_FEModelConfig->m_gravity;
428 m_vegaPhysicsMesh->computeGravity(m_Fgravity.data(), gravity);
438 const auto& uPrev = stateAtT.
getQ();
439 const auto& vPrev = stateAtT.
getQDot();
440 auto& u = newState.
getQ();
441 const auto& v = newState.
getQDot();
444 const double dT = m_timeIntegrator->getTimestepSize();
448 case StateUpdateType::DeltaVelocity:
450 m_internalForceModel->getTangentStiffnessMatrix(u, m_K);
451 m_Feff = m_K * -(uPrev - u + v * dT);
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;
464 m_Feff += m_M * (vPrev - v);
468 LOG(WARNING) <<
"Update type not supported";
478 const auto& vPrev = stateAtT.
getQDot();
479 auto& u = newState.
getQ();
483 m_internalForceModel->getTangentStiffnessMatrix(u, m_K);
484 const double dT = m_timeIntegrator->getTimestepSize();
488 case StateUpdateType::DeltaVelocity:
490 m_Feff = m_K * (vPrev * -dT);
494 m_Feff -= m_C * vPrev;
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;
507 LOG(FATAL) <<
"Update type not supported";
512 FemDeformableBodyModel::computeImplicitSystemLHS(
const kinematicState& imstkNotUsed(stateAtT),
516 const double dT = m_timeIntegrator->getTimestepSize();
520 case StateUpdateType::DeltaVelocity:
521 this->updateMassMatrix();
522 m_internalForceModel->getTangentStiffnessMatrix(newState.
getQ(), m_K);
523 this->updateDampingMatrix();
530 m_Keff += (dT * dT) * m_K;
535 LOG(FATAL) <<
"Update type not supported";
540 FemDeformableBodyModel::computeSemiImplicitSystemRHSAndLHS(
kinematicState& stateAtT,
544 const auto& vPrev = stateAtT.
getQDot();
545 const double dT = m_timeIntegrator->getTimestepSize();
549 case StateUpdateType::DeltaVelocity:
551 this->updateMassMatrix();
552 m_internalForceModel->getForceAndMatrix(newState.
getQ(), m_Finternal, m_K);
553 this->updateDampingMatrix();
560 m_Keff += (dT * dT) * m_K;
563 m_Feff = m_K * (vPrev * -dT);
567 m_Feff -= m_C * vPrev;
570 m_Feff -= m_Finternal;
571 m_Feff += m_FexplicitExternal;
572 m_Feff += m_Fgravity;
573 m_Feff += m_Fcontact;
579 LOG(FATAL) <<
"Update type not supported";
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();
596 case StateUpdateType::DeltaVelocity:
598 this->updateMassMatrix();
599 m_internalForceModel->getForceAndMatrix(u, m_Finternal, m_K);
600 this->updateDampingMatrix();
607 m_Keff += (dT * dT) * m_K;
610 m_Feff = m_K * -(uPrev - u + v * dT);
617 m_Feff -= m_Finternal;
618 m_Feff += m_FexplicitExternal;
619 m_Feff += m_Fgravity;
620 m_Feff += m_Fcontact;
622 m_Feff += m_M * (vPrev - v);
626 LOG(FATAL) <<
"Update type not supported";
631 FemDeformableBodyModel::initializeExplicitExternalForces()
633 m_FexplicitExternal.resize(m_numDof);
634 m_FexplicitExternal.setZero();
640 FemDeformableBodyModel::updateDampingMatrix()
644 const auto& dampingStiffnessCoefficient = m_FEModelConfig->m_dampingStiffnessCoefficient;
645 const auto& dampingMassCoefficient = m_FEModelConfig->m_dampingMassCoefficient;
647 if (dampingMassCoefficient > 0)
649 m_C = dampingMassCoefficient * m_M;
651 if (dampingStiffnessCoefficient > 0)
653 m_C += m_K * dampingStiffnessCoefficient;
656 else if (dampingStiffnessCoefficient > 0)
658 m_C = m_K * dampingStiffnessCoefficient;
664 FemDeformableBodyModel::applyBoundaryConditions(SparseMatrixd& M,
const bool withCompliance)
const 666 double compliance = withCompliance ? 1.0 : 0.0;
669 for (
auto& index : m_fixedNodeIds)
671 auto nodeIdx =
static_cast<SparseMatrixd::Index
>(index) * 3;
673 for (
auto idx = nodeIdx; idx < nodeIdx + 3; idx++)
675 for (
long long k = 0; k < M.outerSize(); ++k)
677 for (SparseMatrixd::InnerIterator i(M, k); i; ++i)
679 if (i.row() == idx || i.col() == idx)
684 if (i.row() == idx && i.col() == idx)
686 i.valueRef() = compliance;
695 FemDeformableBodyModel::applyBoundaryConditions(Vectord& x)
const 697 for (
auto& index : m_fixedNodeIds)
699 const auto _3Index = 3 * index;
700 x(_3Index) = x(_3Index + 1) = x(_3Index + 2) = 0.0;
705 FemDeformableBodyModel::updateMassMatrix()
711 FemDeformableBodyModel::updatePhysicsGeometry()
713 auto volMesh = std::dynamic_pointer_cast<
PointSet>(m_geometry);
714 auto& u = m_currentState->getQ();
715 std::shared_ptr<VecDataArray<double, 3>> displacementsPtr =
717 std::copy_n(u.data(), displacementsPtr->size() * 3,
reinterpret_cast<double*
>(displacementsPtr->getVoidPointer()));
722 for (
int i = 0; i < displacementsPtr->size(); i++)
724 positions[i] = initPositions[i] + displacements[i];
729 FemDeformableBodyModel::updateBodyPreviousStates()
731 m_previousState->setU(m_currentState->getQ());
732 m_previousState->setV(m_currentState->getQDot());
736 FemDeformableBodyModel::updateBodyStates(
const Vectord& solution,
const StateUpdateType updateType)
738 this->updateBodyPreviousStates();
739 this->updateBodyIntermediateStates(solution, updateType);
743 FemDeformableBodyModel::updateBodyIntermediateStates(
744 const Vectord& solution,
747 const auto& uPrev = m_previousState->getQ();
749 const auto& v = m_currentState->getQDot();
750 const double dT = m_timeIntegrator->getTimestepSize();
754 case StateUpdateType::DeltaVelocity:
755 m_currentState->setV(v + solution);
756 m_currentState->setU(uPrev + dT * v);
760 case StateUpdateType::Velocity:
761 m_currentState->setV(solution);
762 m_currentState->setU(uPrev + dT * v);
767 LOG(FATAL) <<
"Unknown state update type";
769 m_qSol = m_currentState->getQ();
772 NonLinearSystem<SparseMatrixd>::VectorFunctionType
773 FemDeformableBodyModel::getFunction()
776 #pragma warning( push ) 777 #pragma warning( disable : 4100 ) 781 return [&,
this](
const Vectord& q,
const bool semiImplicit) ->
const Vectord&
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)
788 applyBoundaryConditions(m_Feff);
793 #pragma warning( pop ) 797 NonLinearSystem<SparseMatrixd>::MatrixFunctionType
798 FemDeformableBodyModel::getFunctionGradient()
801 #pragma warning( push ) 802 #pragma warning( disable : 4100 ) 805 return [&,
this](
const Vectord& q) ->
const SparseMatrixd&
807 this->computeImplicitSystemLHS(*m_previousState.get(), *m_currentState.get(), m_updateType);
809 if (this->m_implementFixedBC)
811 applyBoundaryConditions(m_Keff);
816 #pragma warning( pop ) 820 NonLinearSystem<SparseMatrixd>::VectorMatrixFunctionType
821 FemDeformableBodyModel::getFunctionAndGradient()
824 #pragma warning( push ) 825 #pragma warning( disable : 4100 ) 830 return [&,
this](
const Vectord& q,
const bool 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)
837 applyBoundaryConditions(m_Feff);
838 applyBoundaryConditions(m_Keff);
840 return std::make_pair(&m_Feff, &m_Keff);
843 #pragma warning( pop ) 847 NonLinearSystem<SparseMatrixd>::UpdateFunctionType
848 FemDeformableBodyModel::getUpdateFunction()
851 return [&,
this](
const Vectord& q,
const bool fullyImplicit) ->
void 854 this->updateBodyIntermediateStates(q, m_updateType) :
855 this->updateBodyStates(q, m_updateType);
859 NonLinearSystem<SparseMatrixd>::UpdatePrevStateFunctionType
860 FemDeformableBodyModel::getUpdatePrevStateFunction()
863 return [&,
this]() ->
void 865 this->updateBodyPreviousStates();
870 FemDeformableBodyModel::initializeEigenMatrixFromVegaMatrix(
const vega::SparseMatrix& vegaMatrix,
871 SparseMatrixd& eigenMatrix)
873 auto rowLengths = vegaMatrix.GetRowLengths();
874 auto nonZeroValues = vegaMatrix.GetEntries();
875 auto columnIndices = vegaMatrix.GetColumnIndices();
877 std::vector<Eigen::Triplet<double>> triplets;
878 triplets.reserve(vegaMatrix.GetNumEntries());
879 for (
int i = 0, end = vegaMatrix.GetNumRows(); i < end; ++i)
881 for (
int k = 0, k_end = rowLengths[i]; k < k_end; ++k)
883 triplets.emplace_back(i, columnIndices[i][k], nonZeroValues[i][k]);
886 eigenMatrix.resize(vegaMatrix.GetNumRows(), vegaMatrix.GetNumColumns());
887 eigenMatrix.setFromTriplets(std::begin(triplets), std::end(triplets));
888 eigenMatrix.makeCompressed();
892 FemDeformableBodyModel::setFixedSizeTimeStepping()
894 m_timeStepSizeType = TimeSteppingType::Fixed;
895 m_timeIntegrator->setTimestepSizeToDefault();
899 FemDeformableBodyModel::setTimeStep(
const double timeStep)
901 m_timeIntegrator->setTimestepSize(timeStep);
905 FemDeformableBodyModel::getTimeStep()
const 907 return m_timeIntegrator->getTimestepSize();
911 FemDeformableBodyModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
914 m_taskGraph->addEdge(source, m_solveNode);
915 m_taskGraph->addEdge(m_solveNode, sink);
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
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.