11#ifndef PBAT_FEM_MESH_H
12#define PBAT_FEM_MESH_H
42 common::CFloatingPoint TScalar =
Scalar,
43 common::CIndex TIndex =
Index>
49 static int constexpr kDims = Dims;
50 static int constexpr kOrder = ElementType::kOrder;
53 Eigen::Matrix<ScalarType, kDims, Eigen::Dynamic>;
55 Eigen::Matrix<IndexType, kNodesPerElement, Eigen::Dynamic>;
67 template <
class TDerivedV,
class TDerivedC>
68 Mesh(Eigen::MatrixBase<TDerivedV>
const& V, Eigen::DenseBase<TDerivedC>
const& C);
78 template <
class TDerivedV,
class TDerivedC>
79 void Construct(Eigen::MatrixBase<TDerivedV>
const& V, Eigen::DenseBase<TDerivedC>
const& C);
85 template <
int QuadratureOrder>
97 int kPoints = TElement::template QuadratureType<QuadratureOrder,
ScalarType>::kPoints>
117template <CElement TElement, common::CIndex TIndex>
121 using SelfType = NodalKey<TElement, TIndex>;
122 static int constexpr kVertices = TElement::AffineBaseType::kNodes;
125 Eigen::Vector<TIndex, kVertices>
const& cellVertices,
126 Eigen::Vector<TIndex, kVertices>
const& sortOrder,
127 Eigen::Vector<math::Rational, kVertices>
const& N)
128 : mCellVertices(cellVertices), mSortOrder(sortOrder), mN(N), mSize()
131 auto it = std::remove_if(mSortOrder.begin(), mSortOrder.end(), [
this](TIndex o) {
135 mSize =
static_cast<decltype(mSize)
>(std::distance(mSortOrder.begin(), it));
138 bool operator==(SelfType
const& rhs)
const
141 if (mSize != rhs.mSize)
143 for (
auto i = 0u; i < mSize; ++i)
146 TIndex
const lhsVertex = mCellVertices[mSortOrder[i]];
147 TIndex
const rhsVertex = rhs.mCellVertices[rhs.mSortOrder[i]];
148 if (lhsVertex != rhsVertex)
160 bool operator<(SelfType
const& rhs)
const
163 if (mSize != rhs.mSize)
164 return mSize < rhs.mSize;
166 for (
auto i = 0; i < mSize; ++i)
168 TIndex
const lhsVertex = mCellVertices[mSortOrder[i]];
169 TIndex
const rhsVertex = rhs.mCellVertices[rhs.mSortOrder[i]];
170 if (lhsVertex != rhsVertex)
171 return lhsVertex < rhsVertex;
174 for (
auto i = 0; i < mSize; ++i)
186 Eigen::Vector<TIndex, kVertices> mCellVertices;
187 Eigen::Vector<TIndex, kVertices> mSortOrder;
188 Eigen::Vector<math::Rational, kVertices> mN;
194template <CElement TElement,
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
195template <
class TDerivedV,
class TDerivedC>
196inline Mesh<TElement, Dims, TScalar, TIndex>::Mesh(
197 Eigen::MatrixBase<TDerivedV>
const& V,
198 Eigen::DenseBase<TDerivedC>
const& C)
203template <CElement TElement,
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
204template <
class TDerivedV,
class TDerivedC>
206 Eigen::MatrixBase<TDerivedV>
const& V,
207 Eigen::DenseBase<TDerivedC>
const& C)
209 PBAT_PROFILE_NAMED_SCOPE(
"pbat.fem.Mesh.Construct");
211 kDims >= ElementType::kDims,
212 "Element TElement does not exist in Dims dimensions");
214 std::is_same_v<TScalar, typename TDerivedV::Scalar>,
215 "Vertex positions matrix V must have the same scalar type as TScalar");
217 std::is_same_v<TIndex, typename TDerivedC::Scalar>,
218 "Cell vertex indices matrix C must have the same index type as TIndex");
221 if constexpr (
kOrder == 1)
229 using AffineElementType =
typename ElementType::AffineBaseType;
230 auto constexpr kVerticesPerCell = AffineElementType::kNodes;
231 assert(C.rows() == kVerticesPerCell);
232 assert(V.rows() ==
kDims);
234 using NodalKey = detail::NodalKey<TElement, TIndex>;
235 using NodeMap = std::map<NodalKey, TIndex>;
236 using DVector = Eigen::Vector<TScalar, kDims>;
238 auto const numberOfCells = C.cols();
239 auto const numberOfVertices = V.cols();
242 std::vector<DVector> nodes{};
243 nodes.reserve(
static_cast<std::size_t
>(numberOfVertices));
247 E.resize(ElementType::kNodes, numberOfCells);
248 for (
auto c = 0; c < numberOfCells; ++c)
250 Eigen::Vector<TIndex, kVerticesPerCell> cellVertices = C.col(c);
251 Eigen::Matrix<TScalar, kDims, kVerticesPerCell>
const Xc =
252 V(Eigen::placeholders::all, cellVertices);
255 decltype(cellVertices) sortOrder{};
256 std::iota(sortOrder.begin(), sortOrder.end(), TIndex(0));
257 std::ranges::sort(sortOrder, [&](TIndex i, TIndex j) {
258 return cellVertices[i] < cellVertices[j];
261 auto const nodalCoordinates =
common::ToEigen(ElementType::Coordinates)
262 .reshaped(ElementType::kDims, ElementType::kNodes)
263 .template cast<math::Rational>() /
265 for (
auto i = 0; i < nodalCoordinates.cols(); ++i)
269 auto const Xi = nodalCoordinates.col(i);
270 auto const N = AffineElementType::N(Xi);
271 NodalKey
const key{cellVertices, sortOrder, N};
272 auto it = nodeMap.find(key);
273 bool const bNodeAlreadyCreated = it != nodeMap.end();
274 if (!bNodeAlreadyCreated)
276 auto const nodeIdx =
static_cast<TIndex
>(nodes.size());
277 Eigen::Vector<TScalar, kDims>
const xi = Xc * N.template cast<TScalar>();
280 std::tie(it, bInserted) = nodeMap.insert({key, nodeIdx});
283 TIndex
const node = it->second;
292template <CElement TElement,
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
293template <
int QuadratureOrder>
294inline Eigen::Matrix<TScalar, Eigen::Dynamic, Eigen::Dynamic>
297 using QuadraturePointPositions = Eigen::Matrix<TScalar, Eigen::Dynamic, Eigen::Dynamic>;
298 using AffineElementType =
typename ElementType::AffineBaseType;
299 using QuadratureRuleType =
300 typename ElementType::template QuadratureType<QuadratureOrder, TScalar>;
301 auto constexpr kQuadPts = QuadratureRuleType::kPoints;
302 auto const numberOfElements =
E.cols();
304 .reshaped(QuadratureRuleType::kDims + 1, kQuadPts);
305 QuadraturePointPositions Xg(Dims, numberOfElements * kQuadPts);
306 for (
auto e = 0; e < numberOfElements; ++e)
308 auto const nodes =
E.col(e);
309 auto const vertices = nodes(ElementType::Vertices);
310 auto constexpr kRowsJ = Dims;
311 auto constexpr kColsJ = AffineElementType::kNodes;
312 Eigen::Matrix<TScalar, kRowsJ, kColsJ>
const Ve =
X(Eigen::placeholders::all, vertices);
313 for (
auto g = 0; g < kQuadPts; ++g)
315 Xg.col(e * kQuadPts + g) = Ve * XgRef.col(g);
321template <CElement TElement,
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
322template <
int QuadratureOrder,
int kPo
ints>
323inline Eigen::Vector<TScalar, kPoints>
326 using QuadratureRuleType =
327 typename ElementType::template QuadratureType<QuadratureOrder, TScalar>;
328 auto constexpr kQuadPts = QuadratureRuleType::kPoints;
331 "kPoints must match the number of quadrature points for the given QuadratureOrder");
332 Eigen::Vector<TScalar, kQuadPts>
const wg =
common::ToEigen(QuadratureRuleType::weights);
336template <CElement TElement,
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
339 io::Archive meshArchive = archive[
"pbat.fem.Mesh"];
346template <CElement TElement,
int Dims, common::CFloatingPo
int TScalar, common::CIndex TIndex>
349 io::Archive const meshArchive = archive[
"pbat.fem.Mesh"];
350 int const kDimsRead = meshArchive.
ReadMetaData<
int>(
"kDims");
351 int const kOrderRead = meshArchive.
ReadMetaData<
int>(
"kOrder");
352 if (kDimsRead !=
kDims)
354 throw std::runtime_error(
355 "pbat::fem::Mesh::Deserialize(): kDims in archive does not match template parameter "
360 throw std::runtime_error(
361 "pbat::fem::Mesh::Deserialize(): kOrder in archive does not match template parameter "
366 if (
E.rows() != ElementType::kNodes)
368 throw std::runtime_error(
369 "pbat::fem::Mesh::Deserialize(): Number of rows in E does not match Element::kNodes");
Functions to compute jacobians, their determinants, domain quadrature weights and mapping domain to r...
Fixed size rational number representation using std::int64_t as numerator and denominator.
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 WriteMetaData(std::string const &key, T const &value)
Write metadata to the archive.
Definition Archive.h:158
void WriteData(std::string const &path, T const &data)
Write data to the archive.
Definition Archive.h:137
T ReadMetaData(std::string const &key) const
Read metadata from the archive.
Definition Archive.h:195
Concepts for common types.
Eigen adaptors for ranges.
Reference finite element.
Definition Concepts.h:63
auto ToEigen(R &&r) -> Eigen::Map< Eigen::Vector< std::ranges::range_value_t< R >, Eigen::Dynamic > const >
Map a range of scalars to an eigen vector of such scalars.
Definition Eigen.h:28
Finite Element Method (FEM)
Definition Concepts.h:19
Namespace for I/O.
Definition Archive.cpp:7
Eigen::Vector< Scalar, N > Vector
Fixed-size vector type.
Definition Aliases.h:24
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
double Scalar
Scalar type.
Definition Aliases.h:18
Eigen::Matrix< Scalar, Rows, Cols > Matrix
Fixed-size matrix type.
Definition Aliases.h:31
Profiling utilities for the Physics-Based Animation Toolkit (PBAT)
void Construct(Eigen::MatrixBase< TDerivedV > const &V, Eigen::DenseBase< TDerivedC > const &C)
Constructs a finite element mesh given some input geometric mesh.
Definition Mesh.h:205
static int constexpr kOrder
Definition Mesh.h:50
Eigen::Matrix< ScalarType, kDims, Eigen::Dynamic > NodeMatrix
Node positions matrix type.
Definition Mesh.h:52
auto QuadratureWeights() const -> Eigen::Vector< ScalarType, kPoints >
void Deserialize(io::Archive const &archive)
TScalar ScalarType
Floating point type.
Definition Mesh.h:47
void Serialize(io::Archive &archive) const
static int constexpr kNodesPerElement
Definition Mesh.h:51
NodeMatrix X
Definition Mesh.h:111
TIndex IndexType
Index type.
Definition Mesh.h:48
auto QuadraturePoints() const -> Eigen::Matrix< ScalarType, Eigen::Dynamic, Eigen::Dynamic >
Compute quadrature points in domain space on this mesh.
Eigen::Matrix< IndexType, kNodesPerElement, Eigen::Dynamic > ElementMatrix
Element indices matrix type.
Definition Mesh.h:54
ElementMatrix E
Definition Mesh.h:112
Mesh(Eigen::MatrixBase< TDerivedV > const &V, Eigen::DenseBase< TDerivedC > const &C)
Constructs a finite element mesh given some input geometric mesh.
Definition Mesh.h:196
TElement ElementType
Underlying finite element type.
Definition Mesh.h:46
static int constexpr kDims
Definition Mesh.h:49
Fixed size rational number using std::int64_t for numerator and denominator.
Definition Rational.h:29