7 #include "imstkRigidBodyModel2.h" 8 #include "imstkParallelFor.h" 9 #include "imstkProjectedGaussSeidelSolver.h" 10 #include "imstkRbdConstraint.h" 11 #include "imstkTaskGraph.h" 12 #include "imstkLogger.h" 16 RigidBodyModel2::RigidBodyModel2() :
17 m_config(
std::make_shared<RigidBodyModel2Config>()),
18 m_pgsSolver(
std::make_shared<ProjectedGaussSeidelSolver<double>>())
20 m_computeTentativeVelocities = std::make_shared<TaskNode>(
25 m_taskGraph->addNode(m_computeTentativeVelocities);
26 m_taskGraph->addNode(m_solveNode);
27 m_taskGraph->addNode(m_integrateNode);
30 std::shared_ptr<RigidBody>
33 m_bodies.push_back(std::make_shared<RigidBody>());
35 return m_bodies.back();
41 std::vector<std::shared_ptr<RigidBody>>::iterator bodyIter = std::find(m_bodies.begin(), m_bodies.end(), rbd);
42 if (bodyIter != m_bodies.end())
44 m_bodies.erase(bodyIter);
59 std::shared_ptr<RigidBodyState2> state = std::make_shared<RigidBodyState2>();
60 state->resize(m_bodies.size());
61 std::vector<bool>& isStatic = state->getIsStatic();
62 std::vector<double>& invMasses = state->getInvMasses();
63 StdVectorOfMat3d& invInteriaTensors = state->getInvIntertiaTensors();
64 StdVectorOfVec3d& positions = state->getPositions();
65 StdVectorOfQuatd& orientations = state->getOrientations();
66 StdVectorOfVec3d& velocities = state->getVelocities();
67 StdVectorOfVec3d& angularVelocities = state->getAngularVelocities();
68 StdVectorOfVec3d& tentativeVelocities = state->getTentatveVelocities();
69 StdVectorOfVec3d& tentativeAngularVelocities = state->getTentativeAngularVelocities();
70 StdVectorOfVec3d& forces = state->getForces();
71 StdVectorOfVec3d& torques = state->getTorques();
73 m_Minv = Eigen::SparseMatrix<double>(m_bodies.size() * 6, m_bodies.size() * 6);
74 std::vector<Eigen::Triplet<double>> mInvTriplets;
75 mInvTriplets.reserve((9 + 3) * m_bodies.size());
76 for (
size_t i = 0; i < m_bodies.size(); i++)
81 isStatic[i] = body.m_isStatic;
82 invMasses[i] = (body.m_mass == 0.0) ? 0.0 : 1.0 / body.m_mass;
83 if (body.m_intertiaTensor.determinant() == 0.0)
85 LOG(WARNING) <<
"Inertia tensor provided is not invertible, check that it makes sense";
88 invInteriaTensors[i] = body.m_intertiaTensor.inverse();
89 positions[i] = body.m_initPos;
90 orientations[i] = body.m_initOrientation;
91 velocities[i] = body.m_initVelocity;
92 angularVelocities[i] = body.m_initAngularVelocity;
93 tentativeVelocities[i] = body.m_initVelocity;
94 tentativeAngularVelocities[i] = body.m_initAngularVelocity;
95 forces[i] = body.m_initForce;
96 torques[i] = body.m_initTorque;
99 body.m_pos = &positions[i];
100 body.m_orientation = &orientations[i];
101 body.m_velocity = &velocities[i];
102 body.m_angularVelocity = &angularVelocities[i];
103 body.m_force = &forces[i];
104 body.m_torque = &torques[i];
105 m_locations[m_bodies[i].get()] =
static_cast<StorageIndex
>(i);
107 if (!body.m_isStatic)
110 const double invMass = invMasses[i];
111 const Mat3d& invInvertia = invInteriaTensors[i];
112 int index =
static_cast<int>(i * 6);
113 mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
115 mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
117 mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
119 for (
unsigned int c = 0; c < 3; c++)
121 for (
unsigned int r = 0; r < 3; r++)
123 mInvTriplets.push_back(Eigen::Triplet<double>(index + r, index + c, invInvertia(c, r)));
128 m_Minv.setFromTriplets(mInvTriplets.begin(), mInvTriplets.end());
145 std::vector<double>& invMasses = state->getInvMasses();
146 StdVectorOfMat3d& invInteriaTensors = state->getInvIntertiaTensors();
148 m_Minv = Eigen::SparseMatrix<double>(m_bodies.size() * 6, m_bodies.size() * 6);
149 std::vector<Eigen::Triplet<double>> mInvTriplets;
150 mInvTriplets.reserve((9 + 3) * m_bodies.size());
151 for (
size_t i = 0; i < m_bodies.size(); i++)
155 invMasses[i] = (body.m_mass == 0.0) ? 0.0 : 1.0 / body.m_mass;
156 if (body.m_intertiaTensor.determinant() == 0.0)
158 LOG(WARNING) <<
"Inertia tensor provided is not invertible, check that it makes sense";
162 invInteriaTensors[i] = body.m_intertiaTensor.inverse();
165 if (!body.m_isStatic)
168 const double invMass = invMasses[i];
169 const Mat3d& invInvertia = invInteriaTensors[i];
170 int index =
static_cast<int>(i * 6);
171 mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
173 mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
175 mInvTriplets.push_back(Eigen::Triplet<double>(index, index, invMass));
177 for (
unsigned int c = 0; c < 3; c++)
179 for (
unsigned int r = 0; r < 3; r++)
181 mInvTriplets.push_back(Eigen::Triplet<double>(index + r, index + c, invInvertia(c, r)));
186 m_Minv.setFromTriplets(mInvTriplets.begin(), mInvTriplets.end());
198 const double dt = m_config->m_dt;
199 const std::vector<double>& invMasses =
getCurrentState()->getInvMasses();
200 const StdVectorOfMat3d& invInteriaTensors =
getCurrentState()->getInvIntertiaTensors();
201 StdVectorOfVec3d& tentativeVelocities =
getCurrentState()->getTentatveVelocities();
202 StdVectorOfVec3d& tentativeAngularVelocities =
getCurrentState()->getTentativeAngularVelocities();
205 const Vec3d& fG = m_config->m_gravity;
209 ParallelUtils::parallelFor(tentativeVelocities.size(), [&](
const size_t& i)
211 forces[i] += fG * (1.0 / invMasses[i]);
212 tentativeVelocities[i] += forces[i] * invMasses[i] * dt;
213 tentativeAngularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
214 }, tentativeVelocities.size() > m_maxBodiesParallel);
221 F = Eigen::VectorXd();
224 if (m_constraints.size() == 0)
228 if (m_config->m_maxNumConstraints != -1 && static_cast<int>(m_constraints.size()) > m_config->m_maxNumConstraints * 2)
230 m_constraints.resize(m_config->m_maxNumConstraints * 2);
236 const std::vector<bool>& isStatic = state->getIsStatic();
237 const StdVectorOfVec3d& tentativeVelocities = state->getTentatveVelocities();
238 const StdVectorOfVec3d& tentativeAngularVelocities = state->getTentativeAngularVelocities();
239 StdVectorOfVec3d& forces = state->getForces();
240 StdVectorOfVec3d& torques = state->getTorques();
242 Eigen::VectorXd V = Eigen::VectorXd(state->size() * 6);
243 Eigen::VectorXd Fext = Eigen::VectorXd(state->size() * 6);
247 for (
size_t i = 0; i < state->size(); i++)
251 const Vec3d& velocity = tentativeVelocities[i];
252 const Vec3d& angularVelocity = tentativeAngularVelocities[i];
253 const Vec3d& force = forces[i];
254 const Vec3d& torque = torques[i];
265 V(j) = angularVelocity[0];
268 V(j) = angularVelocity[1];
271 V(j) = angularVelocity[2];
276 for (StorageIndex k = 0; k < 6; k++)
286 Eigen::SparseMatrix<double> J(m_constraints.size(), state->size() * 6);
287 Eigen::VectorXd Vu(m_constraints.size());
288 Eigen::MatrixXd cu(m_constraints.size(), 2);
289 std::vector<Eigen::Triplet<double>> JTriplets;
290 JTriplets.reserve(m_constraints.size() * 12);
292 for (std::list<std::shared_ptr<RbdConstraint>>::iterator iter = m_constraints.begin(); iter != m_constraints.end(); iter++)
294 std::shared_ptr<RbdConstraint> constraint = *iter;
295 Vu(j) = constraint->vu;
299 if (constraint->m_obj1 !=
nullptr)
301 const StorageIndex obj1Location = m_locations[constraint->m_obj1.get()];
302 const StorageIndex start1 = obj1Location * 6;
303 for (StorageIndex c = 0; c < 2; c++)
305 for (StorageIndex r = 0; r < 3; r++)
307 JTriplets.push_back(Eigen::Triplet<double>(j, start1 + k, constraint->J(r, c)));
314 if (constraint->m_obj2 !=
nullptr)
316 const StorageIndex obj2Location = m_locations[constraint->m_obj2.get()];
317 const StorageIndex start2 = obj2Location * 6;
319 for (StorageIndex c = 2; c < 4; c++)
321 for (StorageIndex r = 0; r < 3; r++)
323 JTriplets.push_back(Eigen::Triplet<double>(j, start2 + k, constraint->J(r, c)));
329 cu(j, 0) = constraint->range[0];
330 cu(j, 1) = constraint->range[1];
333 J.setFromTriplets(JTriplets.begin(), JTriplets.end());
335 const double dt = m_config->m_dt;
336 Eigen::SparseMatrix<double> A = J * m_Minv * J.transpose();
337 Eigen::VectorXd b = Vu / dt - J * (V / dt + m_Minv * Fext);
347 m_pgsSolver->setA(&A);
349 m_pgsSolver->setMaxIterations(m_config->m_maxNumIterations);
350 m_pgsSolver->setEpsilon(m_config->m_epsilon);
351 F = J.transpose() * m_pgsSolver->solve(b, cu);
355 for (
size_t i = 0; i < state->size(); i++, j += 6)
357 forces[i] += Vec3d(F(j), F(j + 1), F(j + 2));
358 torques[i] += Vec3d(F(j + 3), F(j + 4), F(j + 5));
363 m_constraints.clear();
370 const double dt = m_config->m_dt;
371 const double velocityDamping = m_config->m_velocityDamping;
372 const double angularVelocityDamping = m_config->m_angularVelocityDamping;
376 const std::vector<double>& invMasses =
getCurrentState()->getInvMasses();
377 const StdVectorOfMat3d& invInteriaTensors =
getCurrentState()->getInvIntertiaTensors();
383 StdVectorOfVec3d& angularVelocities =
getCurrentState()->getAngularVelocities();
385 StdVectorOfVec3d& tentativeVelocities =
getCurrentState()->getTentatveVelocities();
386 StdVectorOfVec3d& tentativeAngularVelocities =
getCurrentState()->getTentativeAngularVelocities();
391 ParallelUtils::parallelFor(positions.size(), [&](
const size_t& i)
395 velocities[i] += forces[i] * invMasses[i] * dt;
396 velocities[i] *= velocityDamping;
397 angularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
398 angularVelocities[i] *= angularVelocityDamping;
399 positions[i] += velocities[i] * dt;
401 const Quatd q = Quatd(0.0,
402 angularVelocities[i][0],
403 angularVelocities[i][1],
404 angularVelocities[i][2]) * orientations[i];
405 orientations[i].x() += q.x() * dt;
406 orientations[i].y() += q.y() * dt;
407 orientations[i].z() += q.z() * dt;
408 orientations[i].w() += q.w() * dt;
409 orientations[i].normalize();
414 m_bodies[i]->m_prevForce = forces[i];
415 forces[i] = Vec3d(0.0, 0.0, 0.0);
416 torques[i] = Vec3d(0.0, 0.0, 0.0);
417 tentativeVelocities[i] = velocities[i];
418 tentativeAngularVelocities[i] = angularVelocities[i];
419 }, positions.size() > m_maxBodiesParallel);
425 m_taskGraph->addEdge(source, m_computeTentativeVelocities);
426 m_taskGraph->addEdge(m_computeTentativeVelocities, m_solveNode);
427 m_taskGraph->addEdge(m_solveNode, m_integrateNode);
428 m_taskGraph->addEdge(m_integrateNode, sink);
std::shared_ptr< FeDeformBodyState > m_initialState
Initial state.
void solveConstraints()
Solve the current constraints of the model, then discards.
void integrate()
Integrate the model state.
std::shared_ptr< FeDeformBodyState > m_previousState
Previous state.
bool initialize() override
Initialize the RigidBody model to the initial state.
void updateMass()
Updates mass and inertia matrices to those provided by the bodies. Not often needed unless mass/inert...
void configure(std::shared_ptr< RigidBodyModel2Config > config)
Configure the model.
Serves as a handle to the body.
void computeTentativeVelocities()
Computes the velocities.
std::shared_ptr< RigidBody > addRigidBody()
Adds a body to the system, must call initialize for changes to effect returns its reference...
std::shared_ptr< FeDeformBodyState > m_currentState
Current state.
void removeRigidBody(std::shared_ptr< RigidBody > body)
Removes a body from the system, must call initialize for changes to effect.
std::shared_ptr< FeDeformBodyState > getCurrentState() const
Return the current state of the problem.
void initGraphEdges()
Initializes the edges of the graph.