diff --git a/Examples/MultipleScenes/multipleScenes.cpp b/Examples/MultipleScenes/multipleScenes.cpp index e120419ee22a37d9f17b185365812f075b0f0217..8b5cd383bc0ab66fc08555a8da941cc08f20ffaf 100644 --- a/Examples/MultipleScenes/multipleScenes.cpp +++ b/Examples/MultipleScenes/multipleScenes.cpp @@ -65,8 +65,8 @@ createSoftBodyScene(std::shared_ptr<SimulationManager> simManager, const char* s auto pbdParams = std::make_shared<PBDModelConfig>(); // FEM constraint - pbdParams->femParams->m_YoungModulus = 100.0; - pbdParams->femParams->m_PoissonRatio = 0.3; + pbdParams->m_femParams->m_YoungModulus = 100.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; pbdParams->m_fixedNodeIds = { 51, 127, 178 }; pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); diff --git a/Examples/PBD/PBDCloth/pbdClothExample.cpp b/Examples/PBD/PBDCloth/pbdClothExample.cpp index c76b56a558a1d6fb254781d2d0962a357bd3663c..bfbcc57d17e1dc1521cc5f8dc9bc7043584041e5 100644 --- a/Examples/PBD/PBDCloth/pbdClothExample.cpp +++ b/Examples/PBD/PBDCloth/pbdClothExample.cpp @@ -99,17 +99,16 @@ main() auto pbdParams = std::make_shared<PBDModelConfig>(); // Constraints - pbdParams->enableConstraint(PbdConstraint::Type::Distance, 0.1); - pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 0.001); - std::vector<size_t> fixedNodes(nCols); - for (size_t i = 0; i < fixedNodes.size(); i++) - { - fixedNodes[i] = i; - } + // pbdParams->enableConstraint(PbdConstraint::Type::Distance, 0.1); + // pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1e2); + // pbdParams->m_solverType = PbdConstraint::SolverType::PBD; + pbdParams->enableConstraint(PbdConstraint::Type::Distance, 1e2); + pbdParams->enableConstraint(PbdConstraint::Type::Dihedral, 1e1); + std::vector<size_t> fixedNodes = { 0, nCols - 1 }; pbdParams->m_fixedNodeIds = fixedNodes; // Other parameters - pbdParams->m_uniformMassValue = 1.0; + pbdParams->m_uniformMassValue = width * height / (nRows * nCols); pbdParams->m_gravity = Vec3d(0, -9.8, 0); pbdParams->m_defaultDt = 0.005; pbdParams->m_iterations = 5; diff --git a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp index 3011315c23af84fe2b9e46340bcb0301380b2fbe..ed1e6083bdab7216fe910523c411c34c906dbf94 100644 --- a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp +++ b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp @@ -120,8 +120,8 @@ generateDragon(const std::shared_ptr<imstk::Scene>& scene, auto pbdParams = std::make_shared<PBDModelConfig>(); // FEM constraint - pbdParams->femParams->m_YoungModulus = 1000.0; - pbdParams->femParams->m_PoissonRatio = 0.3; + pbdParams->m_femParams->m_YoungModulus = 1000.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); // Other parameters diff --git a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp index 0e39f97bf68c5321d47426158c6865ddd86af3b5..31f6e7ff62684e4333c08366386da79f5310a338 100644 --- a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp +++ b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp @@ -79,8 +79,8 @@ main() auto pbdParams = std::make_shared<PBDModelConfig>(); // FEM constraint - pbdParams->femParams->m_YoungModulus = 1000.0; - pbdParams->femParams->m_PoissonRatio = 0.3; + pbdParams->m_femParams->m_YoungModulus = 1000.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::Corotation); diff --git a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp index 00624070bd192830fb30526b3ea74740196cdb45..efc2653af05b7255f1186d3d80ca688bc510d2b7 100644 --- a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp +++ b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp @@ -108,8 +108,8 @@ makeDragonPbdObject(const std::string& name) // Setup the Parameters auto pbdParams = std::make_shared<PBDModelConfig>(); - pbdParams->femParams->m_YoungModulus = 1000.0; - pbdParams->femParams->m_PoissonRatio = 0.3; + pbdParams->m_femParams->m_YoungModulus = 1000.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); pbdParams->m_uniformMassValue = 1.0; diff --git a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp index b07e73792aabf9ecef7a0c46f7511e5f9b02ceec..51acbdc6056aade31b2b788b6bfef2554640437c 100644 --- a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp +++ b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp @@ -66,15 +66,16 @@ main() auto pbdParams = std::make_shared<PBDModelConfig>(); // FEM constraint - pbdParams->femParams->m_YoungModulus = 100.0; - pbdParams->femParams->m_PoissonRatio = 0.3; - pbdParams->m_fixedNodeIds = { 51, 127, 178 }; + pbdParams->m_femParams->m_YoungModulus = 1000.0; + pbdParams->m_femParams->m_PoissonRatio = 0.3; + pbdParams->m_fixedNodeIds = { 50, 126, 177 }; pbdParams->enableFEMConstraint(PbdConstraint::Type::FEMTet, PbdFEMConstraint::MaterialType::StVK); // Other parameters pbdParams->m_uniformMassValue = 1.0; pbdParams->m_gravity = Vec3d(0, -9.8, 0); - pbdParams->m_iterations = 45; + pbdParams->m_iterations = 15; + // pbdParams->m_solverType = PbdConstraint::SolverType::PBD; // Set the parameters pbdModel->configure(pbdParams); diff --git a/Examples/PBD/PBDString/pbdStringExample.cpp b/Examples/PBD/PBDString/pbdStringExample.cpp index b3b17a9eafb256b3461d54bf6420da5a81d54692..a6b8e2b8a7d1e846c6dd0a94d3daeb8a52c2fd11 100644 --- a/Examples/PBD/PBDString/pbdStringExample.cpp +++ b/Examples/PBD/PBDString/pbdStringExample.cpp @@ -91,8 +91,8 @@ main() // Configure the parameters with bend stiffnesses varying from 0.001 to ~0.1 sims[i].params = std::make_shared<PBDModelConfig>(); - sims[i].params->enableConstraint(PbdConstraint::Type::Distance, 0.001); - sims[i].params->enableConstraint(PbdConstraint::Type::Bend, static_cast<double>(i) * 0.1 / numStrings + 0.001); + sims[i].params->enableConstraint(PbdConstraint::Type::Distance, 1e7); + sims[i].params->enableConstraint(PbdConstraint::Type::Bend, (static_cast<double>(i) * 0.1 / numStrings + 0.001) * 1e6); sims[i].params->m_fixedNodeIds = { 0 }; sims[i].params->m_uniformMassValue = 5.0; sims[i].params->m_gravity = Vec3d(0, -9.8, 0); diff --git a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp index 1246418adb0619c49ca29a2077ea7fcacb9ab56d..6121b15e54634b7d15e52f26976341c327a21ed0 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.cpp @@ -21,81 +21,61 @@ #include "imstkPbdAreaConstraint.h" -namespace imstk +namespace imstk { void -PbdAreaConstraint::initConstraint( - const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, const size_t& pIdx3, - const double k) +PbdAreaConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, + const size_t& pIdx0, + const size_t& pIdx1, + const size_t& pIdx2, + const double k) { - m_vertexIds[0] = pIdx1; - m_vertexIds[1] = pIdx2; - m_vertexIds[2] = pIdx3; + m_vertexIds[0] = pIdx0; + m_vertexIds[1] = pIdx1; + m_vertexIds[2] = pIdx2; - m_stiffness = k; + this->m_stiffness = k; + this->m_compliance = 1.0 / k; - const Vec3d& p0 = initVertexPositions[pIdx1]; - const Vec3d& p1 = initVertexPositions[pIdx2]; - const Vec3d& p2 = initVertexPositions[pIdx3]; + const Vec3d& p0 = initVertexPositions[pIdx0]; + const Vec3d& p1 = initVertexPositions[pIdx1]; + const Vec3d& p2 = initVertexPositions[pIdx2]; m_restArea = 0.5 * (p1 - p0).cross(p2 - p0).norm(); } bool -PbdAreaConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) +PbdAreaConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const { const auto i1 = m_vertexIds[0]; const auto i2 = m_vertexIds[1]; const auto i3 = m_vertexIds[2]; - Vec3d& p0 = currVertexPositions[i1]; - Vec3d& p1 = currVertexPositions[i2]; - Vec3d& p2 = currVertexPositions[i3]; + const Vec3d& p0 = currVertexPositions[i1]; + const Vec3d& p1 = currVertexPositions[i2]; + const Vec3d& p2 = currVertexPositions[i3]; - const Real im0 = currInvMasses[i1]; - const Real im1 = currInvMasses[i2]; - const Real im2 = currInvMasses[i3]; + const Vec3d e0 = p0 - p1; + const Vec3d e1 = p1 - p2; + const Vec3d e2 = p2 - p0; - const Vec3d e1 = p0 - p1; - const Vec3d e2 = p1 - p2; - const Vec3d e3 = p2 - p0; + Vec3d n = e0.cross(e1); + c = 0.5 * n.norm(); - Vec3d n = e1.cross(e2); - const Real A = 0.5 * n.norm(); - - if (A < m_epsilon) + if (c < m_epsilon) { return false; } - n /= 2 * A; - - const Vec3d grad0 = e2.cross(n); - const Vec3d grad1 = e3.cross(n); - const Vec3d grad2 = e1.cross(n); + n /= 2 * c; + c -= m_restArea; - Real lambda = im0 * grad0.squaredNorm() + im1 * grad1.squaredNorm() + im2 * grad2.squaredNorm(); - - lambda = (A - m_restArea) / lambda * m_stiffness; - - if (im0 > 0) - { - p0 += -im0 * lambda * grad0; - } - - if (im1 > 0) - { - p1 += -im1 * lambda * grad1; - } - - if (im2 > 0) - { - p2 += -im2 * lambda * grad2; - } + dcdx[0] = e1.cross(n); + dcdx[1] = e2.cross(n); + dcdx[2] = e0.cross(n); return true; } -} // imstk \ No newline at end of file +} diff --git a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.h index a1c96fd035e62b0c5907c643f4c0a78a61c57dda..0135fe574b3849b46d1e47ee1cd982b4cf252e32 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdAreaConstraint.h @@ -51,15 +51,11 @@ public: const size_t& pIdx1, const size_t& pIdx2, const size_t& pIdx3, const double k = 2.5); - /// - /// \brief Solves the area constraint - /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) override; + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const override; public: - double m_restArea = 0.; ///> Area at the rest position - double m_stiffness = 0.; ///> Stiffness of the area constraint + double m_restArea = 0.; ///> Area at the rest position }; } // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.cpp index 5db6715cb5d58b65d9a58e7e60133d71aa178f79..9bb0315a17ef4617bd539746ca0feeda88b6947f 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.cpp @@ -24,20 +24,22 @@ namespace imstk { void -PbdBendConstraint::initConstraint( - const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, - const size_t& pIdx3, const double k) +PbdBendConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, + const size_t& pIdx0, + const size_t& pIdx1, + const size_t& pIdx2, + const double k) { - m_vertexIds[0] = pIdx1; - m_vertexIds[1] = pIdx2; - m_vertexIds[2] = pIdx3; + m_vertexIds[0] = pIdx0; + m_vertexIds[1] = pIdx1; + m_vertexIds[2] = pIdx2; - m_stiffness = k; + m_stiffness = k; + m_compliance = 1.0 / k; - const Vec3d& p0 = initVertexPositions[pIdx1]; - const Vec3d& p1 = initVertexPositions[pIdx2]; - const Vec3d& p2 = initVertexPositions[pIdx3]; + const Vec3d& p0 = initVertexPositions[pIdx0]; + const Vec3d& p1 = initVertexPositions[pIdx1]; + const Vec3d& p2 = initVertexPositions[pIdx2]; // Instead of using the angle between the segments we can use the distance // from the center of the triangle @@ -46,53 +48,35 @@ PbdBendConstraint::initConstraint( } bool -PbdBendConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) +PbdBendConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const { - const size_t i1 = m_vertexIds[0]; - const size_t i2 = m_vertexIds[1]; - const size_t i3 = m_vertexIds[2]; + const size_t i0 = m_vertexIds[0]; + const size_t i1 = m_vertexIds[1]; + const size_t i2 = m_vertexIds[2]; - Vec3d& p0 = currVertexPositions[i1]; - Vec3d& p1 = currVertexPositions[i2]; - Vec3d& p2 = currVertexPositions[i3]; - - const Real im0 = currInvMasses[i1]; - const Real im1 = currInvMasses[i2]; - const Real im2 = currInvMasses[i3]; - - const Real m0 = (im0 > 0.0) ? 1.0 / im0 : 0.0; - const Real m1 = (im1 > 0.0) ? 1.0 / im1 : 0.0; - const Real m2 = (im2 > 0.0) ? 1.0 / im2 : 0.0; + const Vec3d& p0 = currVertexPositions[i0]; + const Vec3d& p1 = currVertexPositions[i1]; + const Vec3d& p2 = currVertexPositions[i2]; // Move towards triangle center const Vec3d& center = (p0 + p1 + p2) / 3.0; const Vec3d& diff = p1 - center; const double dist = diff.norm(); + if (dist < m_epsilon) { return false; } - const Vec3d& dir = diff / dist; - const double c = (dist - m_restLength) * m_stiffness; - - // Now Apply movement weighted by masses - if (im0 > 0.0) - { - p0 += c * dir * 2.0 * m0 / (m0 + m1 + m2); - } - if (im1 > 0.0) - { - p1 -= c * dir * 4.0 * m1 / (m0 + m1 + m2); - } + c = dist - m_restLength; - if (im2 > 0.0) - { - p2 += c * dir * 2.0 * m2 / (m0 + m1 + m2); - } + dcdx.resize(3); + dcdx[0] = (-2.0 / dist) * diff; + dcdx[1] = -2.0 * dcdx[0]; + dcdx[2] = dcdx[0]; return true; } -} // imstk \ No newline at end of file +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.h index 93d70a4b612190d1654d8ec93c0013a9f4a57f98..c2e68dc2f8702512a4f14127834fe361994831f2 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdBendConstraint.h @@ -53,7 +53,7 @@ public: / p2 \param model - \param pIdx1 index of p0 + \param pIdx0 index of p0 \param pIdx2 index of p1 \param pIdx3 index of p2 \param k stiffness @@ -64,14 +64,12 @@ public: const size_t& pIdx3, const double k); /// - /// \brief Solves the bend constraint + /// \brief Compute the value and gradient of constraint /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) override; - + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPosition, + double& c, + StdVectorOfVec3d& dcdx) const override; public: double m_restLength = 0.; ///> Rest length - double m_stiffness = 0.; ///> Bend stiffness }; } //imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp index 529c8103cdb64f2193a53a45cd13be91f296449b..dda274ce9101a8d8b14404fd0ee0bd6062378fa5 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.cpp @@ -29,4 +29,55 @@ PbdCollisionConstraint::PbdCollisionConstraint(const unsigned int& n1, const uns m_bodiesFirst.resize(n1); m_bodiesSecond.resize(n2); } -} // imstk \ No newline at end of file + +void +PbdCollisionConstraint::projectConstraint(const StdVectorOfReal& invMassA, + const StdVectorOfReal& invMassB, + StdVectorOfVec3d& posA, + StdVectorOfVec3d& posB) +{ + double c; + StdVectorOfVec3d dcdxA; + StdVectorOfVec3d dcdxB; + + bool update = this->computeValueAndGradient(posA, posB, c, dcdxA, dcdxB); + if (!update) + { + return; + } + + double lambda = 0.0; + + for (size_t i = 0; i < m_bodiesFirst.size(); ++i) + { + lambda += invMassA[m_bodiesFirst[i]] * dcdxA[i].squaredNorm(); + } + + for (size_t i = 0; i < m_bodiesSecond.size(); ++i) + { + lambda += invMassB[m_bodiesSecond[i]] * dcdxB[i].squaredNorm(); + } + + lambda = c / lambda; + + for (size_t i = 0, vid = 0; i < m_bodiesFirst.size(); ++i) + { + vid = m_bodiesFirst[i]; + if (invMassA[vid] > 0.0) + { + posA[vid] -= invMassA[vid] * lambda * dcdxA[i] * m_configA->m_stiffness; + } + } + + for (size_t i = 0, vid = 0; i < m_bodiesSecond.size(); ++i) + { + vid = m_bodiesSecond[i]; + if (invMassB[vid] > 0.0) + { + posB[vid] -= invMassB[vid] * lambda * dcdxB[i] * m_configB->m_stiffness; + } + } + + return; +} +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.h index 25beedc4823e27b2638d5c21ddebfd9fc65d1e9c..bd5270f7224acfaa8362fa49001b2e5bac916a5a 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdCollisionConstraint.h @@ -62,14 +62,35 @@ public: virtual ~PbdCollisionConstraint() = default; /// - /// \brief + /// \brief Get vertex indices of first object + /// + const std::vector<size_t>& getVertexIdsFirst() const { return m_bodiesFirst; } + const std::vector<size_t>& getVertexIdsSecond() const { return m_bodiesSecond; } + + /// + /// \brief Get config /// - virtual bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositionsA, - StdVectorOfVec3d& currVertexPositionsB, - const StdVectorOfReal& currInvMassesA, - const StdVectorOfReal& currInvMassesB) = 0; + const PbdCollisionConstraintConfig& getConfigFirst() const { return *m_configA; } + const PbdCollisionConstraintConfig& getConfigSecond() const { return *m_configB; } + /// + /// \brief compute value and gradient of constraint function + /// + /// \param[in] currVertexPositionsA current positions from object A + /// \param[in] currVertexPositionsA current positions from object B + /// \param[inout] c constraint value + /// \param[inout] dcdx constraint gradient + /// + virtual bool computeValueAndGradient(const StdVectorOfVec3d& posA, + const StdVectorOfVec3d& posB, + double& c, + StdVectorOfVec3d& dcdxA, + StdVectorOfVec3d& dcdxB) const = 0; + + virtual void projectConstraint(const StdVectorOfReal& invMassA, + const StdVectorOfReal& invMassB, + StdVectorOfVec3d& posA, + StdVectorOfVec3d& posB); protected: std::vector<size_t> m_bodiesFirst; ///> index of points for the first object std::vector<size_t> m_bodiesSecond; ///> index of points for the second object diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp index 116d54f06490edd333eb7b669e7f9689f2073efc..03fe3fd841019825d024481ad38f58ffb441640d 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp @@ -44,10 +44,11 @@ PbdConstantDensityConstraint::initConstraint(const StdVectorOfVec3d& initVertexP m_NeighborSearcher = std::make_shared<NeighborSearch>(m_NeighborSearchMethod, m_maxDist); } -bool -PbdConstantDensityConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) +void +PbdConstantDensityConstraint::projectConstraint(const StdVectorOfReal& currInvMasses, + const double dt, + const PbdConstraint::SolverType& type, + StdVectorOfVec3d& currVertexPositions) { const size_t numParticles = currVertexPositions.size(); @@ -68,8 +69,6 @@ PbdConstantDensityConstraint::solvePositionConstraint( [&](const size_t idx) { updatePositions(currVertexPositions[idx], idx, currVertexPositions); }); - - return true; } double diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h index d5df78118e277daf8da38de48993d8a185827177..81f97b656f2a54f98b8c07ad9640af60e30f50e6 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h @@ -59,9 +59,17 @@ public: /// /// \brief Solves the constant density constraint /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) override; + void projectConstraint(const StdVectorOfReal& currInvMasses, + const double dt, + const PbdConstraint::SolverType& type, + StdVectorOfVec3d& currVertexPositions) override; + + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const + { + return true; + } private: /// diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdConstraint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..443c2a17ad140350c8ed738534e314f6a40b1d09 --- /dev/null +++ b/Source/Constraint/PbdConstraints/imstkPbdConstraint.cpp @@ -0,0 +1,79 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkPbdConstraint.h" + +namespace imstk +{ +void +PbdConstraint::projectConstraint(const StdVectorOfReal& invMasses, const double dt, const SolverType& solverType, StdVectorOfVec3d& pos) +{ + double c; + StdVectorOfVec3d dcdx; + + bool update = this->computeValueAndGradient(pos, c, dcdx); + if (!update) + { + return; + } + + double dcMidc = 0.0; + double lambda = 0.0; + double alpha; + + for (size_t i = 0; i < m_vertexIds.size(); ++i) + { + dcMidc += invMasses[m_vertexIds[i]] * dcdx[i].squaredNorm(); + } + + if (dcMidc < VERY_SMALL_EPSILON) + { + return; + } + + switch (solverType) + { + case (SolverType::xPBD): + alpha = m_compliance / (dt * dt); + lambda = -(c + alpha * m_lambda) / (dcMidc + alpha); + m_lambda += lambda; + break; + case (SolverType::PBD): + lambda = -c * m_stiffness / dcMidc; + break; + default: + alpha = m_compliance / (dt * dt); + lambda = -(c + alpha * m_lambda) / (dcMidc + alpha); + m_lambda += lambda; + } + + for (size_t i = 0, vid = 0; i < m_vertexIds.size(); ++i) + { + vid = m_vertexIds[i]; + if (invMasses[vid] > 0.0) + { + pos[vid] += invMasses[vid] * lambda * dcdx[i]; + } + } + + return; +} +} diff --git a/Source/Constraint/PbdConstraints/imstkPbdConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdConstraint.h index dd556980845d1529c8f9fbdcb96c811bc06f41f0..927fc9eeffc0e5e0172a29a619997a5fd97e0883 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdConstraint.h @@ -47,6 +47,14 @@ public: None }; + /// + /// \brief Type of solvers + enum class SolverType + { + xPBD = 0, + PBD, + GCD + }; /// /// \brief Constructor /// @@ -64,13 +72,15 @@ public: virtual Type getType() const = 0; /// - /// \brief compute delta position from the constraint function - /// \param model \class PbdModel - /// \return true if succeeded + /// \brief Compute value and gradient of the constraint + /// + /// \param[in] currVertexPositions vector of current positions + /// \param[inout] c constraint value + /// \param[inout] dcdx constraint gradient /// - virtual bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) = 0; + virtual bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const = 0; /// /// \brief Get the vertex indices of the constraint @@ -87,9 +97,35 @@ public: /// double getTolerance() const { return m_epsilon; } + /// + /// \brief Set the stiffness + /// + void setStiffness(const double stiffness) + { + m_stiffness = stiffness; + m_compliance = 1.0 / stiffness; + } + + /// + /// \brief Get the stiffness + /// + double getStiffness() const { return m_stiffness; } + + /// + /// \brief Use PBD + /// + void zeroOutLambda() { m_lambda = 0.0; } + + /// + /// \brief Update positions by projecting constraints. + /// + virtual void projectConstraint(const StdVectorOfReal& currInvMasses, const double dt, const SolverType& type, StdVectorOfVec3d& pos); protected: std::vector<size_t> m_vertexIds; ///> index of points for the constraint - double m_epsilon = 1.0e-16; ///> Tolerance used for the costraints + double m_epsilon = 1.0e-16; ///> Tolerance used for the costraints + double m_stiffness = 1.0; ///> used in PBD, [0, 1] + double m_compliance = 1e-7; ///> used in xPBD, inverse of Young's Modulus + mutable double m_lambda = 0.0; ///> Lagrange multiplier }; using PBDConstraintVector = std::vector<std::shared_ptr<PbdConstraint>>; diff --git a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp index f3e83e96cc6fbbb7fabe827ef26922b60bb3317f..d45e2edd87341aa2e7d24fe589cef5e3411168b4 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.cpp @@ -20,26 +20,30 @@ =========================================================================*/ #include "imstkPbdDihedralConstraint.h" +#include <iostream> namespace imstk { void PbdDihedralConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, - const size_t& pIdx3, const size_t& pIdx4, - const double k) + const size_t& pIdx0, + const size_t& pIdx1, + const size_t& pIdx2, + const size_t& pIdx3, + const double k) { - m_vertexIds[0] = pIdx1; - m_vertexIds[1] = pIdx2; - m_vertexIds[2] = pIdx3; - m_vertexIds[3] = pIdx4; + m_vertexIds[0] = pIdx0; + m_vertexIds[1] = pIdx1; + m_vertexIds[2] = pIdx2; + m_vertexIds[3] = pIdx3; - m_stiffness = k; + m_stiffness = k; + m_compliance = 1.0 / k; - const Vec3d& p0 = initVertexPositions[pIdx1]; - const Vec3d& p1 = initVertexPositions[pIdx2]; - const Vec3d& p2 = initVertexPositions[pIdx3]; - const Vec3d& p3 = initVertexPositions[pIdx4]; + const Vec3d& p0 = initVertexPositions[pIdx0]; + const Vec3d& p1 = initVertexPositions[pIdx1]; + const Vec3d& p2 = initVertexPositions[pIdx2]; + const Vec3d& p3 = initVertexPositions[pIdx3]; const Vec3d n1 = (p2 - p0).cross(p3 - p0).normalized(); const Vec3d n2 = (p3 - p1).cross(p2 - p1).normalized(); @@ -48,29 +52,19 @@ PbdDihedralConstraint::initConstraint(const StdVectorOfVec3d& initVertexPosition } bool -PbdDihedralConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& invMasses) +PbdDihedralConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const { - const auto i1 = m_vertexIds[0]; - const auto i2 = m_vertexIds[1]; - const auto i3 = m_vertexIds[2]; - const auto i4 = m_vertexIds[3]; - - Vec3d& p0 = currVertexPositions[i1]; - Vec3d& p1 = currVertexPositions[i2]; - Vec3d& p2 = currVertexPositions[i3]; - Vec3d& p3 = currVertexPositions[i4]; - - const auto im0 = invMasses[i1]; - const auto im1 = invMasses[i2]; - const auto im2 = invMasses[i3]; - const auto im3 = invMasses[i4]; - - if (im0 == 0.0 && im1 == 0.0) - { - return false; - } + const auto i0 = m_vertexIds[0]; + const auto i1 = m_vertexIds[1]; + const auto i2 = m_vertexIds[2]; + const auto i3 = m_vertexIds[3]; + + const Vec3d& p0 = currVertexPositions[i0]; + const Vec3d& p1 = currVertexPositions[i1]; + const Vec3d& p2 = currVertexPositions[i2]; + const Vec3d& p3 = currVertexPositions[i3]; const auto e = p3 - p2; const auto e1 = p3 - p0; @@ -91,39 +85,14 @@ PbdDihedralConstraint::solvePositionConstraint( return false; } - const Vec3d grad0 = -(l / A1) * n1; - const Vec3d grad1 = -(l / A2) * n2; - const Vec3d grad2 = (e.dot(e1) / (A1 * l)) * n1 + (e.dot(e3) / (A2 * l)) * n2; - const Vec3d grad3 = (e.dot(e2) / (A1 * l)) * n1 + (e.dot(e4) / (A2 * l)) * n2; - - auto lambda = im0 * grad0.squaredNorm() + - im1 * grad1.squaredNorm() + - im2 * grad2.squaredNorm() + - im3 * grad3.squaredNorm(); - - // huge difference if use acos instead of atan2 - lambda = (atan2(n1.cross(n2).dot(e), l * n1.dot(n2)) - m_restAngle) / lambda * m_stiffness; - - if (im0 > 0) - { - p0 += -im0 * lambda * grad0; - } + dcdx.resize(4); + dcdx[0] = -(l / A1) * n1; + dcdx[1] = -(l / A2) * n2; + dcdx[2] = (e.dot(e1) / (A1 * l)) * n1 + (e.dot(e3) / (A2 * l)) * n2; + dcdx[3] = (e.dot(e2) / (A1 * l)) * n1 + (e.dot(e4) / (A2 * l)) * n2; - if (im1 > 0) - { - p1 += -im1 * lambda * grad1; - } - - if (im2 > 0) - { - p2 += -im2 * lambda * grad2; - } - - if (im3 > 0) - { - p3 += -im3 * lambda * grad3; - } + c = atan2(n1.cross(n2).dot(e), l * n1.dot(n2)) - m_restAngle; return true; } -} // imstk \ No newline at end of file +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.h index 44c1dc173d99ebab18ce097d93a2a44ce93a7e73..98ad174c203726cf03ff14263504481b79aa5ca4 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdDihedralConstraint.h @@ -61,19 +61,22 @@ public: */ void initConstraint( const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, - const size_t& pIdx3, const size_t& pIdx4, + const size_t& pIdx0, const size_t& pIdx1, + const size_t& pIdx2, const size_t& pIdx3, const double k); /// - /// \brief Solves the dihedral angular constraint + /// \brief Compute value and gradient of the constraint /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& invMasses) override; + /// \param[in] currVertexPositions vector of current positions + /// \param[inout] c constraint value + /// \param[inout] dcdx constraint gradient + /// + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const override; public: double m_restAngle = 0.0; ///> Rest angle - double m_stiffness = 0.0; ///> Angular stiffness }; } //imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.cpp index 7c01fbdbf1a7f38a523547a4ec53aadb2d7dcdd5..f0815882793e062cb43330b643a06f8264a4bf77 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.cpp @@ -24,56 +24,37 @@ namespace imstk { void -PbdDistanceConstraint::initConstraint( - const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, const double k) +PbdDistanceConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, + const size_t& pIdx0, + const size_t& pIdx1, + const double k) { - m_vertexIds[0] = pIdx1; - m_vertexIds[1] = pIdx2; + m_vertexIds[0] = pIdx0; + m_vertexIds[1] = pIdx1; m_stiffness = k; + m_compliance = 1.0 / k; + const Vec3d& p0 = initVertexPositions[pIdx0]; const Vec3d& p1 = initVertexPositions[pIdx1]; - const Vec3d& p2 = initVertexPositions[pIdx2]; - m_restLength = (p1 - p2).norm(); + m_restLength = (p0 - p1).norm(); } bool -PbdDistanceConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) +PbdDistanceConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const { - const size_t i1 = m_vertexIds[0]; - const size_t i2 = m_vertexIds[1]; + const Vec3d& p0 = currVertexPositions[m_vertexIds[0]]; + const Vec3d& p1 = currVertexPositions[m_vertexIds[1]]; + dcdx.resize(m_vertexIds.size()); - Vec3d& p0 = currVertexPositions[i1]; - Vec3d& p1 = currVertexPositions[i2]; + dcdx[0] = p0 - p1; + const double len = dcdx[0].norm(); + dcdx[0] /= len; + dcdx[1] = -dcdx[0]; + c = len - m_restLength; - const Real im1 = currInvMasses[i1]; - const Real im2 = currInvMasses[i2]; - - const auto wsum = im1 + im2; - - if (wsum == 0.0) - { - return false; - } - - Vec3d n = p1 - p0; - const auto len = n.norm(); - n /= len; - - const Vec3d gradC = n * m_stiffness * (len - m_restLength) / wsum; - - if (im1 > 0) - { - p0 += im1 * gradC; - } - - if (im2 > 0) - { - p1 += -im2 * gradC; - } return true; } -} // imstk \ No newline at end of file +} diff --git a/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.h index 72ccda29de33bfc5d9b969d79cd8cf4aec0f8715..12a7516718723d43461778b97f7ef90b6c3be1b5 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdDistanceConstraint.h @@ -46,19 +46,16 @@ public: /// /// \brief Initializes the distance constraint /// - void initConstraint( - const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, const double k = 1e-1); + void initConstraint(const StdVectorOfVec3d& initVertexPositions, + const size_t& pIdx0, + const size_t& pIdx1, + const double k = 1e5); - /// - /// \brief Solves the Distance constraint - /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) override; + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const override; public: double m_restLength = 0.0; ///> Rest length between the nodes - double m_stiffness = 0.0; ///> Stiffness of the constaint }; -} // imstk \ No newline at end of file +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp index 0aed930f7866a07a40fabe813dc5ce50a356b047..85986e9963e3690f7977c2f6e1854dd387c8b30f 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.cpp @@ -25,11 +25,12 @@ namespace imstk { void -PbdEdgeEdgeConstraint::initConstraint( - const size_t& pIdxA1, const size_t& pIdxA2, - const size_t& pIdxB1, const size_t& pIdxB2, - std::shared_ptr<PbdCollisionConstraintConfig> configA, - std::shared_ptr<PbdCollisionConstraintConfig> configB) +PbdEdgeEdgeConstraint::initConstraint(const size_t& pIdxA1, + const size_t& pIdxA2, + const size_t& pIdxB1, + const size_t& pIdxB2, + std::shared_ptr<PbdCollisionConstraintConfig> configA, + std::shared_ptr<PbdCollisionConstraintConfig> configB) { m_configA = configA; m_configB = configB; @@ -40,21 +41,21 @@ PbdEdgeEdgeConstraint::initConstraint( } bool -PbdEdgeEdgeConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositionsA, - StdVectorOfVec3d& currVertexPositionsB, - const StdVectorOfReal& currInvMassesA, - const StdVectorOfReal& currInvMassesB) +PbdEdgeEdgeConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositionsA, + const StdVectorOfVec3d& currVertexPositionsB, + double& cc, + StdVectorOfVec3d& dcdxA, + StdVectorOfVec3d& dcdxB) const { const auto i0 = m_bodiesFirst[0]; const auto i1 = m_bodiesFirst[1]; const auto i2 = m_bodiesSecond[0]; const auto i3 = m_bodiesSecond[1]; - Vec3d& x0 = currVertexPositionsA[i0]; - Vec3d& x1 = currVertexPositionsA[i1]; - Vec3d& x2 = currVertexPositionsB[i2]; - Vec3d& x3 = currVertexPositionsB[i3]; + const Vec3d& x0 = currVertexPositionsA[i0]; + const Vec3d& x1 = currVertexPositionsA[i1]; + const Vec3d& x2 = currVertexPositionsB[i2]; + const Vec3d& x3 = currVertexPositionsB[i3]; auto a = (x3 - x2).dot(x1 - x0); auto b = (x1 - x0).dot(x1 - x0); @@ -72,6 +73,7 @@ PbdEdgeEdgeConstraint::solvePositionConstraint( t = (c * d - a * f) / det; if (s < 0 || s > 1.0 || t < 0 || t > 1.0) { + c = 0.0; return false; } } @@ -91,47 +93,18 @@ PbdEdgeEdgeConstraint::solvePositionConstraint( if (l > dist) { + c = 0.0; return false; } - Vec3d grad0 = -(1 - t) * n; - Vec3d grad1 = -(t) * n; - Vec3d grad2 = (1 - s) * n; - Vec3d grad3 = (s) * n; + dcdxA.resize(2); + dcdxB.resize(2); + dcdxA[0] = -(1 - t) * n; + dcdxA[1] = -(t) * n; + dcdxB[0] = (1 - s) * n; + dcdxB[1] = (s) * n; - const auto im0 = currInvMassesA[i0]; - const auto im1 = currInvMassesA[i1]; - const auto im2 = currInvMassesB[i2]; - const auto im3 = currInvMassesB[i3]; - - auto lambda = im0 * grad0.squaredNorm() + - im1 * grad1.squaredNorm() + - im2 * grad2.squaredNorm() + - im3 * grad3.squaredNorm(); - - lambda = (l - dist) / lambda; - -// LOG(INFO) << "Lambda:" << lambda <<" Normal:" << n[0] <<" " << n[1] <<" "<<n[2]; - - if (im0 > 0) - { - x0 += -im0 * lambda * grad0 * m_configA->m_stiffness; - } - - if (im1 > 0) - { - x1 += -im1 * lambda * grad1 * m_configA->m_stiffness; - } - - if (im2 > 0) - { - x2 += -im2 * lambda * grad2 * m_configB->m_stiffness; - } - - if (im3 > 0) - { - x3 += -im3 * lambda * grad3 * m_configB->m_stiffness; - } + cc = l - dist; return true; } diff --git a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.h index c424f47063976545dce76dc08aaa6f214385d5f2..74b519b35c10956bd23f0e0c7a7e456bf0c61af4 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdEdgeEdgeCollisionConstraint.h @@ -53,12 +53,17 @@ public: std::shared_ptr<PbdCollisionConstraintConfig> configB); /// - /// \brief Solve edge-edge collision constraint + /// \brief compute value and gradient of constraint function /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositionsA, - StdVectorOfVec3d& currVertexPositionsB, - const StdVectorOfReal& currInvMassesA, - const StdVectorOfReal& currInvMassesB) override; + /// \param[in] currVertexPositionsA current positions from object A + /// \param[in] currVertexPositionsA current positions from object B + /// \param[inout] c constraint value + /// \param[inout] dcdx constraint gradient + /// + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositionsA, + const StdVectorOfVec3d& currVertexPositionsB, + double& c, + StdVectorOfVec3d& dcdxA, + StdVectorOfVec3d& dcdxB) const override; }; -} +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdFEMConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdFEMConstraint.h index f71cbc8584097872b9d67c2bd9d3048aa6b420ae..d06dea03362a70a519005fff7082e62c5613da91 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdFEMConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdFEMConstraint.h @@ -74,6 +74,6 @@ public: MaterialType m_material; ///> Material type Mat3d m_invRestMat; - std::shared_ptr<PbdFEMConstraintConfig> config = nullptr; + std::shared_ptr<PbdFEMConstraintConfig> m_config = nullptr; }; -} +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp index c76d78852e044cb37d5b34c8b967d32dd7650bc8..4763b2f29c6d5d94db7561aec5eac5eb262a230d 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.cpp @@ -21,27 +21,29 @@ #include "imstkPbdFETetConstraint.h" #include "imstkLogger.h" +#include <iostream> namespace imstk { bool PbdFEMTetConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, - const size_t& pIdx3, const size_t& pIdx4, + const size_t& pIdx0, const size_t& pIdx1, + const size_t& pIdx2, const size_t& pIdx3, std::shared_ptr<PbdFEMConstraintConfig> config) { - m_vertexIds[0] = pIdx1; - m_vertexIds[1] = pIdx2; - m_vertexIds[2] = pIdx3; - m_vertexIds[3] = pIdx4; + m_vertexIds[0] = pIdx0; + m_vertexIds[1] = pIdx1; + m_vertexIds[2] = pIdx2; + m_vertexIds[3] = pIdx3; - const Vec3d& p0 = initVertexPositions[pIdx1]; - const Vec3d& p1 = initVertexPositions[pIdx2]; - const Vec3d& p2 = initVertexPositions[pIdx3]; - const Vec3d& p3 = initVertexPositions[pIdx4]; + const Vec3d& p0 = initVertexPositions[pIdx0]; + const Vec3d& p1 = initVertexPositions[pIdx1]; + const Vec3d& p2 = initVertexPositions[pIdx2]; + const Vec3d& p3 = initVertexPositions[pIdx3]; m_elementVolume = (1.0 / 6.0) * (p3 - p0).dot((p1 - p0).cross(p2 - p0)); - this->config = config; + m_config = config; + m_compliance = 1.0 / (config->m_lambda + 2 * config->m_mu); Mat3d m; m.col(0) = p0 - p3; @@ -59,21 +61,19 @@ PbdFEMTetConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, } bool -PbdFEMTetConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) +PbdFEMTetConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& cval, + StdVectorOfVec3d& dcdx) const { - const auto i1 = m_vertexIds[0]; - const auto i2 = m_vertexIds[1]; - const auto i3 = m_vertexIds[2]; - const auto i4 = m_vertexIds[3]; + const auto i0 = m_vertexIds[0]; + const auto i1 = m_vertexIds[1]; + const auto i2 = m_vertexIds[2]; + const auto i3 = m_vertexIds[3]; - Vec3d& p0 = currVertexPositions[i1]; - Vec3d& p1 = currVertexPositions[i2]; - Vec3d& p2 = currVertexPositions[i3]; - Vec3d& p3 = currVertexPositions[i4]; - - //double currentVolume = (1.0 / 6.0) * (p3 - p0).dot((p1 - p0).cross(p2 - p0)); + const Vec3d& p0 = currVertexPositions[i0]; + const Vec3d& p1 = currVertexPositions[i1]; + const Vec3d& p2 = currVertexPositions[i2]; + const Vec3d& p3 = currVertexPositions[i3]; Mat3d m; m.col(0) = p0 - p3; @@ -87,8 +87,8 @@ PbdFEMTetConstraint::solvePositionConstraint( // energy constraint double C = 0; - const auto mu = config->m_mu; - const auto lambda = config->m_lambda; + const auto mu = m_config->m_mu; + const auto lambda = m_config->m_lambda; switch (m_material) { @@ -174,46 +174,14 @@ PbdFEMTetConstraint::solvePositionConstraint( } } - const double im1 = currInvMasses[i1]; - const double im2 = currInvMasses[i2]; - const double im3 = currInvMasses[i3]; - const double im4 = currInvMasses[i4]; - Mat3d gradC = m_elementVolume * P * m_invRestMat.transpose(); - - const double sum = im1 * gradC.col(0).squaredNorm() - + im2 * gradC.col(1).squaredNorm() - + im3 * gradC.col(2).squaredNorm() - + im4 * (gradC.col(0) + gradC.col(1) + gradC.col(2)).squaredNorm(); - - if (sum < m_epsilon) - { - return false; - } - - C = C * m_elementVolume; - - const double s = C / sum; - - if (im1 > 0) - { - p0 += -s* im1* gradC.col(0); - } - - if (im2 > 0) - { - p1 += -s* im2* gradC.col(1); - } - - if (im3 > 0) - { - p2 += -s* im3* gradC.col(2); - } - - if (im4 > 0) - { - p3 += s * im4 * (gradC.col(0) + gradC.col(1) + gradC.col(2)); - } + cval = C; + cval *= m_elementVolume; + dcdx.resize(m_vertexIds.size()); + dcdx[0] = gradC.col(0); + dcdx[1] = gradC.col(1); + dcdx[2] = gradC.col(2); + dcdx[3] = -dcdx[0] - dcdx[1] - dcdx[2]; return true; } diff --git a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.h index fa52ece9d3b6de25d4f7c308a244013a38ca4cd1..b2dc8e3d2e0111e9884f275844c7b15f216e0084 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdFETetConstraint.h @@ -54,10 +54,10 @@ public: std::shared_ptr<PbdFEMConstraintConfig> config); /// - /// \brief Solve the tetrahedral FEM constraint + /// \brief Compute the value and gradient of constraint /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) override; + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPosition, + double& c, + StdVectorOfVec3d& dcdx) const override; }; } // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp index 3345de7bfc5ce8b8128babe323f3df1e028d90f6..75b13a8d9e49a1a6ab776c8a3cd7b9e55464758a 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.cpp @@ -26,8 +26,10 @@ namespace imstk { void -PbdPointTriangleConstraint::initConstraint(const size_t& pIdxA1, - const size_t& pIdxB1, const size_t& pIdxB2, const size_t& pIdxB3, +PbdPointTriangleConstraint::initConstraint(const size_t& pIdxA1, + const size_t& pIdxB1, + const size_t& pIdxB2, + const size_t& pIdxB3, std::shared_ptr<PbdCollisionConstraintConfig> configA, std::shared_ptr<PbdCollisionConstraintConfig> configB) { @@ -40,21 +42,21 @@ PbdPointTriangleConstraint::initConstraint(const size_t& pIdxA1, } bool -PbdPointTriangleConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositionsA, - StdVectorOfVec3d& currVertexPositionsB, - const StdVectorOfReal& currInvMassesA, - const StdVectorOfReal& currInvMassesB) +PbdPointTriangleConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositionsA, + const StdVectorOfVec3d& currVertexPositionsB, + double& c, + StdVectorOfVec3d& dcdxA, + StdVectorOfVec3d& dcdxB) const { const size_t i0 = m_bodiesFirst[0]; const size_t i1 = m_bodiesSecond[0]; const size_t i2 = m_bodiesSecond[1]; const size_t i3 = m_bodiesSecond[2]; - Vec3d& x0 = currVertexPositionsA[i0]; - Vec3d& x1 = currVertexPositionsB[i1]; - Vec3d& x2 = currVertexPositionsB[i2]; - Vec3d& x3 = currVertexPositionsB[i3]; + const Vec3d& x0 = currVertexPositionsA[i0]; + const Vec3d& x1 = currVertexPositionsB[i1]; + const Vec3d& x2 = currVertexPositionsB[i2]; + const Vec3d& x3 = currVertexPositionsB[i3]; const Vec3d x12 = x2 - x1; const Vec3d x13 = x3 - x1; @@ -67,6 +69,7 @@ PbdPointTriangleConstraint::solvePositionConstraint( if (alpha < 0 || beta < 0 || alpha + beta > 1) { //LOG(WARNING) << "Projection point not inside the triangle"; + c = 0.0; return false; } @@ -78,49 +81,19 @@ PbdPointTriangleConstraint::solvePositionConstraint( if (l > dist) { + c = 0.0; return false; } double gamma = 1.0 - alpha - beta; - Vec3d grad0 = n; - Vec3d grad1 = -alpha * n; - Vec3d grad2 = -beta * n; - Vec3d grad3 = -gamma * n; - - const Real im0 = currInvMassesA[i0]; - const Real im1 = currInvMassesB[i1]; - const Real im2 = currInvMassesB[i2]; - const Real im3 = currInvMassesB[i3]; - - double lambda = im0 * grad0.squaredNorm() + - im1 * grad1.squaredNorm() + - im2 * grad2.squaredNorm() + - im3 * grad3.squaredNorm(); - - lambda = (l - dist) / lambda; - - //LOG(INFO) << "Lambda:" << lambda <<" Normal:" << n[0] <<" " << n[1] <<" "<<n[2]; - - if (im0 > 0) - { - x0 += -im0 * lambda * grad0 * m_configA->m_stiffness; - } - - if (im1 > 0) - { - x1 += -im1 * lambda * grad1 * m_configB->m_stiffness; - } - - if (im2 > 0) - { - x2 += -im2 * lambda * grad2 * m_configB->m_stiffness; - } - - if (im3 > 0) - { - x3 += -im3 * lambda * grad3 * m_configB->m_stiffness; - } - + dcdxA.resize(1); + dcdxB.resize(3); + dcdxA[0] = n; + dcdxB[0] = -alpha * n; + dcdxB[1] = -beta * n; + dcdxB[2] = -gamma * n; + + c = l - dist; return true; } } // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.h index c4e7af7fb920705a70a84e1d2f17639459bbff03..dc6186775c3ce99bc1fa00956c3ff39a6a5c7631 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdPointTriCollisionConstraint.h @@ -56,12 +56,17 @@ public: std::shared_ptr<PbdCollisionConstraintConfig> configB); /// - /// \brief + /// \brief compute value and gradient of constraint function /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositionsA, - StdVectorOfVec3d& currVertexPositionsB, - const StdVectorOfReal& currInvMassesA, - const StdVectorOfReal& currInvMassesB) override; + /// \param[in] currVertexPositionsA current positions from object A + /// \param[in] currVertexPositionsA current positions from object B + /// \param[inout] c constraint value + /// \param[inout] dcdx constraint gradient + /// + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPositionsA, + const StdVectorOfVec3d& currVertexPositionsB, + double& c, + StdVectorOfVec3d& dcdxA, + StdVectorOfVec3d& dcdxB) const override; }; -} +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.cpp b/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.cpp index 83be1d9feb77a37db106c7763aee10c2a791520b..ef63215ebcfa6e58be138a90c170eb9f9012941f 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.cpp +++ b/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.cpp @@ -25,81 +25,49 @@ namespace imstk { void PbdVolumeConstraint::initConstraint(const StdVectorOfVec3d& initVertexPositions, - const size_t& pIdx1, const size_t& pIdx2, - const size_t& pIdx3, const size_t& pIdx4, - double k) + const size_t& pIdx0, const size_t& pIdx1, + const size_t& pIdx2, const size_t& pIdx3, + const double k) { - m_vertexIds[0] = pIdx1; - m_vertexIds[1] = pIdx2; - m_vertexIds[2] = pIdx3; - m_vertexIds[3] = pIdx4; + m_vertexIds[0] = pIdx0; + m_vertexIds[1] = pIdx1; + m_vertexIds[2] = pIdx2; + m_vertexIds[3] = pIdx3; - m_stiffness = k; + m_stiffness = k; + m_compliance = 1.0 / k; - const Vec3d& p0 = initVertexPositions[pIdx1]; - const Vec3d& p1 = initVertexPositions[pIdx2]; - const Vec3d& p2 = initVertexPositions[pIdx3]; - const Vec3d& p3 = initVertexPositions[pIdx4]; + const Vec3d& p0 = initVertexPositions[pIdx0]; + const Vec3d& p1 = initVertexPositions[pIdx1]; + const Vec3d& p2 = initVertexPositions[pIdx2]; + const Vec3d& p3 = initVertexPositions[pIdx3]; m_restVolume = (1.0 / 6.0) * ((p1 - p0).cross(p2 - p0)).dot(p3 - p0); } bool -PbdVolumeConstraint::solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) +PbdVolumeConstraint::computeValueAndGradient(const StdVectorOfVec3d& currVertexPositions, + double& c, + StdVectorOfVec3d& dcdx) const { - const auto i1 = m_vertexIds[0]; - const auto i2 = m_vertexIds[1]; - const auto i3 = m_vertexIds[2]; - const auto i4 = m_vertexIds[3]; + const auto i0 = m_vertexIds[0]; + const auto i1 = m_vertexIds[1]; + const auto i2 = m_vertexIds[2]; + const auto i3 = m_vertexIds[3]; - Vec3d& x1 = currVertexPositions[i1]; - Vec3d& x2 = currVertexPositions[i2]; - Vec3d& x3 = currVertexPositions[i3]; - Vec3d& x4 = currVertexPositions[i4]; - - const auto im1 = currInvMasses[i1]; - const auto im2 = currInvMasses[i2]; - const auto im3 = currInvMasses[i3]; - const auto im4 = currInvMasses[i4]; + const Vec3d& x0 = currVertexPositions[i0]; + const Vec3d& x1 = currVertexPositions[i1]; + const Vec3d& x2 = currVertexPositions[i2]; + const Vec3d& x3 = currVertexPositions[i3]; const double onesixth = 1.0 / 6.0; - const Vec3d grad1 = onesixth * (x2 - x3).cross(x4 - x2); - const Vec3d grad2 = onesixth * (x3 - x1).cross(x4 - x1); - const Vec3d grad3 = onesixth * (x4 - x1).cross(x2 - x1); - const Vec3d grad4 = onesixth * (x2 - x1).cross(x3 - x1); - - const auto V = grad4.dot(x4 - x1); - - double lambda = im1 * grad1.squaredNorm() + - im2 * grad2.squaredNorm() + - im3 * grad3.squaredNorm() + - im4 * grad4.squaredNorm(); - - lambda = (V - m_restVolume) / lambda * m_stiffness; - - if (im1 > 0) - { - x1 += -im1 * lambda * grad1; - } - - if (im2 > 0) - { - x2 += -im2 * lambda * grad2; - } - - if (im3 > 0) - { - x3 += -im3 * lambda * grad3; - } - - if (im4 > 0) - { - x4 += -im4 * lambda * grad4; - } + dcdx[0] = onesixth * (x1 - x2).cross(x3 - x1); + dcdx[1] = onesixth * (x2 - x0).cross(x3 - x0); + dcdx[2] = onesixth * (x3 - x0).cross(x1 - x0); + dcdx[3] = onesixth * (x1 - x0).cross(x2 - x0); + c = dcdx[3].dot(x3 - x0); return true; } -} // imstk \ No newline at end of file +} // imstk diff --git a/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.h b/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.h index 30b2c4ea47b974da3d92cc2ce57f4cedd1aca516..7f92dc4eba9a35b8e006476e9628dd1950300daa 100644 --- a/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.h +++ b/Source/Constraint/PbdConstraints/imstkPbdVolumeConstraint.h @@ -49,17 +49,16 @@ public: void initConstraint(const StdVectorOfVec3d& initVertexPositions, const size_t& pIdx1, const size_t& pIdx2, const size_t& pIdx3, const size_t& pIdx4, - double k = 2.0); + const double k = 2.0); /// - /// \brief Solves the volume constraint + /// \brief Compute the value and gradient of constraint /// - bool solvePositionConstraint( - StdVectorOfVec3d& currVertexPositions, - const StdVectorOfReal& currInvMasses) override; + bool computeValueAndGradient(const StdVectorOfVec3d& currVertexPosition, + double& c, + StdVectorOfVec3d& dcdx) const override; protected: double m_restVolume = 0.0; ///> Rest volume - double m_stiffness = 1.0; }; -} +} // imstk diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp index 194e1299ca8c77971ecbb16c8483167d9e4d6452..a5a583654b712f1d1df16e669756a55adaa4e6d8 100644 --- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp @@ -44,7 +44,7 @@ PbdModel::PbdModel() : DynamicalModel(DynamicalModelType::PositionBasedDynamics) m_partitionedConstraints(std::make_shared<std::vector<PBDConstraintVector>>()), m_mass(std::make_shared<StdVectorOfReal>()), m_invMass(std::make_shared<StdVectorOfReal>()), - m_Parameters(std::make_shared<PBDModelConfig>()) + m_parameters(std::make_shared<PBDModelConfig>()) { m_validGeometryTypes = { Geometry::Type::PointSet, @@ -66,7 +66,7 @@ PBDModelConfig::enableConstraint(PbdConstraint::Type type, double stiffness) { LOG_IF(FATAL, (type == PbdConstraint::Type::FEMTet || type == PbdConstraint::Type::FEMHex)) << "FEM constraint should be enabled by the enableFEMConstraint function"; - m_RegularConstraints.push_back({ type, stiffness }); + m_regularConstraints.push_back({ type, stiffness }); } void @@ -82,7 +82,7 @@ PbdModel::configure(std::shared_ptr<PBDModelConfig> params) { LOG_IF(FATAL, (!this->getModelGeometry())) << "PbdModel::configure - Set PBD Model geometry before configuration!"; - m_Parameters = params; + m_parameters = params; this->setNumDegreeOfFreedom(std::dynamic_pointer_cast<PointSet>(m_geometry)->getNumVertices() * 3); } @@ -104,9 +104,9 @@ PbdModel::initialize() m_mass->resize(numParticles, 0); m_invMass->resize(numParticles, 0); - setUniformMass(m_Parameters->m_uniformMassValue); + setUniformMass(m_parameters->m_uniformMassValue); - for (auto i : m_Parameters->m_fixedNodeIds) + for (auto i : m_parameters->m_fixedNodeIds) { setFixedPoint(i); } @@ -117,15 +117,17 @@ PbdModel::initialize() if (m_pbdSolver == nullptr) { m_pbdSolver = std::make_shared<PbdSolver>(); - m_pbdSolver->setIterations(m_Parameters->m_iterations); + m_pbdSolver->setIterations(m_parameters->m_iterations); + m_pbdSolver->setSolverType(m_parameters->m_solverType); } m_pbdSolver->setPositions(getCurrentState()->getPositions()); m_pbdSolver->setInvMasses(getInvMasses()); m_pbdSolver->setConstraints(getConstraints()); m_pbdSolver->setPartitionedConstraints(getPartitionedConstraints()); + m_pbdSolver->setTimeStep(m_parameters->m_dt); // Initialize FEM constraints - for (auto& constraint: m_Parameters->m_FEMConstraints) + for (auto& constraint: m_parameters->m_FEMConstraints) { computeElasticConstants(); if (!initializeFEMConstraints(constraint.second)) @@ -135,8 +137,17 @@ PbdModel::initialize() } // Initialize other constraints - for (auto& constraint: m_Parameters->m_RegularConstraints) + for (auto& constraint: m_parameters->m_regularConstraints) { + if (m_parameters->m_solverType == PbdConstraint::SolverType::PBD && constraint.second > 1.0) + { + LOG(WARNING) << "for PBD, k should be between [0, 1]"; + } + else if (m_parameters->m_solverType == PbdConstraint::SolverType::xPBD && constraint.second <= 1.0) + { + LOG(WARNING) << "for xPBD, k is Young's Modulu, and should be much larger than 1"; + } + if (!bOK) { return false; @@ -173,7 +184,11 @@ PbdModel::initialize() } // Partition constraints for parallel computation - partitionConstraints(); + if (!m_partitioned) + { + this->partitionConstraints(); + m_partitioned = true; + } this->setTimeStepSizeType(m_timeStepSizeType); @@ -194,20 +209,20 @@ PbdModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskN void PbdModel::computeElasticConstants() { - if (std::abs(m_Parameters->femParams->m_mu) < MIN_REAL - && std::abs(m_Parameters->femParams->m_lambda) < MIN_REAL) + if (std::abs(m_parameters->m_femParams->m_mu) < MIN_REAL + && std::abs(m_parameters->m_femParams->m_lambda) < MIN_REAL) { - const auto E = m_Parameters->femParams->m_YoungModulus; - const auto nu = m_Parameters->femParams->m_PoissonRatio; - m_Parameters->femParams->m_mu = E / Real(2.0) / (Real(1.0) + nu); - m_Parameters->femParams->m_lambda = E * nu / ((Real(1.0) + nu) * (Real(1.0) - Real(2.0) * nu)); + const auto E = m_parameters->m_femParams->m_YoungModulus; + const auto nu = m_parameters->m_femParams->m_PoissonRatio; + m_parameters->m_femParams->m_mu = E / Real(2.0) / (Real(1.0) + nu); + m_parameters->m_femParams->m_lambda = E * nu / ((Real(1.0) + nu) * (Real(1.0) - Real(2.0) * nu)); } else { - const auto mu = m_Parameters->femParams->m_mu; - const auto lambda = m_Parameters->femParams->m_lambda; - m_Parameters->femParams->m_YoungModulus = mu * (Real(3.0) * lambda + Real(2.0) * mu) / (lambda + mu); - m_Parameters->femParams->m_PoissonRatio = lambda / Real(2.0) / (lambda + mu); + const auto mu = m_parameters->m_femParams->m_mu; + const auto lambda = m_parameters->m_femParams->m_lambda; + m_parameters->m_femParams->m_YoungModulus = mu * (Real(3.0) * lambda + Real(2.0) * mu) / (lambda + mu); + m_parameters->m_femParams->m_PoissonRatio = lambda / Real(2.0) / (lambda + mu); } } @@ -229,7 +244,7 @@ PbdModel::initializeFEMConstraints(PbdFEMConstraint::MaterialType type) auto& tet = elements[k]; auto c = std::make_shared<PbdFEMTetConstraint>(type); c->initConstraint(*m_initialState->getPositions(), - tet[0], tet[1], tet[2], tet[3], m_Parameters->femParams); + tet[0], tet[1], tet[2], tet[3], m_parameters->m_femParams); lock.lock(); m_constraints->push_back(std::move(c)); lock.unlock(); @@ -496,7 +511,10 @@ void PbdModel::partitionConstraints(const bool print) { // Form the map { vertex : list_of_constraints_involve_vertex } - PBDConstraintVector& allConstraints = *m_constraints; + PBDConstraintVector& allConstraints = *m_constraints; + + //std::cout << "---------partitionConstraints: " << allConstraints.size() << std::endl; + std::unordered_map<size_t, std::vector<size_t>> vertexConstraints; for (size_t constrIdx = 0; constrIdx < allConstraints.size(); ++constrIdx) { @@ -524,7 +542,7 @@ PbdModel::partitionConstraints(const bool print) vertexConstraints.clear(); // do graph coloring for the constraint graph - const auto coloring = constraintGraph.doColoring(); + const auto coloring = constraintGraph.doColoring(Graph::ColoringMethod::WelshPowell); const auto& partitionIndices = coloring.first; const auto numPartitions = coloring.second; assert(partitionIndices.size() == allConstraints.size()); @@ -600,7 +618,7 @@ PbdModel::setTimeStepSizeType(const TimeSteppingType type) m_timeStepSizeType = type; if (type == TimeSteppingType::Fixed) { - m_Parameters->m_dt = m_Parameters->m_defaultDt; + m_parameters->m_dt = m_parameters->m_defaultDt; } } @@ -655,9 +673,9 @@ PbdModel::integratePosition() { if (std::abs(invMasses[i]) > MIN_REAL) { - vel[i] += (accn[i] + m_Parameters->m_gravity) * m_Parameters->m_dt; + vel[i] += (accn[i] + m_parameters->m_gravity) * m_parameters->m_dt; prevPos[i] = pos[i]; - pos[i] += (1.0 - m_Parameters->m_viscousDampingCoeff) * vel[i] * m_Parameters->m_dt; + pos[i] += (1.0 - m_parameters->m_viscousDampingCoeff) * vel[i] * m_parameters->m_dt; } }); } @@ -673,9 +691,9 @@ PbdModel::updateVelocity() ParallelUtils::parallelFor(m_mesh->getNumVertices(), [&](const size_t i) { - if (std::abs(invMasses[i]) > MIN_REAL && m_Parameters->m_dt > 0.0) + if (std::abs(invMasses[i]) > MIN_REAL && m_parameters->m_dt > 0.0) { - vel[i] = (pos[i] - prevPos[i]) / m_Parameters->m_dt; + vel[i] = (pos[i] - prevPos[i]) / m_parameters->m_dt; } }); } diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h index 4b837b16c0d3b57113ec485ccba37c711b1d9206..f141c33ff51736e1d620e1963615fb63e45a24bc 100644 --- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h +++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h @@ -25,6 +25,7 @@ #include "imstkPbdCollisionConstraint.h" #include "imstkPbdFEMConstraint.h" #include "imstkPbdState.h" +#include "imstkLogger.h" namespace imstk { @@ -55,7 +56,7 @@ struct PBDModelConfig std::vector<std::size_t> m_fixedNodeIds; ///> Nodal IDs of the nodes that are fixed Vec3r m_gravity = Vec3r(0, -9.81, 0); ///> Gravity - std::shared_ptr<PbdFEMConstraintConfig> femParams = + std::shared_ptr<PbdFEMConstraintConfig> m_femParams = std::make_shared<PbdFEMConstraintConfig>(PbdFEMConstraintConfig { 0.0, // Lame constant, if constraint type is FEM @@ -64,7 +65,7 @@ struct PBDModelConfig 0.2 // FEM parameter, if constraint type is FEM }); ///> Info shared between the fem constraints - std::vector<std::pair<PbdConstraint::Type, double>> m_RegularConstraints; ///> Constraints except FEM + std::vector<std::pair<PbdConstraint::Type, double>> m_regularConstraints; ///> Constraints except FEM std::vector<std::pair<PbdConstraint::Type, PbdFEMConstraint::MaterialType>> m_FEMConstraints; ///> Constraints except FEM /// @@ -77,6 +78,23 @@ struct PBDModelConfig /// \brief Enable a FEM constraint with mu, lambda /// void enableFEMConstraint(PbdConstraint::Type type, PbdFEMConstraint::MaterialType material); + + /// + /// \brief Set the PBD solver type + /// + void setSolverType(const PbdConstraint::SolverType& type) + { + if (type == PbdConstraint::SolverType::GCD) + { + LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead"; + m_solverType = PbdConstraint::SolverType::xPBD; + return; + } + + m_solverType = type; + } + + PbdConstraint::SolverType m_solverType = PbdConstraint::SolverType::xPBD; }; /// @@ -105,7 +123,7 @@ public: /// /// \brief Get the simulation parameters /// - const std::shared_ptr<PBDModelConfig>& getParameters() const { assert(m_Parameters); return m_Parameters; } + const std::shared_ptr<PBDModelConfig>& getParameters() const { assert(m_parameters); return m_parameters; } /// /// \brief Compute elastic constants: Young Modulus, Poisson Ratio, first and second Lame @@ -167,8 +185,8 @@ public: /// /// \brief Set the time step size /// - virtual void setTimeStep(const Real timeStep) override { m_Parameters->m_dt = timeStep; } - void setDefaultTimeStep(const Real timeStep) { m_Parameters->m_defaultDt = static_cast<Real>(timeStep); } + virtual void setTimeStep(const Real timeStep) override { m_parameters->m_dt = timeStep; } + void setDefaultTimeStep(const Real timeStep) { m_parameters->m_defaultDt = static_cast<Real>(timeStep); } /// /// \brief Set the time step size to fixed size @@ -178,8 +196,8 @@ public: /// /// \brief Returns the time step size /// - virtual double getTimeStep() const override { return m_Parameters->m_dt; } - double getDefaultTimeStep() const { return m_Parameters->m_defaultDt; } + virtual double getTimeStep() const override { return m_parameters->m_dt; } + double getDefaultTimeStep() const { return m_parameters->m_defaultDt; } /// /// \brief @@ -263,6 +281,7 @@ protected: void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override; protected: + bool m_partitioned = false; /// \todo this is used in initialize() as a temporary fix to problems on linux size_t m_partitionThreshold = 16; ///> Threshold for constraint partitioning std::shared_ptr<PbdSolver> m_pbdSolver = nullptr; ///> PBD solver @@ -272,7 +291,7 @@ protected: std::shared_ptr<PBDConstraintVector> m_constraints = nullptr; ///> List of pbd constraints std::shared_ptr<std::vector<PBDConstraintVector>> m_partitionedConstraints = nullptr; ///> List of pbd constraints - std::shared_ptr<PBDModelConfig> m_Parameters = nullptr; ///> Model parameters, must be set before simulation + std::shared_ptr<PBDModelConfig> m_parameters = nullptr; ///> Model parameters, must be set before simulation protected: // Computational Nodes diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h index 99868221a18399980496c509932ae8901e25d461..80805ca35b229869c5d7783f7dda3ffee12ae54d 100644 --- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h +++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h @@ -167,11 +167,11 @@ protected: #ifdef iMSTK_ENABLE_VR std::vector<vtkOpenVRCameraPose> m_camPos; #endif - vtkSmartPointer<vtkChartXY> m_timeTableChart = nullptr; vtkSmartPointer<vtkContextActor> m_timeTableChartActor = nullptr; vtkSmartPointer<vtkTable> m_timeTable = nullptr; vtkPlotBar* m_timeTablePlot = nullptr; int m_timeTableIter = 0; + }; } diff --git a/Source/Scene/imstkScene.h b/Source/Scene/imstkScene.h index 749aca0adbd5b89e49f2ffcdf6804ced1ad4c35a..9bb077ca445aa4587bac8dfca99678605839f1ea 100644 --- a/Source/Scene/imstkScene.h +++ b/Source/Scene/imstkScene.h @@ -281,8 +281,8 @@ protected: NamedMap<VisualModel> m_DebugRenderModelMap; NamedMap<Light> m_lightsMap; std::shared_ptr<IBLProbe> m_globalIBLProbe = nullptr; - std::shared_ptr<Camera> m_camera = std::make_shared<Camera>(); - std::shared_ptr<CollisionGraph> m_collisionGraph = std::make_shared<CollisionGraph>(); + std::shared_ptr<Camera> m_camera = nullptr; + std::shared_ptr<CollisionGraph> m_collisionGraph = nullptr; std::vector<std::shared_ptr<SceneObjectControllerBase>> m_objectControllers; ///> List of object controllers std::vector<std::shared_ptr<CameraController>> m_cameraControllers; ///> List of camera controllers std::unordered_map<std::string, std::thread> m_threadMap; ///> diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h index 7873b600521f8e7d02523688f402b8a1017001df..0bb255069f5d61a3dbad29c0d3491f71270c5a81 100644 --- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h @@ -115,7 +115,7 @@ protected: std::shared_ptr<VTKInteractorStyle> m_vtkInteractorStyle; bool m_enableVR; std::string m_windowName = "imstk"; - vtkSmartPointer<vtkCallbackCommand> timerCallbackCommand = nullptr; + vtkSmartPointer<vtkCallbackCommand> timerCallbackCommand; #ifdef iMSTK_ENABLE_VR vtkSmartPointer<OpenVRCommand> m_openVRCommand; diff --git a/Source/Solvers/imstkPbdSolver.cpp b/Source/Solvers/imstkPbdSolver.cpp index 25accfa1988a429ad1ad5d9188014056f7535dd6..a03ff5351351d8448fa6371394dc1600eaaffe29 100644 --- a/Source/Solvers/imstkPbdSolver.cpp +++ b/Source/Solvers/imstkPbdSolver.cpp @@ -42,23 +42,36 @@ PbdSolver::solve() const PBDConstraintVector& constraints = *m_constraints; const std::vector<PBDConstraintVector>& partitionedConstraints = *m_partitionedConstraints; + // zero out the Lagrange multiplier + for (size_t j = 0; j < constraints.size(); ++j) + { + constraints[j]->zeroOutLambda(); + } + + for (size_t j = 0; j < partitionedConstraints.size(); j++) + { + const PBDConstraintVector& constraintPartition = partitionedConstraints[j]; + ParallelUtils::parallelFor(constraintPartition.size(), + [&](const size_t idx) { constraintPartition[idx]->zeroOutLambda(); } + ); + } + unsigned int i = 0; while (i++ < m_iterations) { - for (size_t j = 0; j < constraints.size(); j++) + for (size_t j = 0; j < constraints.size(); ++j) { - constraints[j]->solvePositionConstraint(currPositions, invMasses); + constraints[j]->projectConstraint(invMasses, m_dt, m_solverType, currPositions); } for (size_t j = 0; j < partitionedConstraints.size(); j++) { - const PBDConstraintVector& constraintPartition = partitionedConstraints[j]; - const size_t numConstraintsInPartition = constraintPartition.size(); + const PBDConstraintVector& constraintPartition = partitionedConstraints[j]; ParallelUtils::parallelFor(constraintPartition.size(), [&](const size_t idx) { - constraintPartition[idx]->solvePositionConstraint(currPositions, invMasses); + constraintPartition[idx]->projectConstraint(invMasses, m_dt, m_solverType, currPositions); }); // Sequential /*for (size_t k = 0; k < constraintPartition.size(); k++) @@ -104,7 +117,7 @@ PbdCollisionSolver::solve() const PBDCollisionConstraintVector& constraints = *constraintList; for (size_t j = 0; j < constraints.size(); j++) { - constraints[j]->solvePositionConstraint(posA, posB, invMassA, invMassB); + constraints[j]->projectConstraint(invMassA, invMassB, posA, posB); } colDataIter++; } diff --git a/Source/Solvers/imstkPbdSolver.h b/Source/Solvers/imstkPbdSolver.h index 0622a90ec0911e88eed660e2da4c17ddce234826..f7012d6b5766bd9e6315db03f85812299793909b 100644 --- a/Source/Solvers/imstkPbdSolver.h +++ b/Source/Solvers/imstkPbdSolver.h @@ -24,6 +24,7 @@ #include "imstkPbdCollisionConstraint.h" #include "imstkPbdConstraint.h" #include "imstkSolverBase.h" +#include "imstkLogger.h" namespace imstk { @@ -87,11 +88,31 @@ public: /// void setInvMasses(std::shared_ptr<StdVectorOfReal> invMasses) { this->m_invMasses = invMasses; } + /// + /// \brief Set time step + /// + void setTimeStep(const double dt) { m_dt = dt; } + /// /// \brief Get Iterations. Returns current nonlinear iterations. /// size_t getIterations() const { return this->m_iterations; } + /// + /// \brief Set the PBD solver type + /// + void setSolverType(const PbdConstraint::SolverType& type) + { + if (type == PbdConstraint::SolverType::GCD) + { + LOG(WARNING) << "GCD is NOT implemented yet, use xPBD instead"; + m_solverType = PbdConstraint::SolverType::xPBD; + return; + } + + m_solverType = type; + } + /// /// \brief Solve the non linear system of equations G(x)=0 using Newton's method. /// @@ -99,12 +120,14 @@ public: private: size_t m_iterations = 20; ///> Number of NL Gauss-Seidel iterations for regular constraints + double m_dt; ///> time step std::shared_ptr<std::vector<PBDConstraintVector>> m_partitionedConstraints = nullptr; ///> Set of vector'd/partitioned pbd constraints std::shared_ptr<PBDConstraintVector> m_constraints = nullptr; ///> Vector of constraints std::shared_ptr<StdVectorOfVec3d> m_positions = nullptr; std::shared_ptr<StdVectorOfReal> m_invMasses = nullptr; + PbdConstraint::SolverType m_solverType = PbdConstraint::SolverType::xPBD; }; class PbdCollisionSolver : SolverBase