PhysicsBasedAnimationToolkit 0.0.10
Cross-platform C++20 library of algorithms and data structures commonly used in computer graphics research on physically-based simulation.
Loading...
Searching...
No Matches
MultibodyTetrahedralMeshSystem.h
1#ifndef PBAT_SIM_CONTACT_MULTIBODYTETRAHEDRALMESHSYSTEM_H
2#define PBAT_SIM_CONTACT_MULTIBODYTETRAHEDRALMESHSYSTEM_H
3
4#include "pbat/Aliases.h"
9#include "pbat/graph/BreadthFirstSearch.h"
10#include "pbat/graph/ConnectedComponents.h"
11#include "pbat/graph/Mesh.h"
12#include "pbat/io/Archive.h"
14
15#include <Eigen/Core>
16#include <ranges>
17
18namespace pbat::sim::contact {
24template <common::CIndex TIndex = Index, common::CArithmetic TScalar = Scalar>
25struct MultibodyTetrahedralMeshSystem
26{
27 using IndexType = TIndex;
28 using ScalarType = TScalar;
29
30 MultibodyTetrahedralMeshSystem() = default;
38 Eigen::Ref<Eigen::Matrix<TScalar, 3, Eigen::Dynamic>> X,
39 Eigen::Ref<Eigen::Matrix<IndexType, 4, Eigen::Dynamic>> T);
49 Eigen::Ref<Eigen::Matrix<TScalar, 3, Eigen::Dynamic>> X,
50 Eigen::Ref<Eigen::Matrix<IndexType, 4, Eigen::Dynamic>> T,
51 TScalar muS = 0.4,
52 TScalar muD = 0.2);
57 Eigen::Index NumBodies() const { return VP.size() - 1; }
63 auto ContactVerticesOf(IndexType o) const { return V.segment(VP[o], VP[o + 1] - VP[o]); }
69 auto ContactEdgesOf(IndexType o) const { return E.middleCols(EP[o], EP[o + 1] - EP[o]); }
75 auto ContactTrianglesOf(IndexType o) const { return F.middleCols(FP[o], FP[o + 1] - FP[o]); }
83 template <class TDerivedT>
84 auto TetrahedraOf(IndexType o, Eigen::DenseBase<TDerivedT> const& T) const
85 {
86 return T.middleCols(TP[o], TP[o + 1] - TP[o]);
87 }
88
96 template <class TDerivedX>
97 auto ContactVertexPositionsOf(IndexType o, Eigen::DenseBase<TDerivedX> const& X) const
98 {
99 return X(Eigen::placeholders::all, V.segment(VP[o], VP[o + 1] - VP[o]));
100 }
101
107 auto BodyOfContactVertex(IndexType v) const { return CC[V[v]]; }
113 auto BodyOfContactEdge(IndexType e) const { return CC[E(0, e)]; }
119 auto BodyOfContactTriangle(IndexType f) const { return CC[F(0, f)]; }
126 template <class TDerivedT>
127 auto BodyOfTetrahedron(IndexType t, Eigen::DenseBase<TDerivedT> const& T) const
128 {
129 return CC[T(0, t)];
130 }
131
136 Eigen::Index NumContactVertices() const { return V.size(); }
141 Eigen::Index NumContactEdges() const { return E.cols(); }
146 Eigen::Index NumContactTriangles() const { return F.cols(); }
151 Eigen::Index NumTetrahedra() const { return TP(TP.size() - 1); }
158 auto ContactVerticesRangeFor(IndexType o) const { return std::make_pair(VP[o], VP[o + 1]); }
165 auto ContactEdgesRangeFor(IndexType o) const { return std::make_pair(EP[o], EP[o + 1] - 1); }
173 {
174 return std::make_pair(FP[o], FP[o + 1] - 1);
175 }
176
183 void SetMaterial(IndexType o, TScalar muS, TScalar muD);
189 void SetMaterial(TScalar muS, TScalar muD);
196 auto TetrahedraRangeFor(IndexType o) const { return std::make_pair(TP[o], TP[o + 1] - 1); }
201 void Serialize(io::Archive& archive) const;
206 void Deserialize(io::Archive& archive);
207
208 Eigen::Vector<TIndex, Eigen::Dynamic>
210 Eigen::Matrix<TIndex, 2, Eigen::Dynamic>
212 Eigen::Matrix<TIndex, 3, Eigen::Dynamic>
214
215 Eigen::Vector<TIndex, Eigen::Dynamic>
217 Eigen::Vector<TIndex, Eigen::Dynamic>
219 Eigen::Vector<TIndex, Eigen::Dynamic>
221 Eigen::Vector<TIndex, Eigen::Dynamic> TP;
224
225 Eigen::Vector<TIndex, Eigen::Dynamic> CC;
226
227 Eigen::Matrix<TScalar, 2, Eigen::Dynamic>
231};
232
233template <common::CIndex TIndex, common::CArithmetic TScalar>
234inline MultibodyTetrahedralMeshSystem<TIndex, TScalar>::MultibodyTetrahedralMeshSystem(
235 Eigen::Ref<Eigen::Matrix<TScalar, 3, Eigen::Dynamic>> X,
236 Eigen::Ref<Eigen::Matrix<IndexType, 4, Eigen::Dynamic>> T)
237 : MultibodyTetrahedralMeshSystem<TIndex, TScalar>()
238{
239 Construct(std::move(X), std::move(T));
240}
241
242template <common::CIndex TIndex, common::CArithmetic TScalar>
244 Eigen::Ref<Eigen::Matrix<TScalar, 3, Eigen::Dynamic>> X,
245 Eigen::Ref<Eigen::Matrix<IndexType, 4, Eigen::Dynamic>> T,
246 TScalar muS,
247 TScalar muD)
248{
249 PBAT_PROFILE_NAMED_SCOPE("pbat.sim.contact.MultibodyTetrahedralMeshSystem.Construct");
250 IndexType const nNodes = static_cast<IndexType>(X.cols());
251 IndexType const nElements = static_cast<IndexType>(T.cols());
252 // 1. Compute the mesh's dual graph over tets
253 Eigen::SparseMatrix<IndexType, Eigen::ColMajor, IndexType> const EG =
254 graph::MeshDualGraph(T, nNodes, graph::EMeshDualGraphOptions::All);
255 // 2. Compute the connected components of the mesh
257 Eigen::Vector<IndexType, Eigen::Dynamic> ECC(nElements);
258 ECC.setConstant(IndexType(-1));
260 Eigen::Map<Eigen::Vector<IndexType, Eigen::Dynamic> const>(
261 EG.outerIndexPtr(),
262 EG.outerSize() + 1),
263 Eigen::Map<Eigen::Vector<IndexType, Eigen::Dynamic> const>(
264 EG.innerIndexPtr(),
265 EG.nonZeros()),
266 ECC,
267 bfs);
268 // 3. Transfer the element connected components to the mesh vertex connected component map
269 CC.setConstant(nNodes, IndexType(-1));
270 auto verticesToElements =
271 Eigen::Vector<IndexType, Eigen::Dynamic>::LinSpaced(nElements, 0, nElements - 1)
272 .template replicate<1, 4>()
273 .transpose()
274 .reshaped(); // `4 x |# elements|` matrix `[[0,0,0,0], [1,1,1,1], ...,
275 // [nElements-1,nElements-1,nElements-1,nElements-1]]`
276 CC(T.reshaped()) = ECC(verticesToElements);
277 // 4. Sort the tets by connected component
278 Eigen::Vector<IndexType, Eigen::Dynamic> Eordering =
280 nElements,
281 [&](IndexType ei, IndexType ej) {
282 return ECC[ei] < ECC[ej];
283 });
284 for (auto r = 0; r < T.rows(); ++r)
285 common::Permute(T.row(r).begin(), T.row(r).end(), Eordering.begin());
286 common::Permute(ECC.begin(), ECC.end(), Eordering.begin());
287 // 5. Sort vertices by connected component
288 Eigen::Vector<IndexType, Eigen::Dynamic> Xordering =
289 common::ArgSort<IndexType>(nNodes, [&](IndexType i, IndexType j) { return CC[i] < CC[j]; });
290 for (auto d = 0; d < X.rows(); ++d)
291 common::Permute(X.row(d).begin(), X.row(d).end(), Xordering.begin());
292 common::Permute(CC.begin(), CC.end(), Xordering.begin());
293 // 6. Re-index tet vertices to match the sorted order
294 // If Xordering[i] = j, then all nodes i in T must become j
295 Eigen::Vector<IndexType, Eigen::Dynamic> XorderingInverse(nNodes);
296 XorderingInverse(Xordering) =
297 Eigen::Vector<IndexType, Eigen::Dynamic>::LinSpaced(nNodes, 0, nNodes - 1);
298 T.reshaped() = XorderingInverse(T.reshaped());
299 // 7. Compute boundary mesh, and note that V and F will already be sorted by connected
300 // component, because we have re-indexed T and X
301 std::tie(V, F) = geometry::SimplexMeshBoundary<IndexType>(T, nNodes);
302 // 8. Compute edges from triangles (edges are also sorted by connected component, since
303 // triangles are)
304 auto const nEdges =
305 F.size() / 2; // Boundary (triangle) mesh of tetrahedral mesh must be manifold+watertight
306 E.resize(2, nEdges);
307 auto const nTriangles = F.cols();
308 for (auto f = 0, e = 0; f < nTriangles; ++f)
309 {
310 for (auto k = 0; k < 3; ++k)
311 {
312 auto i = F(k, f);
313 auto j = F((k + 1) % 3, f);
314 // De-duplicate since every edge is counted twice in the loop
315 if (i < j)
316 {
317 E(0, e) = i;
318 E(1, e) = j;
319 ++e;
320 }
321 }
322 }
323 // 9. Compute the prefix sums for vertices, edges, triangles, and tetrahedra
324 VP.setZero(nComponents + 1);
325 EP.setZero(nComponents + 1);
326 FP.setZero(nComponents + 1);
327 TP.setZero(nComponents + 1);
328 IndexType const nContactVertices = static_cast<IndexType>(V.size());
329 IndexType const nContactEdges = static_cast<IndexType>(E.cols());
330 IndexType const nContactFaces = static_cast<IndexType>(F.cols());
331 for (IndexType o = 0; o < nComponents; ++o)
332 {
333 // Count vertices of body o
334 auto& vosum = VP(o + 1);
335 vosum = VP(o);
336 while (vosum < nContactVertices and CC(V(vosum)) == o)
337 ++vosum;
338 // Count edges of body o
339 auto& eosum = EP(o + 1);
340 eosum = EP(o);
341 while (eosum < nContactEdges and CC(E(0, eosum)) == o)
342 ++eosum;
343 // Count faces of body o
344 auto& fosum = FP(o + 1);
345 fosum = FP(o);
346 while (fosum < nContactFaces and CC(F(0, fosum)) == o)
347 ++fosum;
348 // Count tetrahedra of body o
349 auto& tosum = TP(o + 1);
350 tosum = TP(o);
351 while (tosum < nElements and CC(T(0, tosum)) == o)
352 ++tosum;
353 }
354 // 10. Initialize friction coefficients
355 muF.resize(2, nContactFaces);
356 SetMaterial(muS, muD);
357}
358
359template <common::CIndex TIndex, common::CArithmetic TScalar>
360inline void
362{
363 muF(Eigen::placeholders::all, Eigen::seqN(FP[o], FP[o + 1] - FP[o])).colwise() =
364 Eigen::Vector2<TScalar>(muS, muD);
365}
366
367template <common::CIndex TIndex, common::CArithmetic TScalar>
369{
370 this->muF.colwise() = Eigen::Vector2<TScalar>(muS, muD);
371}
372
373template <common::CIndex TIndex, common::CArithmetic TScalar>
375{
376 io::Archive group = archive["pbat.sim.contact.MultibodyTetrahedralMeshSystem"];
377 group.WriteData("V", V);
378 group.WriteData("E", E);
379 group.WriteData("F", F);
380 group.WriteData("VP", VP);
381 group.WriteData("EP", EP);
382 group.WriteData("FP", FP);
383 group.WriteData("TP", TP);
384 group.WriteData("CC", CC);
385 group.WriteData("muF", muF);
386}
387
388template <common::CIndex TIndex, common::CArithmetic TScalar>
390{
391 io::Archive group = archive["pbat.sim.contact.MultibodyTetrahedralMeshSystem"];
392 V = group.ReadData<decltype(V)>("V");
393 E = group.ReadData<decltype(E)>("E");
394 F = group.ReadData<decltype(F)>("F");
395 VP = group.ReadData<decltype(VP)>("VP");
396 EP = group.ReadData<decltype(EP)>("EP");
397 FP = group.ReadData<decltype(FP)>("FP");
398 TP = group.ReadData<decltype(TP)>("TP");
399 CC = group.ReadData<decltype(CC)>("CC");
400 muF = group.ReadData<decltype(muF)>("muF");
401}
402} // namespace pbat::sim::contact
403
404#endif // PBAT_SIM_CONTACT_MULTIBODYTETRAHEDRALMESHSYSTEM_H
(De)serializer
Non-intrusive sorting.
This file contains functions to compute the boundary of a mesh.
Permutation of values in-place.
Archive class for reading and writing data to HDF5 files.
Definition Archive.h:29
T ReadData(std::string const &path) const
Read data from the archive.
Definition Archive.h:179
void WriteData(std::string const &path, T const &data)
Write data to the archive.
Definition Archive.h:137
Concepts for common types.
Mesh graph utilities.
void Permute(TValuesBegin vb, TValuesEnd ve, TPermutationBegin pb)
Permute the values in-place according to the permutation.
Definition Permute.h:39
auto ArgSort(TIndex n, FLess less) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Computes the indices that would sort an array.
Definition ArgSort.h:32
auto SimplexMeshBoundary(Eigen::Ref< Eigen::Matrix< TIndex, Eigen::Dynamic, Eigen::Dynamic > const > const &C, TIndex n) -> std::tuple< Eigen::Vector< TIndex, Eigen::Dynamic >, Eigen::Matrix< TIndex, Eigen::Dynamic, Eigen::Dynamic > >
Obtains the boundary mesh of a simplex mesh.
Definition MeshBoundary.h:40
auto MeshDualGraph(Eigen::DenseBase< TDerivedE > const &E, TIndex nNodes=TIndex(-1), EMeshDualGraphOptions opts=EMeshDualGraphOptions::All) -> Eigen::SparseMatrix< TIndex, Eigen::ColMajor, TIndex >
Construct dual graph of input mesh, i.e. the graph of adjacent elements.
Definition Mesh.h:147
TIndex ConnectedComponents(Eigen::DenseBase< TDerivedP > const &ptr, Eigen::DenseBase< TDerivedAdj > const &adj, Eigen::Ref< Eigen::Vector< TIndex, Eigen::Dynamic > > components, DepthFirstSearch< TIndex > &dfs)
Compute connected components of a graph using depth-first search.
Definition ConnectedComponents.h:27
Namespace for contact detection algorithms.
Definition Constraints.cpp:3
Profiling utilities for the Physics-Based Animation Toolkit (PBAT)
Definition BreadthFirstSearch.h:14
void Construct(Eigen::Ref< Eigen::Matrix< TScalar, 3, Eigen::Dynamic > > X, Eigen::Ref< Eigen::Matrix< IndexType, 4, Eigen::Dynamic > > T, TScalar muS=0.4, TScalar muD=0.2)
Construct a new Multibody Tetrahedral Mesh System object.
Definition MultibodyTetrahedralMeshSystem.h:243
Eigen::Index NumBodies() const
Get the number of bodies in the multibody system.
Definition MultibodyTetrahedralMeshSystem.h:57
auto ContactTrianglesOf(IndexType o) const
Get triangles of body o
Definition MultibodyTetrahedralMeshSystem.h:75
Eigen::Index NumContactTriangles() const
Get the number of contact triangles.
Definition MultibodyTetrahedralMeshSystem.h:146
auto ContactVerticesRangeFor(IndexType o) const
Get the range of contact vertices for body o
Definition MultibodyTetrahedralMeshSystem.h:158
Eigen::Vector< TIndex, Eigen::Dynamic > FP
Definition MultibodyTetrahedralMeshSystem.h:220
auto TetrahedraOf(IndexType o, Eigen::DenseBase< TDerivedT > const &T) const
Get tetrahedra of body o
Definition MultibodyTetrahedralMeshSystem.h:84
TIndex IndexType
Definition MultibodyTetrahedralMeshSystem.h:27
Eigen::Index NumContactEdges() const
Get the number of contact edges.
Definition MultibodyTetrahedralMeshSystem.h:141
Eigen::Vector< TIndex, Eigen::Dynamic > CC
Definition MultibodyTetrahedralMeshSystem.h:225
auto BodyOfContactVertex(IndexType v) const
Get the body associated with vertex v
Definition MultibodyTetrahedralMeshSystem.h:107
auto ContactVertexPositionsOf(IndexType o, Eigen::DenseBase< TDerivedX > const &X) const
Get vertex positions of body o
Definition MultibodyTetrahedralMeshSystem.h:97
auto BodyOfContactTriangle(IndexType f) const
Get the body associated with triangle f
Definition MultibodyTetrahedralMeshSystem.h:119
auto ContactEdgesOf(IndexType o) const
Get edges of body o
Definition MultibodyTetrahedralMeshSystem.h:69
Eigen::Vector< TIndex, Eigen::Dynamic > EP
Definition MultibodyTetrahedralMeshSystem.h:218
auto TetrahedraRangeFor(IndexType o) const
Get the range of tetrahedra for body o
Definition MultibodyTetrahedralMeshSystem.h:196
Eigen::Index NumContactVertices() const
Get the number of contact vertices.
Definition MultibodyTetrahedralMeshSystem.h:136
auto ContactTrianglesRangeFor(IndexType o) const
Get the range of contact triangles for body o
Definition MultibodyTetrahedralMeshSystem.h:172
Eigen::Index NumTetrahedra() const
Get the number of tetrahedra.
Definition MultibodyTetrahedralMeshSystem.h:151
void SetMaterial(TScalar muS, TScalar muD)
Set the friction coefficients for all bodies.
Definition MultibodyTetrahedralMeshSystem.h:368
Eigen::Matrix< TIndex, 2, Eigen::Dynamic > E
Definition MultibodyTetrahedralMeshSystem.h:211
void Serialize(io::Archive &archive) const
Serialize the multibody tetrahedral mesh system to an HDF5 archive.
Definition MultibodyTetrahedralMeshSystem.h:374
auto BodyOfTetrahedron(IndexType t, Eigen::DenseBase< TDerivedT > const &T) const
Get the body associated with tetrahedron t
Definition MultibodyTetrahedralMeshSystem.h:127
void SetMaterial(IndexType o, TScalar muS, TScalar muD)
Set the friction coefficients for body o
Definition MultibodyTetrahedralMeshSystem.h:361
Scalar ScalarType
Definition MultibodyTetrahedralMeshSystem.h:28
void Deserialize(io::Archive &archive)
Deserialize the multibody tetrahedral mesh system from an HDF5 archive.
Definition MultibodyTetrahedralMeshSystem.h:389
Eigen::Matrix< TIndex, 3, Eigen::Dynamic > F
Definition MultibodyTetrahedralMeshSystem.h:213
Eigen::Vector< TIndex, Eigen::Dynamic > VP
Definition MultibodyTetrahedralMeshSystem.h:216
Eigen::Vector< TIndex, Eigen::Dynamic > V
Definition MultibodyTetrahedralMeshSystem.h:209
MultibodyTetrahedralMeshSystem(Eigen::Ref< Eigen::Matrix< TScalar, 3, Eigen::Dynamic > > X, Eigen::Ref< Eigen::Matrix< IndexType, 4, Eigen::Dynamic > > T)
Construct a new Multibody Tetrahedral Mesh System object.
Definition MultibodyTetrahedralMeshSystem.h:234
Eigen::Vector< TIndex, Eigen::Dynamic > TP
Definition MultibodyTetrahedralMeshSystem.h:221
Eigen::Matrix< Scalar, 2, Eigen::Dynamic > muF
Definition MultibodyTetrahedralMeshSystem.h:228
auto BodyOfContactEdge(IndexType e) const
Get the body associated with edge e
Definition MultibodyTetrahedralMeshSystem.h:113
auto ContactVerticesOf(IndexType o) const
Get vertices of body o
Definition MultibodyTetrahedralMeshSystem.h:63
auto ContactEdgesRangeFor(IndexType o) const
Get the range of contact edges for body o
Definition MultibodyTetrahedralMeshSystem.h:165