7 #include "imstkDataTracker.h" 8 #include "imstkPbdModel.h" 9 #include "imstkGraph.h" 10 #include "imstkLineMesh.h" 11 #include "imstkLogger.h" 12 #include "imstkParallelUtils.h" 13 #include "imstkPbdConstraintFunctor.h" 14 #include "imstkPbdModelConfig.h" 15 #include "imstkPbdSolver.h" 16 #include "imstkTaskGraph.h" 20 PbdModel::PbdModel() : AbstractDynamicalModel(
DynamicalModelType::PositionBasedDynamics),
21 m_config(
std::make_shared<PbdModelConfig>()),
22 m_constraints(
std::make_shared<PbdConstraintContainer>())
31 m_state.m_bodies[0] = std::make_shared<PbdBody>(0);
32 m_state.m_bodies[0]->bodyType = PbdBody::Type::DEFORMABLE_ORIENTED;
33 m_state.m_bodies[0]->prevVertices = std::make_shared<VecDataArray<double, 3>>();
34 m_state.m_bodies[0]->vertices = std::make_shared<VecDataArray<double, 3>>();
35 m_state.m_bodies[0]->prevOrientations = std::make_shared<StdVectorOfQuatd>();
36 m_state.m_bodies[0]->orientations = std::make_shared<StdVectorOfQuatd>();
37 m_state.m_bodies[0]->velocities = std::make_shared<VecDataArray<double, 3>>();
38 m_state.m_bodies[0]->angularVelocities = std::make_shared<VecDataArray<double, 3>>();
39 m_state.m_bodies[0]->masses = std::make_shared<DataArray<double>>();
40 m_state.m_bodies[0]->invMasses = std::make_shared<DataArray<double>>();
41 m_state.m_bodies[0]->inertias = std::make_shared<StdVectorOfMat3d>();
42 m_state.m_bodies[0]->invInertias = std::make_shared<StdVectorOfMat3d>();
45 m_state.m_bodies[1] = std::make_shared<PbdBody>(1);
46 m_state.m_bodies[1]->bodyType = PbdBody::Type::DEFORMABLE_ORIENTED;
47 m_state.m_bodies[1]->prevVertices = std::make_shared<VecDataArray<double, 3>>();
48 m_state.m_bodies[1]->vertices = std::make_shared<VecDataArray<double, 3>>();
49 m_state.m_bodies[1]->prevOrientations = std::make_shared<StdVectorOfQuatd>();
50 m_state.m_bodies[1]->orientations = std::make_shared<StdVectorOfQuatd>();
51 m_state.m_bodies[1]->velocities = std::make_shared<VecDataArray<double, 3>>();
52 m_state.m_bodies[1]->angularVelocities = std::make_shared<VecDataArray<double, 3>>();
53 m_state.m_bodies[1]->masses = std::make_shared<DataArray<double>>();
54 m_state.m_bodies[1]->invMasses = std::make_shared<DataArray<double>>();
55 m_state.m_bodies[1]->inertias = std::make_shared<StdVectorOfMat3d>();
56 m_state.m_bodies[1]->invInertias = std::make_shared<StdVectorOfMat3d>();
58 m_validGeometryTypes = {
67 m_integrationPositionNode = m_taskGraph->addFunction(
"PbdModel_IntegratePosition",
68 [&]() { integratePosition(); });
69 m_solveConstraintsNode = m_taskGraph->addFunction(
"PbdModel_SolveConstraints",
70 [&]() { solveConstraints(); });
71 m_updateVelocityNode = m_taskGraph->addFunction(
"PbdModel_UpdateVelocity",
72 [&]() { updateVelocity(); });
78 m_state.deepCopy(m_initialState);
81 for (
auto bodyIter = m_state.m_bodies.begin();
82 bodyIter != m_state.m_bodies.end(); bodyIter++)
85 for (
int i = 0; i < body.prevVertices->size(); i++)
87 (*body.prevVertices)[i] = (*body.vertices)[i];
91 for (
int i = 0; i < body.prevOrientations->size(); i++)
93 (*body.prevOrientations)[i] = (*body.orientations)[i];
105 std::shared_ptr<PbdBody>
108 m_state.m_bodies.push_back(std::make_shared<PbdBody>(m_iterKey));
111 return m_state.m_bodies.back();
115 PbdModel::removeBody(std::shared_ptr<PbdBody> body)
117 auto iter = std::find(m_state.m_bodies.begin(), m_state.m_bodies.end(), body);
118 CHECK(iter != m_state.m_bodies.end()) <<
"removeBody called but could not find PbdyBody in PbdState";
119 m_state.m_bodies.erase(iter);
123 std::shared_ptr<imstk::PbdBody>
126 if (index < m_state.m_bodies.size())
128 return m_state.m_bodies[index];
132 LOG(WARNING) <<
"PbdModel::getBody: index out of range";
139 const Vec3d& pos,
const Quatd& orientation,
140 const double mass,
const Mat3d inertia,
141 const Vec3d& velocity,
const Vec3d& angularVelocity,
144 const int virtualBufferId =
static_cast<int>(persist);
146 m_state.m_bodies[virtualBufferId]->prevVertices->push_back(pos);
147 m_state.m_bodies[virtualBufferId]->vertices->push_back(pos);
148 m_state.m_bodies[virtualBufferId]->prevOrientations->push_back(orientation);
149 m_state.m_bodies[virtualBufferId]->orientations->push_back(orientation);
150 m_state.m_bodies[virtualBufferId]->velocities->push_back(velocity);
151 m_state.m_bodies[virtualBufferId]->angularVelocities->push_back(angularVelocity);
152 m_state.m_bodies[virtualBufferId]->masses->push_back(mass);
153 m_state.m_bodies[virtualBufferId]->invMasses->push_back((mass == 0.0) ? 0.0 : 1.0 / mass);
154 m_state.m_bodies[virtualBufferId]->inertias->push_back(inertia);
155 Mat3d invInertia = Mat3d::Zero();
156 if (inertia.determinant() == 0.0)
158 LOG(FATAL) <<
"Tried to add virtual particle with non-invertible inertia";
161 invInertia = inertia.inverse();
162 m_state.m_bodies[virtualBufferId]->invInertias->push_back(invInertia);
163 return { virtualBufferId, m_state.m_bodies[virtualBufferId]->vertices->size() - 1 };
168 const Vec3d& pos,
const double mass,
169 const Vec3d& velocity,
172 return addVirtualParticle(pos, Quatd::Identity(),
173 mass, Mat3d::Identity(),
174 velocity, Vec3d::Zero(), persist);
180 CHECK(m_state.m_bodies.size() != 0 || m_state.m_bodies[0] !=
nullptr) <<
"Missing virtual/dummy body";
181 resizeBodyParticles(*m_state.m_bodies[0], 0);
184 std::shared_ptr<PbdModelConfig>
187 CHECK(m_config !=
nullptr) <<
"Cannot PbdModel::getConfig, config is nullptr";
195 m_initialState.deepCopy(m_state);
199 m_config->computeElasticConstants();
202 for (
const auto& functorVec : m_config->m_functors)
204 for (
const auto& functor : functorVec.second)
206 (*functor)(*m_constraints);
211 if (m_config->m_doPartitioning)
213 m_constraints->partitionConstraints(static_cast<int>(m_partitionThreshold));
217 m_constraints->clearPartitions();
222 if (m_pbdSolver ==
nullptr)
224 m_pbdSolver = std::make_shared<PbdSolver>();
227 if (m_config->m_dataTracker)
229 m_pbdSolver->m_dataTracker = m_config->m_dataTracker;
230 m_config->m_dataTracker->configureProbe(DataTracker::Physics::SolverTime_ms, DataTracker::ePhysics::SolverTime_ms);
231 m_config->m_dataTracker->configureProbe(DataTracker::Physics::NumConstraints, DataTracker::ePhysics::NumConstraints);
232 m_config->m_dataTracker->configureProbe(DataTracker::Physics::AverageC, DataTracker::ePhysics::AverageC);
242 m_taskGraph->addEdge(source, m_integrationPositionNode);
243 m_taskGraph->addEdge(m_integrationPositionNode, m_solveConstraintsNode);
244 m_taskGraph->addEdge(m_solveConstraintsNode, m_updateVelocityNode);
245 m_taskGraph->addEdge(m_updateVelocityNode, sink);
251 for (
const auto& functorVec : m_config->m_functors)
253 for (
const auto& functor : functorVec.second)
255 if (
auto bodyFunctor = std::dynamic_pointer_cast<PbdBodyConstraintFunctor>(functor))
257 if (bodyFunctor->m_bodyIndex == bodyId)
259 bodyFunctor->addConstraints(*m_constraints, vertices);
269 m_config->m_dt = timeStep;
275 return m_config->m_dt;
282 clearVirtualParticles();
283 int bodyCount = m_state.m_bodies.size() - 2;
286 ParallelUtils::parallelFor(bodyCount,
288 integratePosition(*m_state.m_bodies[i + 2]);
301 const int numParticles = pos.size();
302 CHECK(numParticles == prevPos.size()) <<
"PbdModel data corrupt";
303 CHECK(numParticles == vel.size()) <<
"PbdModel data corrupt";
304 CHECK(numParticles == invMasses.
size()) <<
"PbdModel data corrupt";
306 const double dt = m_config->m_dt;
307 const double linearVelocityDamp = 1.0 - m_config->getLinearDamping(body.
bodyHandle);
308 ParallelUtils::parallelFor(numParticles,
311 if (std::abs(invMasses[i]) > 0.0)
313 const Vec3d accel =
static_cast<double>(body.
bodyGravity) * m_config->m_gravity + body.externalForce * invMasses[i];
314 vel[i] += accel * dt;
315 vel[i] *= linearVelocityDamp;
318 vel[i] = vel[i].cwiseMax(-m_velocityThreshold).cwiseMin(m_velocityThreshold);
321 pos[i] += vel[i] * dt;
323 }, numParticles > 50);
328 StdVectorOfQuatd& orientations = *body.orientations;
329 StdVectorOfQuatd& prevOrientations = *body.prevOrientations;
331 const StdVectorOfMat3d& inertias = *body.inertias;
332 const StdVectorOfMat3d& invInertias = *body.invInertias;
335 CHECK(numParticles == orientations.size()) <<
"PbdModel data corrupt";
336 CHECK(numParticles == prevOrientations.size()) <<
"PbdModel data corrupt";
337 CHECK(numParticles == angularVelocities.size()) <<
"PbdModel data corrupt";
338 CHECK(numParticles == invInertias.size()) <<
"PbdModel data corrupt";
340 const double angularVelocityDamp = 1.0 - m_config->getAngularDamping(body.
bodyHandle);
341 ParallelUtils::parallelFor(numParticles,
344 if (!invInertias[i].isZero())
346 Vec3d& w = angularVelocities[i];
347 const Vec3d accel = invInertias[i] *
348 (body.externalTorque - (w.cross(inertias[i] * w)));
350 w *= angularVelocityDamp;
351 prevOrientations[i] = orientations[i];
354 w.cwiseMax(-m_velocityThreshold).cwiseMin(m_velocityThreshold);
358 const double phi = w.norm();
359 if (phi * scale > 0.5)
363 const Quatd dq = Quatd(0.0,
366 w[2] * scale) * orientations[i];
367 orientations[i].coeffs() += dq.coeffs() * 0.5;
368 orientations[i].normalize();
370 }, numParticles > 50);
377 int bodyCount = m_state.m_bodies.size() - 2;
378 ParallelUtils::parallelFor(bodyCount,
380 updateVelocity(*m_state.m_bodies[i + 2]);
385 for (
const auto& colConstraintList : m_pbdSolver->getConstraintLists())
387 for (
auto& colConstraint : *colConstraintList)
389 colConstraint->correctVelocity(m_state, m_config->m_dt);
392 m_pbdSolver->clearConstraintLists();
398 if (m_config->m_dt > 0.0)
406 const int numParticles = pos.size();
407 CHECK(numParticles == prevPos.size()) <<
"PbdModel data corrupt";
408 CHECK(numParticles == vel.size()) <<
"PbdModel data corrupt";
409 CHECK(numParticles == invMasses.
size()) <<
"PbdModel data corrupt";
411 const double invDt = 1.0 / m_config->m_dt;
412 ParallelUtils::parallelFor(numParticles,
415 if (std::abs(invMasses[i]) > 0.0)
417 vel[i] = (pos[i] - prevPos[i]) * invDt;
419 }, numParticles > 50);
423 const StdVectorOfQuatd& orientations = *body.orientations;
424 const StdVectorOfQuatd& prevOrientations = *body.prevOrientations;
426 const StdVectorOfMat3d& invInertias = *body.invInertias;
429 CHECK(numParticles == orientations.size()) <<
"PbdModel data corrupt";
430 CHECK(numParticles == prevOrientations.size()) <<
"PbdModel data corrupt";
431 CHECK(numParticles == angularVelocities.size()) <<
"PbdModel data corrupt";
432 CHECK(numParticles == invInertias.size()) <<
"PbdModel data corrupt";
434 ParallelUtils::parallelFor(numParticles,
437 if (!invInertias[i].isZero())
439 const Quatd dq = orientations[i] * prevOrientations[i].inverse();
441 const Vec3d angularVel = 2.0 * Vec3d(dq.x(), dq.y(), dq.z()) * invDt;
442 angularVelocities[i] = dq.w() >= 0.0 ? angularVel : -angularVel;
444 }, numParticles > 50);
448 body.externalForce = Vec3d::Zero();
449 body.externalTorque = Vec3d::Zero();
455 m_pbdSolver->setPbdBodies(&m_state);
456 m_pbdSolver->setConstraints(getConstraints());
457 m_pbdSolver->setTimeStep(m_config->m_dt);
458 m_pbdSolver->setIterations(m_config->m_iterations);
459 m_pbdSolver->setSolverType(m_config->m_solverType);
460 m_pbdSolver->solve();
466 body.prevVertices->resize(particleCount);
467 body.vertices->resize(particleCount);
468 body.velocities->resize(particleCount);
469 body.masses->resize(particleCount);
470 body.invMasses->resize(particleCount);
473 body.prevOrientations->resize(particleCount);
474 body.orientations->resize(particleCount);
475 body.angularVelocities->resize(particleCount);
476 body.inertias->resize(particleCount);
477 body.invInertias->resize(particleCount);
Represents a pbd body in the model. This is a data only object. It does no function. PbdBody can be of different types. The types effect what properties it has.
void configure(std::shared_ptr< PbdModelConfig > params)
Set simulation parameters.
int size() const
Get number of values/tuples.
std::pair< int, int > PbdParticleId
Index pair that refers to a particle in a PbdState. Index 0 is the body id, Index 1 is the particle i...
int bodyHandle
Id in the system.
void addConstraints(std::shared_ptr< std::unordered_set< size_t >> vertices, const int bodyId)
Add/generate constraints for given set of vertices on the body, useful for topology changes...
void setTimeStep(const double timeStep) override
Set the time step size.
void clearVirtualParticles()
Resize 0 the virtual particles.
void updateVelocity()
Time integrate the velocity.
DynamicalModelType
Type of the time dependent mathematical model.
bool initialize() override
Initialize the PBD model.
void resizeBodyParticles(PbdBody &body, const int particleCount)
Resize the amount of particles for a body.
bool bodyGravity
Switch to activate/deactivate gravity for this Pbd Body. 1 is gravity on, 0 is gravity off...
PbdParticleId addVirtualParticle(const Vec3d &pos, const Quatd &orientation, const double mass, const Mat3d inertia, const Vec3d &velocity=Vec3d::Zero(), const Vec3d &angularVelocity=Vec3d::Zero(), const bool persist=false)
Add a particle to a virtual pool/buffer of particles for quick removal/insertion The persist flag ind...
std::shared_ptr< PbdBody > getBody(size_t index) const
void integratePosition()
Time integrate the position.
void solveConstraints()
Solve the internal constraints.
void resetToInitialState() override
Reset the current state to the initial state.
std::shared_ptr< PbdModelConfig > getConfig() const
Get the simulation parameters.
double getTimeStep() const override
Returns the time step size.
bool getOriented() const
The body should have orientations if its DEFORMABLE_ORIENTED or RIGID.
std::shared_ptr< PbdBody > addBody()
Add/remove PbdBody.
void initGraphEdges()
Initializes the edges of the graph.